Scala operator oddity - scala

When I invoke + on 2 I get an Int back, but when its done using explicit method call I get Double instead.
scala> 2+2
res1: Int = 4
scala> 2.+(2)
res2: Double = 4.0
It seems that .+() is invoked on implicit converted Int to Double.
scala> 2.+
<console>:16: error: ambiguous reference to overloaded definition,
both method + in class Double of type (x: Char)Double
and method + in class Double of type (x: Short)Double
match expected type ?
2.+
^
Why is that so ?

In Scala 2.9 and before, 2. is interpreted as 2.0 so the ambiguous dot denotes a float literal. You’d explicitly call the method by using the syntax (2).+(2).
The ambiguous floating point syntax will however be deprecated in 2.10:
scala> 2.+(2)
<console>:1: warning: This lexical syntax is deprecated. From scala 2.11, a dot will only be considered part of a number if it is immediately followed by a digit.
2.+(2)
^
<console>:2: warning: This lexical syntax is deprecated. From scala 2.11, a dot will only be considered part of a number if it is immediately followed by a digit.
2.+(2)
^
<console>:8: warning: This lexical syntax is deprecated. From scala 2.11, a dot will only be considered part of a number if it is immediately followed by a digit.
2.+(2)
^
res1: Double = 4.0

The reason is not in explicit method call -- by writing 2.+ you specifying Double on the left side and then calling addition operator on it:
scala> 2.
res0: Double = 2.0

Related

Scala coding standards: curly braces on the same line

The scala coding standards state that
Technically, Scala’s parser does support GNU-style notation with opening braces on the line following the declaration. However, the parser is not terribly predictable when dealing with this style due to the way in which semi-colon inference is implemented. Many headaches will be saved by simply following the curly brace convention demonstrated above.
I've looked, and I couldn't find any real examples of this. Can anyone explain the reasoning behind this with an exmaple? Has anyone run into problems with using curly braces on a new line?
Consider this expression:
someElement
{
// Some code
}
How is this interpreted? Is it an expression (such as a value, or a function call with no arguments) followed by a block statement enclosed within braces? Or is it a function call with the braces enclosing a single argument?
If Scala didn't have semicolon inference—that is, if Scala required semicolons to denote the end of a statement in the same manner that Java does—then the two could be easily distinguished because the former would require a semicolon at the end of the first line. However, the Scala parser has to infer where the semicolon(s) need to be to make sense of the code, and sometimes it gets things wrong. (Both interpretations, depending upon context, are valid and it's not always possible for the Scala parser to resolve the ambiguity by itself.)
For example, let's say that someElement is a function with a by name argument. If you attempt to call it in the Scala REPL intending to put the argument (within braces) on another line, you'll find that entering someElement alone causes an error:
> scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.
scala> def someElement(x: => Int): Int = {
| // Do something...
| x
| }
someElement: (x: => Int)Int
scala> someElement
<console>:13: error: missing argument list for method someElement
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `someElement _` or `someElement(_)` instead of `someElement`.
someElement
^
That is, you don't even get as far as entering the braces. However, if you enter the following, then you're OK:
scala> someElement {
| 10
| }
res0: Int = 10
But what if someElement is a value? Now we see this in the REPL:
scala> val someElement = 5
someElement: Int = 5
scala> someElement
res1: Int = 5
scala> {
| 5
| }
res2: Int = 5
Now the REPL accepts the same code, on separate lines, as two different expressions.
Let's get really ambiguous. Say someElement is a value, but it's now a reference to a function taking a single argument. Let's look at the possible interpretations:
scala> def square(a: Int) = a * a
square: (a: Int)Int
scala> val someElement = square _
someElement: Int => Int = $$Lambda$1034/1609754699#74abbb
scala> someElement
res3: Int => Int = $$Lambda$1034/1609754699#74abbb
scala> {
| 5
| }
res4: Int = 5
That is, it's treated as two separate statements: a value followed by a block statement. However:
scala> someElement {
| 5
| }
res5: Int = 25
is treated as a call to square with an argument of 5.
The Scala compiler is a little smarter than the REPL since it can see all of the code at once, and will try to resolve ambiguities by seeing which of the alternatives make the most sense, but its interpretation may not always match yours.
So, as you can see, putting the open brace on the same line—if the two expressions are linked—makes the relationship explicit and removes ambiguity. Alternatively, if you want the expressions to be parsed unambiguously as separate statements, add a semicolon after the first line.
(IMHO, the semicolon inference is one of Scala's Achilles Heels.)

How can I find the definition of methods/operations defined in an implicitly-converted class?

I'm looking at someone else's source code (Scala), where I see the operator :+= being called on a variable of type IndexedSeq. I am looking all over the scaladocs page for that class to figure out what that operator does, but I do not see it. I'm thinking that either it's defined in a class outside of IndexedSeq's inheritance hierarchy, or else the javascript on the scaladocs page is hiding it somewhere I can't see it. (Actually it's neither; see answer below.)
I've hit every button on the scaladocs page trying to unhide everything. I've looked in the web-page's HTML code. There has got to be a way to look up an operator from the documentation of a class to which it can be applied. Hasn't there?
(N.B.: I looked up that operator using symbolhound, so I know what that operator means now. This question is about scala documentation in general, not that particular operator.)
All operators in Scala are normal methods.
You cannot find it because it is compiler magic for re-assignement, it is not an operator. Or to say it another way: it looks like an operator of its own, but it is actually "an operator followed by the = character".
The compiler will magically turn that into a assignment if the operator (here :+) returns the proper type, and the original value was a var, obviously.
Since it is not provided by any implicit nor explicit method on Seq[T] or whatever, it does not appear anywhere in the generated scaladoc.
So to answer the general question:
It is a language construct, so the only place where it is documented is the specification, sadly,
but, if you find some "<?>=" unknown operator somewhere, look for the definition of "<?>", that one is sure to be documented.
Edit: I finally found where this is defined in the SLS:
§6.12.4:
An assignment operator is an operator symbol (syntax category op in (§1.1)) that
ends in an equals character “=”, with the exception of operators for which one of the
following conditions holds:
(1) the operator also starts with an equals character, or
(2) the operator is one of (<=), (>=), (!=).
It also says later on that it only happens when all other options have been tried (including potential implicits).
Is this value assigned to a variable? If it's the case I think this syntax sugar:
scala> var x = IndexedSeq(1,2,3)
x: IndexedSeq[Int] = Vector(1, 2, 3)
scala> x :+= 10
scala> x
res59: IndexedSeq[Int] = Vector(1, 2, 3, 10)
scala> val y = IndexedSeq(1,2,3)
y: IndexedSeq[Int] = Vector(1, 2, 3)
scala> y :+= 10
<console>:16: error: value :+= is not a member of IndexedSeq[Int]
y :+= 10
^
It is syntax sugar for "operation and assignment", like +=:
scala> var x = 10
x: Int = 10
scala> x += 1
scala> x
res63: Int = 11
Which de-sugars to x = x + 1.

Why does "a".::(List()) report error ":: is not member of string"?

See this:
scala> 1 + 1
res0: Int = 2
scala> 1.+(1)
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
res1: Double = 2.0
scala> "a" :: List()
res2: List[String] = List(a)
scala> "a".::(List())
<console>:8: error: value :: is not a member of String
"a".::(List())
^
Why does the error occur?
Try this
List().::("a")
The reason is that :: is a method of List.
From ScalaByExample:
Like any infix operator, :: is also implemented as a method of an
object. In this case, the object is the list that is extended. This is
possible, because operators ending with a ‘:’ character are treated
specially in Scala. All such operators are treated as methods of their
right operand. E.g.,
x :: y = y.::(x) whereas x + y = x.+(y)
Note, however, that operands of a binary operation are in each case
evaluated from left to right. So, if D and E are expressions with
possible side-effects,
D :: E
is translated to
{val x = D; E.::(x)}
in order to maintain the left-to-right order of operand evaluation.
In scala methods which ends with : got applied in reverse order.
So when you write a::list it is actually list.::(a). String doesn't have :: method, so the solution is to write List().::("a") or Nil.::("a")
Because of operator precedence. In Scala methods which ends with : are right associative. So you should call List().::("a")
If you want to use left associative method then you should write List("a") ++ List(), but that's not always a good choice, cause it has linear execution time

Adding an Int to a String in scala [duplicate]

This question already has answers here:
Scala operator oddity
(2 answers)
Closed 10 years ago.
I am having a little trouble understanding the rationale behind the following few pieces of scala code:
We all know that 1 + 1 = 2 in the REPL.
scala> 1 + 1
res0: Int = 2
If I type in "Abc" + "Def", I should get "AbcDef" in the REPL.
scala> "Abc" + "Def"
res6: java.lang.String = AbcDef
Now let's say I invoke the + method on String "Abc" and pass "Def" as a parameter:
scala> "Abc".+("Def")
res7: java.lang.String = AbcDef
By the same rationale, why does something like 1.+(1) return a double 2.0?
scala> 1.+(1)
res1: Double = 2.0
Also, why does passing the argument "1" as a parameter result in "1.01" as follows:
scala> 1.+("1")
res9: String = 1.01
Why is the returned result a String instead of an effort for "1" to me transformed into the callers type?
Thanks
If you try that on Scala 2.10.0, you'll get a clue as to the answer:
scala> 1.+(1)
<console>:1: warning: This lexical syntax is deprecated. From scala 2.11,
a dot will only be considered part of a number if it is immediately
followed by a digit.
1.+(1)
^
Simply put, 1. is a valid Double in Scala (as it is in Java), so Scala is really doing this:
1. + (1)
That is, infix addition of a Double to an expression enclosed inside a (redundant) parenthesis.
As for the latter, Scala follows Java convention that anything added to a String results in a String and vice versa.

Having trouble adding update method to Symbol

I am attempting to add an update method to the Symbol class.
class SymbolUpdate(s: Symbol) {
def update(i: Int) = s.name + i
}
implicit def toSymbolUpdate(s: Symbol) = new SymbolUpdate(s)
But when I run the code I get the following
scala> 's = 1
<console>:327: error: value update is not a member of object Symbol
's = 1
^
But it does work when I call the method directly.
scala> 's.update(1)
res41: java.lang.String = s1
Or if I explicitly put an empty argument array.
scala> 's() = 1
res42: java.lang.String = s1
Not sure what the problem is with my code?
According to the Scala Language Spec:
An assignment f(args) = e with a function application to the left of the ‘=’ operator is interpreted as f.update(args, e), i.e. the invocation of an update function
defined by f.
It's especially clear if you read the corresponding section in Programming in Scala:
Similarly, when an assignment is made to a variable to which parenthesis and one or more arguments have been applied, the compiler will transform that into an invocation of an update methods that takes the arguments in parenthesis as well as the object to the right of the equals sign.
Together, I take it to mean that the parenthesis are required.