I am new to Scala. I wonder whether it is possible to define some precedence with method calls. For example, if I have the chain of method calls:
someObject method1 param1 method2 param2 method3 param3
can this be equivalent to the following:
someObject.method1(param1).method2(param2.method3(param3))
or
someObject method1 param1 method2 (param2 method3 param3)
So I want method3 to take precedence over method2...
The reason I want to do this is that I want to develop a DSL, so I want to avoid using dots and parentheses as much as possible. If you guys find another solution for me, feel free to let me know.
You'll have to use methods with special operator characters to influence precedence as implied by Tomasz. This is partly why lots of Scala DSL make heavy use of operators. Also why some DSL are hard to read if you don't work with them daily.
Given method with using only letters, underscore and digits - you won't be able to influence things, here is what I put together for myself after reading the spec:
Any method which takes a single parameter can be used as an infix operator: a.m(b) can be written a m b.
Any method which does not require a parameter can be used as a postfix operator: a.m can be written a m.
Postfix operators have lower precedence than infix operators, so foo bar baz means foo.bar(baz) while foo bar baz bam means (foo.bar(baz)).bam and foo bar baz bam bim means (foo.bar(baz)).bam(bim).
So without knowing at all what your method signatures are, the following code (because it's all alphanumeric):
someObject method1 param1 method2 param2 method3 param3
will be parsed as:
someObject.method1(param1).method2(param2).method3(param3)
If you rename method3 to |*| or +:+ or whatever operator makes sense, you can achieve what you want:
someObject method1 param1 method2 param2 |*| param3
// same as
someObject.method1(param1).method2(param2.|*|(param3))
For example to see the difference:
implicit def pimp(s:String) = new {
def |*|(t:String) = t + s
def switch(t:String) = t + s
}
scala> "someObject" concat "param1" concat "param2" |*| "param3"
res2: java.lang.String = someObjectparam1param3param2
scala> "someObject" concat "param1" concat "param2" switch "param3"
res3: java.lang.String = param3someObjectparam1param2
This behavior is defined in chapter 6.12.3 Infix Operations of The Scala Language Specification.
In short: methods are invoked from left to right by default with some exceptions. These exceptions were only introduced to support mathematical operators precedence. So when you have two functions named * and +:
a + b * c
This will always be translated to:
a.+(b.*(c))
Here the first name of the function controls the precedence. However for ordinary functions you cannot control the order. Think about it - this would actually cause havoc and terribly unmaintainable code.
See also (not quite duplicate?): Operator precedence in Scala.
Related
I am a scala newbie.
This is my code. The results of two types of same method use are different,
can anyone explain to me why???
The thing is that in Scala, all functions ( or "operators") which have names ending with a colon ':' are deemed as right associative when used with infix notation.
So... for your function,
def ::(t: TG) = ???
When, you are writing
val lxx3 = lxx1 :: lxx2
The function :: associates to the right (ie. with lxx2). So it is actually equivalent to
val lxx3 = lxx2.::(lxx1)
instead of this,
val lxx3 = lxx1.::(lxx2)
I've got a number of nested objects, all wrapped in a Scala Option type. Elsewhere in my project I'm having to call an attribute that is embedded some 5 levels deep (some of which are Lists), each time making a call to .get. This way I end up with something that looks like the following:
objectA.get.attrB.get.attrC.get(0).attrD.get
Other than the series of .get calls (which I'm not sure is ideal), I'm not implementing much error handling this way and should any of the attributes be empty then the whole thing falls apart. Given the nested calls, if I were to limit this to a one-liner as above, I would also only be able to use .getOrElse once at the end.
Are there any suggested ways of working with Option types in Scala?
In this case, the most readable solution out of the box (that is, without writing helper methods) would argueably be to chain calls to Option.flatMap:
objectA flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
By using flatMap, if any of the option in the chain is None, you'll end up with None at the end (no exception unlike with get which will blow when called on None).
By example:
case class C(attrD: Option[String])
case class B(attrC: List[C])
case class A(attrB: Option[B])
val objectA = Some(A(Some(B(List(C(Some("foo")), C(Some("bar")))))))
// returns Some(foo)
objectA flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
val objectA2 = Some(A(Some(B(List()))))
// returns None
objectA2 flatMap (_.attrB) flatMap (_.attrC.headOption) flatMap (_.attrD)
You could also use for comprehensions instead of flatMap (for comprehension being desugared to chains of flatMap/map), but in this case it will actually be less readable (the opposite is usually true) because on each step you'll have to introduce a binding and then reference that on the next step:
for ( a <- objectA; b <- a.attrB; c <- b.attrC.headOption; d <- c.attrD ) yield d
Another solution, if you're willing to use ScalaZ, is to use >>= in place of flatMap, which makes it somewhat shorter:
val objectA = Option(A(Some(B(List(C(Some("foo")), C(Some("bar")))))))
// returns Some(foo)
objectA >>= (_.attrB) >>= (_.attrC.headOption) >>= (_.attrD)
This is really exactly the same as using flatMap, only shorter.
I believe you wanted this,
val deepNestedVal = objectA.get.attrB.get.attrC.get.attrD.get
I think the more preferred way would be to use for-comprehension,
val deepNestedVal = for {
val1 <- objectA
val2 <- val1.attrB
val3 <- val2.attrC
val4 <- val3.attrD
} yield val4
Other way is to use flatMap as shown in the answer by #Régis Jean-Gilles
In order to take multiple variables as arguments for data types in Scala we can write something as :
def test(args: String*)
How can we take multiple functions as arguments in the same spirit? (The Syntax?) I could not find anything after much googling.
Functions in Scala are values with types like any other values, and A => B (or, equivalently, Function1[A, B]) is the type of a function from A to B. So if for example you want to take a variable number of functions from strings to strings, you could write the following:
def test(funcs: (String => String)*) = ???
You could actually skip the internal parentheses and write funcs: String => String*, but I personally find the precedence there a bit unclear.
When programming in Scala, I do more and more functional stuff. However, when using infix notation it is hard to tell when you need parenthesis and when you don't.
For example the following piece of code:
def caesar(k:Int)(c:Char) = c match {
case c if c isLower => ('a'+((c-'a'+k)%26)).toChar
case c if c isUpper => ('A'+((c-'A'+k)%26)).toChar
case _ => c
}
def encrypt(file:String,k:Int) = (fromFile(file) mkString) map caesar(k)_
The (fromFile(file) mkString) needs parenthesis in order to compile. When removed I get the following error:
Caesar.scala:24: error: not found: value map
def encrypt(file:String,k:Int) = fromFile(file) mkString map caesar(k)_
^
one error found
mkString obviously returns a string on which (by implicit conversion AFAIK)I can use the map function.
Why does this particular case needs parentheses? Is there a general guideline on when and why you need it?
This is what I put together for myself after reading the spec:
Any method which takes a single parameter can be used as an infix operator: a.m(b) can be written a m b.
Any method which does not require a parameter can be used as a postfix operator: a.m can be written a m.
For instance a.##(b) can be written a ## b and a.! can be written a!
Postfix operators have lower precedence than infix operators, so foo bar baz means foo.bar(baz) while foo bar baz bam means (foo.bar(baz)).bam and foo bar baz bam bim means (foo.bar(baz)).bam(bim).
Also given a parameterless method m of object a, a.m.m is valid but a m m is not as it would parse as exp1 op exp2.
Because there is a version of mkString that takes a single parameter it will be seen as an infix opertor in fromFile(file) mkString map caesar(k)_. There is also a version of mkString that takes no parameter which can be used a as postfix operator:
scala> List(1,2) mkString
res1: String = 12
scala> List(1,2) mkString "a"
res2: String = 1a2
Sometime by adding dot in the right location, you can get the precedence you need, e.g. fromFile(file).mkString map { }
And all that precedence thing happens before typing and other phases, so even though list mkString map function makes no sense as list.mkString(map).function, this is how it will be parsed.
The Scala reference mentions (6.12.3: Prefix, Infix, and Postfix Operations)
In a sequence of consecutive type infix operations t0 op1 t1 op2 . . .opn tn, all operators op1, . . . , opn must have the same associativity.
If they are all left-associative, the sequence is interpreted as (. . . (t0 op1 t1) op2 . . .) opn tn.
In your case, 'map' isn't a term for the operator 'mkstring', so you need grouping (with the parenthesis around 'fromFile(file) mkString')
Actually, Matt R comments:
It's not really an associativity issue, more that "Postfix operators always have lower precedence than infix operators. E.g. e1 op1 e2 op2 is always equivalent to (e1 op1 e2) op2". (Also from 6.12.3)
huynhjl's answer (upvoted) gives more details, and Mark Bush's answer (also upvoted) point to "A Tour of Scala: Operators" to illustrate that "Any method which takes a single parameter can be used as an infix operator".
Here's a simple rule: never used postfix operators. If you do, put the whole expression ending with the postfix operator inside parenthesis.
In fact, starting with Scala 2.10.0, doing that will generate a warning by default.
For good measure, you might want to move the postfix operator out, and use dot notation for it. For example:
(fromFile(file)).mkString map caesar(k)_
Or, even more simply,
fromFile(file).mkString map caesar(k)_
On the other hand, pay attention to the methods where you can supply an empty parenthesis to turn them into infix:
fromFile(file) mkString () map caesar(k)_
The spec doesn't make it clear, but my experience and experimentation has shown that the Scala compiler will always try to treat method calls using infix notation as infix operators. Even though your use of mkString is postfix, the compiler tries to interpret it as infix and so is trying to interpret "map" as its argument. All uses of postfix operators must either be immediately followed by an expression terminator or be used with "dot" notation for the compiler to see it as such.
You can get a hint of this (although it's not spelled out) in A Tour of Scala: Operators.
I start reading Lift framework source code, I find that there're so many methods are defined using a name like methodName_? , is there a convention that _? has some special meaning?
def empty_? : Boolean = {}
You're unlikely to see the construct outside of the lift framework; I suspect that it's mostly Ruby-envy.
Almost any other Scala project will shy away from this syntax. Not because of the trailing question mark, but because it's yet another way to introduce underscores into your code - and the symbol is already far too heavily overloaded.
Based on an evaluation of multiple Scala projects, the notation can be reasonably described as non-idiomatic.
UPDATE
The reason that the underscore is required is to disambiguate from infix notation, in which:
x?y
would be read as
x.?(y)
with ? being a method name. Whereas:
x_?y
Clearly demarks x_? as being atomic.
The syntax is an example of what is formally known as a "mixed identifier", and is intended to allow definitions such as
def prop_=(v:String) = ... //setter
def unary_- = ... //prefix negation operator
It could (arguably) be considered a hack when similar construct is used simply to shove a question mark at the end of a method name.
The ? denotes that this is a predicate, a function returning Boolean. This convention goes back to Lisp, where ? (Scheme), p or -p (other Lisps, simulating the question mark with a "similar" letter) also denote predicates. Think of it as asking a question, "is the object empty?"
Scala will only allow mixed identifier names (containing alphanumerics and punctuation) if you separate them by _. E.g.,
scala> def iszero?(x : Int) = x == 0
<console>:1: error: '=' expected but identifier found.
def iszero?(x : Int) = x == 0
^
doesn't work, but
scala> def iszero_?(x : Int) = x == 0
iszero_$qmark: (x: Int)Boolean
does.