How Scala compiler deals with potential multiple assignments of values - scala

val-variables in Scala should have the following properties, ensured during compilation, not later in runtime:
the immutable variable can not be used (a in "read") before being assigned to (bound).
the immutable variable can not be assigned again after being assigned once.
According to tutorials and docs it is not required to assign the val immediately at the declaration point as long as type is specified.
http://www.tutorialspoint.com/scala/scala_variables.htm
http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#value-declarations-and-definitions
But this seems to create a loophole
def fn1(x: Int, y: Int): Int = {
val const2 : Int
const2 = 0
if (x < 10) const2 = x
if (y > 10) const2 = y
const2
}
def fn2(x: Int, y: Int): Int = {
val const2 : Int
var i: Int
for( i <- x to y ){
const2 = 0
}
const2
}
In these both examples it seems impossible to the compiler to predict whether the assignment would be singular or not. So the compiler does not have standing to prohibit this code from being compiled, but it equally does not have grounds to warrant the singular-assignment nature of val-variables in every execution path possible at runtime.
Whatever compiler would do, compile the code or throw an error instead, it might end on the wrong side. So what should it do, specifications-wise ?
PS. a minor question with documentation: the chapter 4.1 has says
PatDef ::= Pattern2 {‘,’ Pattern2}
Why is it "Pattern2" repeated and having the same numeric index?
Should it perhaps be merely Pattern {‘,’ Pattern} instead or perhaps Pattern1 {‘,’ Pattern2} ?

This is illegal:
val const2 : Int
const2 = 0
vals cannot be reassigned after declaration, period.

Related

Why is it possible to assign recursive lambdas to non-lazy vals in Scala?

In the following statement the val f is defined as a lambda that references itself (it is recursive):
val f: Int => Int = (a: Int) =>
if (a > 10) 3 else f(a + 1) + 1 // just some simple function
I've tried it in the REPL, and it compiles and executes correctly.
According to the specification, this seems like an instance of illegal forward referencing:
In a statement sequence s[1]...s[n] making up a block, if a simple
name in s[i] refers to an entity defined by s[j] where j >= i,
then for all s[k] between and including s[i] and s[j],
s[k] cannot be a variable definition.
If s[k] is a value definition, it must be lazy.
The assignment is a single statement, so it satisfied the j >= i criteria, and it is included in the interval of statements the two rules apply to (between and including s[i] and s[j]).
However, it seems that it violates the second rule, because f is not lazy.
How is that a legal statement (tried it in Scala 2.9.2)?
You probably tried to use this in the REPL, which wraps all contents in an object definition. This is important because in Scala (or better: on the JVM) all instance values are initialized with a default value, which is null for all AnyRefs and 0, 0.0 or false for AnyVals. For method values this default initialization does not happen, therefore you get an error message in this case:
scala> object x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
defined object x
scala> def x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
<console>:7: error: forward reference extends over definition of value f
def x { val f: Int => Int = a => if (a > 10) 3 else f(a+1)+1 }
^
This behavior can even lead to weird situations, therefore one should be careful with recursive instance values:
scala> val m: Int = m+1
m: Int = 1
scala> val s: String = s+" x"
s: String = null x

Why can't a variable be assigned placeholder in function literal?

I'm having trouble understanding underscores in function literals.
val l = List(1,2,3,4,5)
l.filter(_ > 0)
works fine
l.filter({_ > 0})
works fine
l.filter({val x=1; 1+_+3 > 0}) // ie you can have multiple statements in your function literal and use the underscore not just in the first statement.
works fine
And yet:
l.filter({val x=_; x > 0})
e>:1: error: unbound placeholder parameter
l.filter({val x=_; x > 0})
I can't assign the _ to a variable, even though the following is legal function literal:
l.filter(y => {val x=y; x > 0})
works fine.
What gives? Is my 'val x=_' getting interpreted as something else? Thanks!
Actually, you have to back up a step.
You are misunderstanding how the braces work.
scala> val is = (1 to 5).toList
is: List[Int] = List(1, 2, 3, 4, 5)
scala> is map ({ println("hi") ; 2 * _ })
hi
res2: List[Int] = List(2, 4, 6, 8, 10)
If the println were part of the function passed to map, you'd see more greetings.
scala> is map (i => { println("hi") ; 2 * i })
hi
hi
hi
hi
hi
res3: List[Int] = List(2, 4, 6, 8, 10)
Your extra braces are a block, which is some statements followed by a result expression. The result expr is the function.
Once you realize that only the result expr has an expected type that is the function expected by map, you wouldn't think to use underscore in the preceding statements, since a bare underscore needs the expected type to nail down what the underscore means.
That's the type system telling you that your underscore isn't in the right place.
Appendix: in comments you ask:
how can I use the underscore syntax to bind the parameter of a
function literal to a variable
Is this a "dumb" question, pardon the expression?
The underscore is so you don't have to name the parameter, then you say you want to name it.
One use case might be: there are few incoming parameters, but I'm interested in naming only one of them.
scala> (0 /: is)(_ + _)
res10: Int = 15
scala> (0 /: is) { case (acc, i) => acc + 2 * i }
res11: Int = 30
This doesn't work, but one may wonder why. That is, we know what the fold expects, we want to apply something with an arg. Which arg? Whatever is left over after the partially applied partial function.
scala> (0 /: is) (({ case (_, i) => _ + 2 * i })(_))
or
scala> (0 /: is) (({ case (_, i) => val d = 2 * i; _ + 2 * d })(_))
SLS 6.23 "placeholder syntax for anonymous functions" mentions the "expr" boundary for when you must know what the underscore represents -- it's not a scope per se. If you supply type ascriptions for the underscores, it will still complain about the expected type, presumably because type inference goes left to right.
The underscore syntax is mainly user for the following replacement:
coll.filter(x => { x % 2 == 0});
coll.filter(_ % 2 == 0);
This can only replace a single parameter. This is the placeholder syntax.
Simple syntactic sugar for a lambda.
In the breaking case you are attempting null initialization/defaulting.
For primitive types with init conventions:
var x: Int = _; // x will be 0
The general case:
var y: List[String] = _; // y is null
var z: Any = _; // z = null;
To get pedantic, it works because null is a ref to the only instance of scala.Null, a sub-type of any type, which will always satisfy the type bound because of covariance. Look HERE.
A very common usage scenario, in ScalaTest:
class myTest extends FeatureTest with GivenWhenThen with BeforeAndAfter {
var x: OAuthToken = _;
before {
x = someFunctionThatReturnsAToken;
}
}
You can also see why you shouldn't use it with val, since the whole point is to update the value after initialization.
The compiler won't even let you, failing with: error: unbound placeholder parameter.
This is your exact case, the compiler thinks you are defaulting, a behaviour undefined for vals.
Various constraints, such as timing or scope make this useful.
This is different from lazy, where you predefine the expression that will be evaluated when needed.
For more usages of _ in Scala, look HERE.
Because in this two cases underscore (_) means two different things. In case of a function it's a syntactic sugar for lambda function, your l.filter(_ > 0) later desugares into l.filter(x => x > 0). But in case of a var it has another meaning, not a lambda function, but a default value and this behavior is defined only for var's:
class Test {
var num: Int = _
}
Here num gonna be initialized to its default value determined by its type Int. You can't do this with val cause vals are final and if in case of vars you can later assign them some different values, with vals this has no point.
Update
Consider this example:
l filter {
val x = // compute something
val z = _
x == z
}
According to your idea, z should be bound to the first argument, but how scala should understand this, or you you have more code in this computation and then underscore.
Update 2
There is a grate option in scala repl: scala -Xprint:type. If you turn it on and print your code in (l.filter({val x=1; 1+_+3 > 0})), this what you'll see:
private[this] val res1: List[Int] = l.filter({
val x: Int = 1;
((x$1: Int) => 1.+(x$1).+(3).>(0))
});
1+_+3 > 0 desugares into a function: ((x$1: Int) => 1.+(x$1).+(3).>(0)), what filter actually expects from you, a function from Int to Boolean. The following also works:
l.filter({val x=1; val f = 1+(_: Int)+3 > 0; f})
cause f here is a partially applied function from Int to Boolean, but underscore isn't assigned to the first argument, it's desugares to the closes scope:
private[this] val res3: List[Int] = l.filter({
val x: Int = 1;
val f: Int => Boolean = ((x$1: Int) => 1.+((x$1: Int)).+(3).>(0));
f
});

Curried update method

I'm trying to have curried apply and update methods like this:
def apply(i: Int)(j: Int) = matrix(i)(j)
def update(i: Int, j: Int, value: Int) =
new Matrix(n, m, (x, y) => if ((i,j) == (x,y)) value else matrix(x)(y))
Apply method works correctly, but update method complains:
scala> matrix(2)(1) = 1
<console>:16: error: missing arguments for method apply in class Matrix;
follow this method with `_' if you want to treat it as a partially applied function
matrix(2)(1) = 1
Calling directly update(2)(1)(1) works, so it is a conversion to update method that doesn't work properly. Where is my mistake?
The desugaring of assignment syntax into invocations of update maps the concatenation of a single argument list on the LHS of the assignment with the value on the RHS of the assignment to the first parameter block of the update method definition, irrespective of how many other parameter blocks the update method definition has. Whilst this transformation in a sense splits a single parameter block into two (one on the LHS, one on the RHS of the assignment), it will not further split the left parameter block in the way that you want.
I also think you're mistaken about the example of the explicit invocation of update that you show. This doesn't compile with the definition of update that you've given,
scala> class Matrix { def update(i: Int, j: Int, value: Int) = (i, j, value) }
defined class Matrix
scala> val m = new Matrix
m: Matrix = Matrix#37176bc4
scala> m.update(1)(2)(3)
<console>:10: error: not enough arguments for method update: (i: Int, j: Int, value: Int)(Int, Int, Int).
Unspecified value parameters j, value.
m.update(1)(2)(3)
^
I suspect that during your experimentation you actually defined update like so,
scala> class Matrix { def update(i: Int)(j: Int)(value: Int) = (i, j, value) }
defined class Matrix
The update desugaring does apply to this definition, but probably not in the way that you expect: as described above, it only applies to the first argument list, which leads to constructs like,
scala> val m = new Matrix
m: Matrix = Matrix#39741f43
scala> (m() = 1)(2)(3)
res0: (Int, Int, Int) = (1,2,3)
Here the initial one-place parameter block is split to an empty parameter block on the LHS of the assignment (ie. the ()) and a one argument parameter block on the RHS (ie. the 1). The remainder of the parameter blocks from the original definition then follow.
If you're surprised by this behaviour you won't be the first.
The syntax you're after is achievable via a slightly different route,
scala> class Matrix {
| class MatrixAux(i : Int) {
| def apply(j : Int) = 23
| def update(j: Int, value: Int) = (i, j, value)
| }
|
| def apply(i: Int) = new MatrixAux(i)
| }
defined class Matrix
scala> val m = new Matrix
m: Matrix = Matrix#3af30087
scala> m(1)(2) // invokes MatrixAux.apply
res0: Int = 23
scala> m(1)(2) = 3 // invokes MatrixAux.update
res1: (Int, Int, Int) = (1,2,3)
My guess is, that it is simply not supported. Probably not due to an explicit design decision, because I don't see why it shouldn't work in principle.
The translation concerned with apply, i.e., the one performed when converting m(i)(j) into m.apply(i, j) seems to be able to cope with currying. Run scala -print on your program to see the code resulting from the translation.
The translation concerned with update, on the other hand, doesn't seem to be able to cope with currying. Since the error message is missing arguments for method apply, it even looks as if the currying confuses the translator such that it tries to translate m(i)(j) = v into m.apply, but then screws up the number of required arguments. scala -print unfortunately won't help here, because the type checker terminates the translation too early.
Here is what the language specs (Scala 2.9, "6.15 Assignments") say about assignments. Since currying is not mentioned, I assume that it is not explicitly supported. I couldn't find the corresponding paragraph for apply, but I guess it is purely coincidental that currying works there.
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.

issue `object Foo { val 1 = 2 }` in scala

I found this issue of scala: https://issues.scala-lang.org/browse/SI-4939
Seems we can define a method whose name is a number:
scala> object Foo { val 1 = 2 }
defined module Foo
But we can't invoke it:
scala> Foo.1
<console>:1: error: ';' expected but double literal found.
Foo.1
And we can invoke it inside the object:
scala> object O { val 1 = 1; def x = 1 }
defined module O
scala> O.x
res1: Int = 1
And follow will throw error:
scala> object O { val 1 = 2; def x = 1 }
defined module O
scala> O.x
scala.MatchError: 2
at O$.<init>(<console>:5)
at O$.<clinit>(<console>)
at .<init>(<console>:7)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:9)
I use scalac -Xprint:typer to see the code, the val 1 = 2 part is:
<synthetic> private[this] val x$1: Unit = (2: Int(2) #unchecked) match {
case 1 => ()
}
From it, we can see the method name changed to x$1, and only can be invoked inside that object.
And the resolution of that issue is: Won't Fix
I want to know is there any reason to allow a number to be the name of a method? Is there any case we need to use a "number" method?
There is no name "1" being bound here. val 1 = 2 is a pattern-matching expression, in much the same way val (x,2) = (1,2) binds x to 1 (and would throw a MatchError if the second element were not thet same). It's allowed because there's no real reason to add a special case to forbid it; this way val pattern matching works (almost) exactly the same way as match pattern-matching.
There are usually two factors in this kind of decision:
There are many bugs in Scalac that are much higher priority, and bug fixing resources are limited. This behavior is benign and therefore low priority.
There's a long term cost to any increases in the complexity of the language specification, and the current behavior is consistent with the spec. Once things start getting special cased, there can be an avalanche effect.
It's some combination of these two.
Update. Here's what seems strange to me:
val pair = (1, 2)
object Foo
object Bar
val (1, 2) = pair // Pattern matching on constants 1 and 2
val (Foo, Bar) = pair // Pattern matching on stable ids Foo and Bar
val (foo, bar) = pair // Binds foo and bar because they are lowercase
val 1 = 1 // Pattern matching on constant 1
val Foo = 1 // *Not* pattern matching; binds Foo
If val 1 = 1 is pattern matching, then why should val Foo = 1 bind Foo rather than pattern match?
Update 2. Daniel Sobral pointed out that this is a special exception, and Martin Odersky recently wrote the same.
Here's a few examples to show how the LHS of an assignment is more than just a name:
val pair = (1, 2)
val (a1, b1) = pair // LHS of the = is a pattern
val (1, b2) = pair // okay, b2 is bound the the value 2
val (0, b3) = pair // MatchError, as 0 != 1
val a4 = 1 // okay, a4 is bound to the value 1
val 1 = 1 // okay, but useless, no names are bound
val a # 1 = 1 // well, we can bind a name to a pattern with #
val 1 = 0 // MatchError
As always, you can use backticks to escape the name. I see no problem in supporting such names – either you use them and they work for you or they do not work for you, and you don’t use them.

Scala puts precedence on implicit conversion over "natural" operations... Why? Is this a bug? Or am I doing something wrong?

This simple test, of course, works as expected:
scala> var b = 2
b: Int = 2
scala> b += 1
scala> b
res3: Int = 3
Now I bring this into scope:
class A(var x: Int) { def +=(y:Int) { this.x += y } }
implicit def int2A(i:Int) : A = new A(i)
I'm defining a new class and a += operation on it, and a convenient implicit conversion for those times when I want to add an Int to A's Int value.
I never expected this would affect the way my regular Int operations behave, when the "A" class is not at all part of the expression.
But it does:
scala> var b:Int = 0
b: Int = 0
scala> b += 1
scala> b
res29: Int = 0
scala> b += 2
scala> b
res31: Int = 0
What seems to be happening here is that the b:Int is implicitly converted to an "A", which is not bound to any variable, and then += is invoked on it, discarding the results.
Scala seems to give high precedence the implicit conversion over the natural += behavior (compiler magic, not an actual method) that is already defined to Ints. Common-sense as well as a C++ background tells me implicits should only be invoked as a last resort, when the compilation would otherwise fail. That leads to several questions...
Why? Is this a bug? Is it by design?
Is there a work-around (other than not using "+=" for my DSL's "+=" operation)?
Thanks
As others have noted, Int cannot have a += "method", because Int is immutable. What happens instead is that x += 1 is treated as a short form for x = x + 1, but only if there is no
method called += that is defined on the type. So method resolution takes precedence.
Given that Scala lets you define += methods and also lets you do += on variables, could we have changed the priority of the two? I.e. try expanded += first and only if that fails search for a method named +=?
Theoretically yes, but I argue it would have been worse than the current scheme. Practically, no. There are many types in Scala's collection library that define both a + method for
non-destructive addition and a += method for destructive addition. If we had switched the priority around then a call like
myHashTable += elem
would expand to
myHashTable = myHashTable + elem
So it would construct a new hashtable and assign this back to the variable, instead of simply updating an element. Not a wise thing to do...
From Programming in Scala, Chapter 17:
Whenever you write a += b, and a does
not support a method named +=, Scala
will try interpreting it as a = a + b.
The class Int does not contain method +=. However class A provides += method. That might be triggering the implicit conversion from Int to A.
I don't think it is a bug.
Actually, Int only has a "+" method but doesn't have a "+=" method.
b += 1 would transform to b = b + 1 in compile time if there is not a other implicit which has a "+=" method exists.
Scala seems to give high precedence the implicit conversion over the natural += that is already defined to Ints.
Which version of Scala are you talking about? I don't know of any version that has a += method on Int. Certainly, none of the still supported versions do, that must be some really ancient version you have there.
And since there is no += on Int, but you are calling a += method on Int, Scala tries to satisfy that type constraint via an implicit conversion.
Even withstanding Eastsun's explanation, it seems like this is a bug, and it should try the b=b+1 transformation before trying an implicit conversion for +=.
Please ask this question to the scala-user email list by emailing scala-user#listes.epfl.ch or by visiting n4.nabble.com/Scala-User-f1934582.html. If it's a bug, that's where it will be noticed and fixed.