scala> val set = Set("apricot", "banana", "clementine", "durian", "fig", "guava", "jackfruit", "kiwi", "lime", "mango")
set: scala.collection.immutable.Set[java.lang.String] = Set(banana, durian, fig, jackfruit, lime, mango, clementine, apricot, kiwi, guava)
scala> set.partition(_ length > 5)
<console>:1: error: ')' expected but integer literal found.
set.partition(_ length > 5)
^
scala> set.partition(_.length > 5)
res5: (scala.collection.immutable.Set[java.lang.String], scala.collection.immutable.Set[java.lang.String]) = (Set(banana, durian, jackfruit, clementine, apricot),Set(fig, lime, mango, kiwi, guava))
Can someone please explain why does it complain when I execute
set.partition(_ length > 5)
and not when I execute
set.partition(_.length > 5)
I have also tried the following with little success:
scala> set.partition((_ length) > 5)
<console>:9: error: missing parameter type for expanded function ((x$1) => x$1.length)
set.partition((_ length) > 5)
^
When you drop the dot, Scala assumes you have a one-parameter method. In other words, when you say _ length > 5 it thinks that length is a method requiring one argument, that > is that argument, and then it doesn't konw what to do with the 5.
Notice that this is similar to when you write 5 + 5. This statement is the same as writing 5.+(5), but you are dropping the dot and parentheses. Scala notices the missing dot and assumes (correctly) that + is a method requiring a single argument.
If you write "abc" length by itself, then there is nothing for Scala to assume is the argument, so it then realizes that length doesn't require one.
So:
"abc".length // fine
"abc" length // fine
"abc".length > 4 // fine
("abc" length) > 4 // fine
"abc" length > 4 // error!
Thus, you need either a dot or parentheses to tell the compiler that "abc" and length go together and have no additional argument.
In terms of coding style, I suggest you always use the dot for zero-arg methods. I find it more readable and it will help you to avoid compilation errors such as this one.
When you write:
set.partition(_ length > 5)
// ^ object
// ^ method
// ^ parameter
it treats length as a method that receives one parameter, >.
While when you write:
set.partition(_.length > 5)
// ^------^ object
// ^ method
// ^ parameter
it treats _.length as the object, > is the parameter, and 5 is the argument.
Related
I read that if a method takes no argument and has no side-effects, parenthesis can be removed to improve readability (spartan implementation). So I can call following code
def withoutP = {
println(s"without p")
}
withoutP
Then I found this code which takes arguments but I can still call it without parenthesis. How?
def isEven(n: Int) = (n % 2) == 0
List(1, 2, 3, 4) filter isEven foreach println
I tried running this code but it didn't work. Why?
def withP(i:Int) = {
println("with p")
}
withP 1
';' expected but integer literal found.
[error] withP 1
[error] ^
[error] one error found
In your example
def isEven(n: Int) = (n % 2) == 0
List(1, 2, 3, 4) filter isEven foreach println
you don't actually call isEven. You call filter, which is a method on List, and isEven is the parameter for filter. filter calls isEven for every value in the list, using the value as the argument.
filter is written in the infix notation, which is legal for methods that accept only one argument. The alternative is
List(1, 2, 3, 4).filter(isEven)
The . is also required in this case, because filter is a method in the List class.
1.For first example, invoke withoutP without parameter, this compiles is by Scala allows the omission of parentheses on methods of arity-0 (no arguments)
2.For second example, invoke withoutP 1 with a parameter, this not compile is caused by Infix notation need to start with a object. so you can achieve parentheses by:
this withP 1 //infix notation with this (current object)
so for the 1 and 2 are not the same omission parentheses rules. First is the arity-0 rule, and Second should use Infix notation to omit parentheses.
In Scala, if I have a variable declaration, e.g.
var x: Char = 'a'
If I then try and update this character by adding 1, e.g.
x = x + 1
I get a compilation error: Type mismatch, found Int required Char. However, I can do this without a compilation error:
x = 'a' + 1
I'm guessing this has something to do with literal values vs objects, however, I'm trying to get my head around the exact behaviour. You can clearly assign a literal integer to a Char, e.g. 97, and you can also assign the result of 97-32. However if I say 97-32+5 then I get a type mismatch error. At what point does the compiler differentiate between an expression that results in a literal vs one that result in an object?
Assignment is the key here.
Look at the following REPL session:
alex#POSITRON ~ $ scala
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val x:Char = 'a'
x: Char = a
scala> x + 1
res0: Int = 98
scala> var y:Char = 'a'
y: Char = a
scala> y + 1
res1: Int = 98
scala> y = y + 1
<console>:8: error: type mismatch;
found : Int
required: Char
y = y + 1
^
scala>
So as you can see unless you try to reassign the variable values everything goes fine. When you write 'a'+1 or x + 1 it gets converted to Int.
So when you finally try to x = x + 1 reassign then you are trying to assign Int value to the Char variable. This explain why compilation error occurs.
In the Char companion object there is implicit def char2int(x: Char): Int method.
I think in var x:Char = 'a' + 1 the first thing which happens is invocation of this method to convert 'a' to 97. Then 97 is added 1, both as Ints. Then the variable x gets instantiated in the same way as in val y:Char = 98. This I think explains how variable initialization works.
There's a special rule for typing literals in the spec.
However, if the expected type pt of a literal in an expression is
either Byte, Short, or Char and the integer number fits in the numeric
range defined by the type, then the number is converted to type pt and
the literal's type is pt.
That lets you write:
scala> 97 : Char
res0: Char = a
scala> 97 + 1 : Char
res1: Char = b
Sneakily, they mean constant expressions here. But the definition of constant expression is platform-specific, so technically res1 could also fail to compile, if it were not constant-folded.
A related question about constant folding in scaladoc shows the weird loss of type checking under scaladoc:
$ ~/scala-2.12.3/bin/scaladoc -d /tmp folded.scala
folded.scala:9: error: type mismatch;
found : Int
required: Char
x = 'a' - 32 + 5
^
model contains 4 documentable templates
one error found
Is it possible to call an apply function directly on the result of a method which takes a second parameter list (with an implicit arg)? Even with parentheses in the logical place, I get the same compile-time type error, which indicates it doesn't parse it as expected.
val x = Map(1 -> 2, 2->4, 3-> 6) //1
val y = x.map(_.swap) //2
y(4) //3
x.map(_.swap)(4) //4
((x.map(_.swap))(4) //5
Line 4 makes sense to not parse since the (4) easily appears to be the second parameter list for map(), but line 5, there is a set of ()'s around the .map expression, yet it still associates the (4) to the .map rather than the result of .map().
Is there a way to do lines 2 and 3 in one expression?
EDIT: I'm aware of .apply(), which is what the compiler will insert itself. Is there a way to do this without manually de-sugaring?
Yes there are several possible solutions.
All work by either satisfying the implicit parameter list or giving the compiler a hint that expression has ended and the (), read apply, is really the apply-method and no second argument list.
1. Calling .apply()
scala> Map(1 -> 2, 2 -> 4, 3 -> 6).map(_.swap).apply(4)
res7: Int = 2
2. Supplying the implicit directly
Another option is supplying the implicit directly
Example with breakout
import scala.collection.breakOut
scala> List(1).map(_ + 1)(breakOut)(0)
res38: Int = 2
I think the general problem is: You have to fill to provide the implicit for the CanBuildFrom to work properly or explicitly state that you want to call apply and not fill the second parameter list.
You can find more in http://docs.scala-lang.org/tutorials/FAQ/breakout. Opposing to the name the secCanBuildFrom works.
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.
There is something that I can't quite understand hope someone can shed some light..
I have Seq[String]
val strDeps: Seq[String] = ...
and I tried to sort it on the reverse of the using the sortWith method and I get the following error.
scala> print(strDeps.sortWith(_.reverse.compareTo(_.reverse) < 0) mkString ("\n"))
<console>:15: error: wrong number of parameters; expected = 2
print(strDeps.sortWith(_.reverse.compareTo(_.reverse) < 0) mkString ("\n"))
^
But when I try sort it without doing a reverse it works fine.
scala> print(strDeps.sortWith(_.compareTo(_) < 0) mkString ("\n"))
// this is fine
Also it works fine without the placeholder syntax
scala> print(strDeps.sortWith((a,b) => a.reverse.compareTo(b.reverse) < 0) mkString ("\n"))
// this works fine too
_ expands only to the smallest possible scope.
The inner _.reverse part is already interpreted as x => x.reverse therefore the parameter is missing inside sortWith.
compareTo(_)
Is a partially applied method. It just means "compareTo, but without applying the first parameter". Note that _ is not a parameter. Rather, it indicates the absence of a parameter.
compareTo(_.reverse)
Is a method taking an anonymous function as parameter, the parameter being _.reverse. That translates to x => x.reverse.