Scala - the assignment associativity of "val a = b = c" - scala

As I read from book, scala operator associativity comes from left to right except operator ends with ":" char.
Given the val a = b = c, it becomes val a = (b = c) and makes a is initialized as Unit.
But why does not it become (val a = b) = c, and it cause that compile error because to use a Unit(returned from a=b) to receive c?
And after I really types (val a = b) = c, the compiler complains illeagal start of simple expression and pointers to val. Why are these two assignment operators not grouped from left to right?

The important thing to see here is that val a = b = c is a declaration and not an expression, but precedence and associativity are notions applying to expressions.
Looking at the Scala 2.11 Language Specification, 4.1 Value Declarations and Definitions, you can see that
val a = b = c
is a basic declaration falling into the PatVarDef case, so it can be read as (simplifying the Pattern2 part to the specific case of varid here):
'val' varid '=' Expr
Thus, here we have
the variable identifier varid is a,
the expression Expr is b = c,
a is assigned the value b = c evaluates to, which happens to be Unit.
For the later see What is the motivation for Scala assignment evaluating to Unit rather than the value assigned?
Note that the above assumes that b is a var, e.g.,
val c = 17
var b = 3
val a = b = c
as b is reassigned in the third line (else you would get error: reassignment to val). If you want to assign the same value to two val for some reason, you can use
val c = 17
val a, b = c

Related

Where is Scala's += defined in the context of Int?

Just starting out with Scala
var c = 0
c += 1 works
c.+= gives me error: value += is not a member of Int
Where is the += defined?
Section 6.12.4 Assignment Operators of the Scala Language Specification (SLS) explains how such compound assignment operators are desugared:
l ω= r
(where ω is any sequence of operator characters other than <, >, ! and doesn't start with =) gets desugared to
l.ω=(r)
IFF l has a member named ω= or is implicitly convertible to an object that has a member named ω=.
Otherwise, it gets desugared to
l = l.ω(r)
(except l is guaranteed to be only evaluated once), if that typechecks.
Or, to put it more simply: the compiler will first try l.ω=(r) and if that doesn't work, it will try l = l.ω(r).
This allows something like += to work like it does in other languages but still be overridden to do something different.
Actually, the code you've described does work.
scala> var c = 4
c: Int = 4
scala> c.+=(2) // no output because assignment is not an expression
scala> c
res1: Int = 6
I suspect (but can't say for sure) that it can't be found in the library because the compiler de-surgars (rewrites) it to c = c.+(1), which is in the library.

Kotlin: Curly braces around several expressions (or statements)

I think this question is somewhat related to Kotlin function declaration: equals sign before curly braces
In Scala, every statement is an expression (possibly with Unit type). If we surround multiple expressions with braces, then the final expression is the actual value of the curly braced part. Therefore,
// Scala
val a = {
val b = 1
val c = b + b
c + c
}
println(a)
The type of a is Int and the code prints the value 4.
However, in Kotlin, this is somewhat different.
If we do the same thing in the Kotlin,
// Kotlin
val a = {
val b = 1
val c = b + b
c + c
}
println(a)
The type of a is () -> Int and the code prints the Function0<java.lang.Integer>, which means a 0-ary function object with result type Int.
So if we want to print the value 4, we need to do println(a()).
In fact, the expression {} in Kotlin is a function () -> ().
I cannot find an explanation about this in Kotlin official reference pages. Without a parameter list or ->, curly braces make a function?
When I use Scala, I write many codes like the first code. However, in Kotlin, it creates a function object and we have to call the function, which may be an overhead in a loop or recursion.
Is there any document about this thing: just curly braces make a function object?
Any way to workaround the overhead in the second code if it is used many times?
EDIT
Here is the actual code that iterates many times:
in Java
while ((count = input.read(data, 0, BYTE_BLOCK_SIZE)) != -1) {
....
}
in Scala
while {
count = input.read(data, 0, BYTE_BLOCK_SIZE)
count != -1
} {
....
}
in Kotlin
while ({
count = input.read(data, 0, BYTE_BLOCK_SIZE)
count != -1
}()) {
...
}
You can see, only Kotlin makes a lot of function objects and calls them.
In Kotlin {} are always a lambda expression or a part of a syntax construct like while(true) {}. Probably different from Scala, but easy to grasp, nonetheless.
What you probably want is:
val a = run {
val b = 1
val c = b + b
c + c
}
println(a)
Kotlin has no build-in concept of "code blocks anywhere". Instead we use standard functions-helpers like run in the example above.
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run.html
If {} defines a function, you can just call the function upon declaring it, which will immediately evaluate it:
val a = {
val b = 1
val c = b + b
c + c
}()
println(a)
prints 4. (Note the () at the end of the block)
In Scala, every statement is an expression (possibly with Unit type)
That's not exactly true. Check: Is everything a function or expression or object in scala?
As Zoltan said {} defines functions so instead of:
// Kotlin
val a = {
val b = 1
val c = b + b
c + c
}
println(a)
it should be:
// Kotlin
val a = {
val b = 1
val c = b + b
c + c
}
println(a()) //you defined a function, which returns `4`, not expression
or
// Kotlin
val a = {
val b = 1
val c = b + b
c + c
}() //note these braces
println(a)
If you would like to print a value, not function, you can try to declare the variable and then use one of Kotlin functions to change a value like in example below:
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)
Read: Higher-Order Functions and
Lambdas
Hope it will help

+= operator in Scala

I'm reading Programming in Scala by M. Odersky and now I'm trying to understand the meaning of operators. As far as I can see, any operator in Scala is just a method. Consider the following example:
class OperatorTest(var a : Int) {
def +(ot: OperatorTest): OperatorTest = {
val retVal = OperatorTest(0);
retVal.a = a + ot.a;
println("=")
return retVal;
}
}
object OperatorTest {
def apply(a: Int) = new OperatorTest(a);
}
I this case we have only + operator defined in this class. And if we type something like this:
var ot = OperatorTest(10);
var ot2 = OperatorTest(20);
ot += ot2;
println(ot.a);
then
=+
30
will be the output. So I'd assume that for each class (or type?) in Scala we have += operator defined for it, as a += b iff a = a + b. But since every operator is just a method, where the += operator defined? Maybe there is some class (like Object in Java) containing all the defenitions for such operators and so forth.
I looked at AnyRef in hoping to find, but couldn't.
+= and similar operators are desugared by the compiler in case there is a + defined and no += is defined. (Similarly works for other operators too.) Check the Scala Language Specification (6.12.4):
Assignment operators are treated specially in that they can be
expanded to assignments if no other interpretation is valid.
Let's consider an assignment operator such as += in an infix operation
l += r, where l, r are expressions. This operation can be
re-interpreted as an operation which corresponds to the assignment
l = l + r except that the operation's left-hand-side l is evaluated
only once.
The re-interpretation occurs if the following two conditions are
fulfilled.
The left-hand-side l does not have a member named +=, and also cannot
be converted by an implicit conversion to a value with a member named
+=. The assignment l = l + r is type-correct. In particular this implies that l refers to a variable or object that can be assigned to,
and that is convertible to a value with a member named +.

Where is += method located for int in scala

Is +=(or any assignment operators) a method in scala for Int type.
For example,
var x=5
x+=1
Here I am able to use += method only when it is a variable.
I am not able to do,
5+=1
Does scala compiler considers this method as a special case?
Why it is not available in scala.Int class?
There is no += method, it is expanded to x = x + 1 by the compiler. This is detailed in the specification:
6.12.4 Assignment Operators
Let's consider an assignment operator such as += in an infix operation
l += r, where l, r
are expressions. This operation can be re-interpreted as an operation
which corresponds to the assignment
l = l + r
except that the operation's left-hand-side l is evaluated only once.
The re-interpretation occurs if the following two conditions are
fulfilled.
The left-hand-side l does not have a member named +=, and also cannot be converted by an implicit conversion to a value with a member
named +=.
The assignment l = l + r is type-correct. In particular this implies that l refers to a variable or object that can be assigned to,
and that is convertible to a value with a member named +.

Declaring multiple variables in Scala

I'd like to use val to declare multiple variable like this:
val a = 1, b = 2, c = 3
But for whatever reason, it's a syntax error, so I ended up using either:
val a = 1
val b = 2
val c = 3
or
val a = 1; val b = 2; val c = 3;
I personally find both options overly verbose and kind of ugly.
Is there a better option?
Also, I know Scala is very well thought-out language, so why isn't the val a = 1, b = 2, c = 3 syntax allowed?
The trivial answer is to declare them as tuples:
val (a, b, c) = (1, 2, 3)
What might be interesting here is that this is based on pattern matching. What is actually happens is that you are constructing a tuple, and then, through pattern matching, assigning values to a, b and c.
Let's consider some other pattern matching examples to explore this a bit further:
val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r
val DatePattern(year, month, day) = "2009-12-30"
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100))
val head :: tail = List.range(1, 10)
object ToInt {
def unapply(s: String) = try {
Some(s.toInt)
} catch {
case _ => None
}
}
val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01"
Just as a side note, the rnd example, in particular, may be written more simply, and without illustrating pattern matching, as shown below.
val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100)
Daniel's answer nicely sums up the correct way to do this, as well as why it works. Since he already covered that angle, I'll attempt to answer your broader question (regarding language design)...
Wherever possible, Scala strives to avoid adding language features in favor of handling things through existing mechanisms. For example, Scala doesn't include a break statement. However, it's almost trivial to roll one of your own as a library:
case object BreakException extends RuntimeException
def break = throw BreakException
def breakable(body: =>Unit) = try {
body
} catch {
case BreakException => ()
}
This can be used in the following way:
breakable {
while (true) {
if (atTheEnd) {
break
}
// do something normally
}
}
(note: this is included in the standard library for Scala 2.8)
Multiple assignment syntaxes such as are allowed by languages like Ruby (e.g. x = 1, y = 2, z = 3) fall into the category of "redundant syntax". When Scala already has a feature which enables a particular pattern, it avoids adding a new feature just to handle a special case of that pattern. In this case, Scala already has pattern matching (a general feature) which can be used to handle multiple assignment (by using the tuple trick outlined in other answers). There is no need for it to handle that particular special case in a separate way.
On a slightly different aside, it's worth noting that C's (and thus, Java's) multiple assignment syntax is also a special case of another, more general feature. Consider:
int x = y = z = 1;
This exploits the fact that assignment returns the value assigned in C-derivative languages (as well as the fact that assignment is right-associative). This is not the case in Scala. In Scala, assignment returns Unit. While this does have some annoying drawbacks, it is more theoretically valid as it emphasizes the side-effecting nature of assignment directly in its type.
I'll add one quirk here, because it hit myself and might help others.
When using pattern matching, s.a. in declaring multiple variables, don't use Capital names for the variables. They are treated as names of classes in pattern matching, and it applies here as well.
val (A,B)= (10,20) // won't work
println(A)
Error message does not really tell what's going on:
src/xxx.scala:6: error: not found: value A
val (A,B)= (10,20)
^
src/xxx.scala:6: error: not found: value B
val (A,B)= (10,20)
^
src/xxx.scala:7: error: not found: value A
println(A)
^
I thought `-ticking would solve the issue but for some reason does not seem to (not sure, why not):
val (`A`,`B`)= (10,20)
println(A)
Still the same errors even with that.
Please comment if you know how to use tuple-initialization pattern with capital variable names.
If all your variables are of the same type and take same initial value, you could do this.
val a, b, c: Int = 0;
It seems to work if you declare them in a tuple
scala> val (y, z, e) = (1, 2, 45)
y: Int = 1
z: Int = 2
e: Int = 45
scala> e
res1: Int = 45
Although I would probably go for individual statements. To me this looks clearer:
val y = 1
val z = 2
val e = 45
especially if the variables are meaningfully named.