What does { val x = a; b.:::(x) } mean in Scala? - scala

I am new to Scala and studying a book about it (Programming in Scala). I am really lost, what is the author trying to explain with the code below. Can anyone explain it in more detail ?
{ val x = a; b.:::(x) }

::: is a method that prepends list given as argument to the list it is called on
you could look at this as
val a = List(1, 2)
val b = List(3, 4)
val x = a
b.prependList(x)
but actually for single argument methods if it's not ambiguous scala allows to skip parenthesis and the dot and this is how this method is supposed to be used to not look ugly
x ::: b
it will just join these two lists, but there is some trick here
if method name ends with : it will be bound the other way
so typing x ::: b works as if this type of thing was done (x):::.b. You obviously can't type it like this in scala, won't compile, but this is what happens. Thanks to this x is on the left side of the operator and it's elements will be on the left side (beginning) of the list that is result of this call.
Oh well, now I found maybe some more explanation for you and also the very same piece of code you posted, in answer to this question: What good are right-associative methods in Scala?

Assuming a and b are lists: It assigns a to x, then returns the list b prepended with the list x.
For example, if val a = List(1,2,3) and val b = List(4,5,6) then it returns List(1,2,3,4,5,6).

Related

Get a different result when calling the same function

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)

What is the use of ::: (triple colons) in Scala

I am new to scala..I came across a concept where it says like below:
{ val x = a; b.:::(x) }
In this block a is still evaluated before b, and then the result of
this evaluation is passed as an operand to b’s ::: method
What is the meaning of above statement..
I tried like below:
var a =10
var b =20
What should be the result i should expect.
Can somebody please give me an example...
Thanks in advance....
The ::: operator is defined on List trait and concatenates two lists. Using it on Int like in your example (var a=10) shouldn't work (unless you define such operator yourself).
Here is how it works on lists:
val a = List(1, 2);
val b = List(3, 4);
val c1 = a ::: b // List(1, 2, 3, 4)
val c2 = a.:::(b) // List(3, 4, 1, 2)
Calling ::: with the infix syntax (c1) and method call syntax (c2) differ in the order in which lists are concatenated (see Jörg's comment).
The statement "a is still evaluated before b" means that a is evaluated before passing it as an argument to the method call. Unless the method uses call by name, its arguments are evaluated before the call just like in Java.
This could give you some hint how to search for meaning of Scala operators and keywords.

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.

How can I be modifying a Nil list?

You know that scene in Goodbye and Thanks For All The Fish where Arthur is so deliriously happy he stops a waiter and demands to know, "Why is this food so good?" I'm in that situation. Scala seems to be doing exactly what I'd want, but I don't understand how it's doing it. Consider the following:
scala> var v = Nil:List[String];
v: List[String] = List()
scala> v.length
res38: Int = 0
scala> v ::= "Hello"
scala> v.length
res39: Int = 1
scala> Nil.length
res40: Int = 0
Which is exactly what you'd hope for, but how is it happening?
Nil is an object that extends List[Nothing], which is a subtype of List[String], so assignment works fine, but it's an immutable list, isn't it? So I shouldn't be able to append to it. But I can append to it, or at least I can append to v, which I thought point to Nil. v is changed, but Nil isn't.
So, WTF? Does Scala have some clever copy-on-modify semantics I'm unaware of? Is Nil really a function that returns empty lists? More broadly, is there some way I could have made the REPL answer these questions?
When Scala sees
v ::= "Hello"
it first checks if v knows the method ::=. In this case (type List), it doesn't, so, because the method consists only of symbols and ends with an = sign, it tries something else:
v = v.::("Hello")
which, incidentally, is written "Hello" :: v in infix notation. Now, since v knows the method ::, that works and returns a new List, which is then assigned to v as indicated.
By the way, it is prepending, not appending.
When you use the keyword var you're not "translating to final" in the Java sense. Instead, var allows for reassignment. When you call the operator ::= you're actually reassigning what v points to. The operator ::= returns a new list, not the original list with "Hello" appended to it. Hence, v is now pointing to "Hello" and not a Nil list.
Here, watch this:
var myThing = new List(1, 2, 3)
var myOhterThing = myThing
myThing = new List(1, 2, 3, 4)
It's almost the same as saying "take the first list, copy it and append a '4' onto it. Now assign 'myThing' to point to that list." Using that operator you have effectively done the same thing. Writing it out this way lets you see that.
Try it with val v, to see what's mutable. :)
Nil is immutable. When you cons to it (::) you get a new instance which is also immutable.
Try this:
val v1 = Nil
val v2 = "Hello" :: v1
v1 == v2
(you will get false since they don't point to the same object)
Given v is a var you can reassign values to it.
So when you have:
v ::= "Hello" // what you really have is:
v = "Hello" :: v // or
v = "Hello" :: Nil // or
v = List("Hello")
The above creates a new List and Nil is left unchanged. It is similar to String addition in Java. Since String is immutable you never change a single instance - only create new ones.
Since Nil has not changed, Nil.length = 0.

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.