Related
In Scala 2 as explained here we had a Function Type that was implementing trait FunctionX and Method Type that was a non-value type. We could transform a method to Method Value which was an instance of Function Type like this:
class Sample {
def method(x:Int) = x+1
val methodValue = method _
}
Now in Scala 3, we can leave the underscore so it looks more like this:
class Sample:
def method(x:Int) = x+1
val methodValue = method
Isn't the equality sign suggesting semantic equivalence of method and function value in val methodValue = method? Also in Scala 2 I couldn't use any methods (at least in Scastie with Scala version 2.13.5) on created method like apply but in Scala 3 I can do that suggesting that methods in Scala 3 are regular objects:
scala> val s = Sample()
val s: Sample = Sample#793c2cde
scala> s.method
val res13: Int => Int = Lambda$1530/856511870#ab595e8
scala> s.methodValue
val res14: Int => Int = Sample$$Lambda$1422/1191732945#1bbbede1
scala> s.method.
!= andThen compose finalize isInstanceOf notifyAll →
## apply ensuring formatted ne synchronized
-> asInstanceOf eq getClass nn toString
== clone equals hashCode notify wait
So is Scala 3 functions and methods the same or very similar objects or at least the difference has been significantly reduced?
Isn't the equality sign suggesting semantic equivalence of method and
function value in val methodValue = method?
The key concept to understand is eta expansion which converts methods into functions. Scala 3 has automated this process so
The syntax m _ is no longer needed and will be deprecated in the
future.
Hence methods and functions are not the same, however Scala 3 tries to transparently convert between them so programmers do not have to worry about the distinction.
I'm confused over when a select is appropriate and when an apply is. I thought apply was a function or method application, thus
scala> val expr = u reify { Random.nextInt }
expr: reflect.runtime.universe.Expr[Int] = Expr[Int](Random.nextInt())
scala> u showRaw expr.tree
res0: String = Apply(Select(Ident(scala.util.Random), newTermName("nextInt")), List())
Is what I expect; an application of nextInt with an empty parameter list.
Also,
scala> val expr = u reify { Random.shuffle(List("sammy", "snake")) }
expr: reflect.runtime.universe.Expr[List[String]] = Expr[List[String]](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom))
scala> u showRaw expr.tree
res2: String = Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom"))))
Is again what I expected - an application of the shuffle method, with a list of strings.
However,
scala> val expr = u reify { Random.shuffle(List("sammy", "snake")).head }
expr: reflect.runtime.universe.Expr[String] = Expr[String](Random.shuffle(List.apply("sammy", "snake"))(List.canBuildFrom).head)
scala> u showRaw expr.tree
res1: String = Select(Apply(Apply(Select(Ident(scala.util.Random), newTermName("shuffle")), List(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant("sammy")), Literal(Constant("snake")))))), List(Select(Ident(scala.collection.immutable.List), newTermName("canBuildFrom")))), newTermName("head"))
Is a Select on head. I'm confused because I would have thought that that outer node would be an application of head. Why is it a select when head is a method?
Is there a web page that details the difference between Select and Apply because I cannot find one.
The meaning of Select and Apply is purely syntactical.
Select(prefix, newTermName("member")) means prefix.member
Apply(prefix, List(arg1, arg2, ...)) means prefix(arg1, arg2, ...)
So techically, Random.nextInt is a Select, but the Scala typechecker wrapped it in an additional Apply because Random.nextInt is defined as a function that takes single, empty parameter list. In other words, this is a desugaring performed by the typechecker.
This isn't the case with List's head method. If you look at its definition, it takes no parameter lists:
def head: A
And that's why the typechecker does not wrap it in an Apply tree.
Summarizing - there is difference between methods that take single, empty parameter list and methods that take no parameter lists. As a syntactic sugar, Scala allows to call methods with single, empty parameter list as if they take no parameter lists (without any parens), but the typechecker will still add the Apply in such cases.
In this case, trees precisely reproduce syntactic structure of Scala programs. Select corresponds to member selection, e.g. to foo.bar, whereas Apply stands for an application of an argument list, e.g. baz(1, 2, 3).
If we have an empty arglist method in Scala, e.g. def x() = ??? (or Random.nextInt()), then its invocation can be written both as a Select (corresponding to something.x) and an Apply(Select(...), Nil) (corresponding to something.x()), because both are valid Scala expressions.
If we have a nullary method in Scala, e.g. def y = ??? (or List.head), then its invocation can only be written as a Select (which corresponds to somethingElse.y). If we write Apply(Select(...), Nil), that would mean somethingElse.y(), which would stand for applying an empty argument list to the result of calling method y on somethingElse.
I am new to scala, and today when I came across this akka source code I was puzzled:
def traverse[A, B](in: JIterable[A], fn: JFunc[A, Future[B]],
executor: ExecutionContext): Future[JIterable[B]] = {
implicit val d = executor
scala.collection.JavaConversions.iterableAsScalaIterable(in).foldLeft(
Future(new JLinkedList[B]())) { (fr, a) ⇒
val fb = fn(a)
for (r ← fr; b ← fb) yield { r add b; r }
}
}
Why the code is written using implicit parameters intentionally? Why can't it be written as:
scala.collection.JavaConversions.iterableAsScalaIterable(in).foldLeft(
Future(new JLinkedList[B](),executor))
without decalaring a new implicit variable d? Is there any advantage of doing this? For now I only find implicits increase the ambiguity of the code.
I can give you 3 reasons.
1) It hides boilerplate code.
Lets sort some lists:
import math.Ordering
List(1, 2, 3).sorted(Ordering.Int) // Fine. I can tell compiler how to sort ints
List("a", "b", "c").sorted(Ordering.String) // .. and strings.
List(1 -> "a", 2 -> "b", 3 -> "c").sorted(Ordering.Tuple2(Ordering.Int, Ordering.String)) // Not so fine...
With implicit parameters:
List(1, 2, 3).sorted // Compiller knows how to sort ints
List(1 -> "a", 2 -> "b", 3 -> "c").sorted // ... and some other types
2) It alows you to create API with generic methods:
scala> (70 to 75).map{ _.toChar }
res0: scala.collection.immutable.IndexedSeq[Char] = Vector(F, G, H, I, J, K)
scala> (70 to 75).map{ _.toChar }(collection.breakOut): String // You can change default behaviour.
res1: String = FGHIJK
3) It allows you to focus on what really matters:
Future(new JLinkedList[B]())(executor) // meters: what to do - `new JLinkedList[B]()`. don't: how to do - `executor`
It's not so bad, but what if you need 2 futures:
val f1 = Future(1)(executor)
val f2 = Future(2)(executor) // You have to specify the same executor every time.
Implicit creates "context" for all actions:
implicit val d = executor // All `Future` in this scope will be created with this executor.
val f1 = Future(1)
val f2 = Future(2)
3.5) Implicit parameters allows type-level programming . See shapeless.
About "ambiguity of the code":
You don't have to use implicits, alternatively you can specify all parameters explicitly. It looks ugly sometimes (see sorted example), but you can do it.
If you can't find which implicit variables are used as parameters you can ask compiler:
>echo object Test { List( (1, "a") ).sorted } > test.scala
>scalac -Xprint:typer test.scala
You'll find math.this.Ordering.Tuple2[Int, java.lang.String](math.this.Ordering.Int, math.this.Ordering.String) in output.
In the code from Akka you linked, it is true that executor could be just passed explicitly. But if there was more than one Future used throughout this method, declaring implicit parameter would definitely make sense to avoid passing it around many times.
So I would say that in the code you linked, implicit parameter was used just to follow some code style. It would be ugly to make an exception from it.
Your question intrigued me, so I searched a bit on the net. Here's what I found on this blog: http://daily-scala.blogspot.in/2010/04/implicit-parameters.html
What is an implicit parameter?
An implicit parameter is a parameter to method or constructor that is marked as implicit. This means that if a parameter value is not supplied then the compiler will search for an "implicit" value defined within scope (according to resolution rules.)
Why use an implicit parameter?
Implicit parameters are very nice for simplifying APIs. For example the collections use implicit parameters to supply CanBuildFrom objects for many of the collection methods. This is because normally the user does not need to be concerned with those parameters. Another example is supplying an encoding to an IO library so the encoding is defined once (perhaps in a package object) and all methods can use the same encoding without having to define it for every method call.
I've searched for a half-hour, and still cannot figure it out.
In SIP: Modularizing Language Features there are a number of features which will require explicit "enabling" in Scala 2.10 (import language.feature).
Amongst them there is postfixOps, to which I just cannot find a reference anywhere. What exactly does this feature allow?
It allows you to use operator syntax in postfix position. For example
List(1,2,3) tail
rather than
List(1,2,3).tail
In this harmless example it is not a problem, but it can lead to ambiguities. This will not compile:
val appender:List[Int] => List[Int] = List(1,2,3) ::: //add ; here
List(3,4,5).foreach {println}
And the error message is not very helpful:
value ::: is not a member of Unit
It tries to call the ::: method on the result of the foreach call, which is of type Unit. This is likely not what the programmer intended. To get the correct result, you need to insert a semicolon after the first line.
The simplest answer ever:
Dropping dot from methods without parameters is DEPRECATED!
List(1,2,3) reverse //is bad style and will lead to unpredicted behaviour
List(1,2,3) map(_*2) reverse //bad too, because reverse can take first method call from the next line (details below)
OK to drop dot in methods that take one parameter of higher order function like map, filter, count and be safe!
Also, purely functional methods like zip.
List(1,2,3) map(_*2) filter(_>2)
(List(1,2,3) map(_*2)).reverse //safe and good
List(1,3,5) zip List(2,4,6)
Long answer WHY
case class MyBool(x: Boolean) {
def !!! = MyBool(!x) //postfix
def or(other: MyBool): MyBool = if(x) other else this //infix
def justMethod0() = this //method with empty parameters
def justMethod2(a: MyBool, b: MyBool) = this //method with two or more
override def toString = if(x) "true" else "false"
}
1) Postfix operator - is actually a method call with no parameters (a!==a.!) and without brackets. (considered not safe and deprecated)
val b1 = MyBool(false) !!!
List(1,2,3) head
2) Postfix operator is method, that should end the line, or else it will be treated as infix.
val b1 = MyBool(true) no! no! //ERROR
//is actually parsed like
val b2 = MyBool(true).no!(no!) //(no!) is unknown identifier
//as bad as
Vector(1,2,3) toList map(_*2) //ERROR
3) Infix operator is method with one parameter, that can be called without dot and parentheses. Only for purely functional methods
val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2
4) Method with one or more parameters will chain without dot if you call it with parameters. def a(), def a(x), def a(x,y)
But you should do this only for methods that use higher order function as parameter!
val d1 = MyBool(true) justMethod2(b1, c1) or b1 justMethod0() justMethod2(c1, b1)
//yes, it works, but it may be confusing idea
val d2 = MyBool(true).justMethod2(b1,c1).or(b1).justMethod0().justMethod2(c1, b1)
d1 == d2
//looks familiar? This is where it should be used:
List(1,2,3) filter(_>1) map(_*2)
Sample warnings:
warning: there were 1 deprecation warning(s); re-run with -deprecation
for details warning: postfix operator tail should be enabled by making
the implicit value scala.language.postfixOps visible. This can be
achieved by adding the import clause 'import
scala.language.postfixOps' or by setting the compiler option
-language:postfixOps. See the Scala docs for value scala.language.postfixOps for a discussion why the feature should be
explicitly enabled.
It refers to the ability to call a nullary (with no arg list or empty arg list) method as a postfix operator:
By example:
case class MyBool(value: Boolean) {
def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated
See: http://www.scala-lang.org/node/118
Am I right understanding that
def is evaluated every time it gets accessed
lazy val is evaluated once it gets accessed
val is evaluated once it gets into the execution scope?
Yes, but there is one nice trick: if you have lazy value, and during first time evaluation it will get an exception, next time you'll try to access it will try to re-evaluate itself.
Here is example:
scala> import io.Source
import io.Source
scala> class Test {
| lazy val foo = Source.fromFile("./bar.txt").getLines
| }
defined class Test
scala> val baz = new Test
baz: Test = Test#ea5d87
//right now there is no bar.txt
scala> baz.foo
java.io.FileNotFoundException: ./bar.txt (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:137)
...
// now I've created empty file named bar.txt
// class instance is the same
scala> baz.foo
res2: Iterator[String] = empty iterator
Yes, though for the 3rd one I would say "when that statement is executed", because, for example:
def foo() {
new {
val a: Any = sys.error("b is " + b)
val b: Any = sys.error("a is " + a)
}
}
This gives "b is null". b is never evaluated and its error is never thrown. But it is in scope as soon as control enters the block.
I would like to explain the differences through the example that i executed in REPL.I believe this simple example is easier to grasp and explains the conceptual differences.
Here,I am creating a val result1, a lazy val result2 and a def result3 each of which has a type String.
A). val
scala> val result1 = {println("hello val"); "returns val"}
hello val
result1: String = returns val
Here, println is executed because the value of result1 has been computed here. So, now result1 will always refer to its value i.e "returns val".
scala> result1
res0: String = returns val
So, now, you can see that result1 now refers to its value. Note that, the println statement is not executed here because the value for result1 has already been computed when it was executed for the first time. So, now onwards, result1 will always return the same value and println statement will never be executed again because the computation for getting the value of result1 has already been performed.
B). lazy val
scala> lazy val result2 = {println("hello lazy val"); "returns lazy val"}
result2: String = <lazy>
As we can see here, the println statement is not executed here and neither the value has been computed. This is the nature of lazyness.
Now, when i refer to the result2 for the first time, println statement will be executed and value will be computed and assigned.
scala> result2
hello lazy val
res1: String = returns lazy val
Now, when i refer to result2 again, this time around, we will only see the value it holds and the println statement wont be executed. From now on, result2 will simply behave like a val and return its cached value all the time.
scala> result2
res2: String = returns lazy val
C). def
In case of def, the result will have to be computed everytime result3 is called. This is also the main reason that we define methods as def in scala because methods has to compute and return a value everytime it is called inside the program.
scala> def result3 = {println("hello def"); "returns def"}
result3: String
scala> result3
hello def
res3: String = returns def
scala> result3
hello def
res4: String = returns def
One good reason for choosing def over val, especially in abstract classes (or in traits that are used to mimic Java's interfaces), is, that you can override a def with a val in subclasses, but not the other way round.
Regarding lazy, there are two things I can see that one should have in mind. The first is that lazy introduces some runtime overhead, but I guess that you would need to benchmark your specific situation to find out whether this actually has a significant impact on the runtime performance. The other problem with lazy is that it possibly delays raising an exception, which might make it harder to reason about your program, because the exception is not thrown upfront but only on first use.
You are correct. For evidence from the specification:
From "3.3.1 Method Types" (for def):
Parameterless methods name expressions that are re-evaluated each time
the parameterless method name is referenced.
From "4.1 Value Declarations and Definitions":
A value definition val x : T = e defines x as a name of the value that results from
the evaluation of e.
A lazy value definition evaluates its right hand side e the first
time the value is accessed.
def defines a method. When you call the method, the method ofcourse runs.
val defines a value (an immutable variable). The assignment expression is evaluated when the value is initialized.
lazy val defines a value with delayed initialization. It will be initialized when it's first used, so the assignment expression will be evaluated then.
A name qualified by def is evaluated by replacing the name and its RHS expression every time the name appears in the program. Therefore, this replacement will be executed every where the name appears in your program.
A name qualified by val is evaluated immediately when control reaches its RHS expression. Therefore, every time the name appears in the expression, it will be seen as the value of this evaluation.
A name qualified by lazy val follows the same policy as that of val qualification with an exception that its RHS will be evaluated only when the control hits the point where the name is used for the first time
Should point out a potential pitfall in regard to usage of val when working with values not known until runtime.
Take, for example, request: HttpServletRequest
If you were to say:
val foo = request accepts "foo"
You would get a null pointer exception as at the point of initialization of the val, request has no foo (would only be know at runtime).
So, depending on the expense of access/calculation, def or lazy val are then appropriate choices for runtime-determined values; that, or a val that is itself an anonymous function which retrieves runtime data (although the latter seems a bit more edge case)