I know this has been discussed on SO in other posts before and I understand the basic difference between the use of def and val. def is used for defining a method and val for an immutable reference. What I am trying to accomplish by asking this question is to understand if there is something more to def. Can it be used interchangeably with a val?
Recently I tried the following code and cannot convince myself if my present understanding of def is sufficient:
scala> def i: Int = 3
i: Int
scala> i
res2: Int = 3
So I am curious, is this equivalent to val i = 3?
Then I tried this:
scala> i()
<console>:9: error: Int does not take parameters
i()
I did this just to test my understanding of the semantics of def. Now I want to know, when i is a method, why Scala complains with "...does not take parameters"?
Next I tried the following:
scala> def i(): Int = 3
i: ()Int
scala> i()
res4: Int = 3
This time Scala seems to agree that i is a method. So can I use def in place of val interchangeable to declare and initialize a variable?
Both
def i = 3
and
def i() = 3
declare methods. The only difference is, that the first one is a method without a parameter list and the second is a method with an empty parameter list. The former is usually used for methods without side effects and the latter for methods with side effects.
You should use a val instead of a def if the value never changes and you want to avoid recomputing it. A def gets recomputed every time it is called, while a val is assigned a value only once.
def defines a method, val defines an immutable value, as you already know.
One major difference is in when the expression on the right side of the = is evaluated. For a method, it is evaluated each time you call the method. For a value, it is evaluated when you initialize the value. See the difference:
scala> def i: Int = { println("Hello"); 3 }
i: Int
scala> i
Hello
res0: Int = 3
scala> i
Hello
res1: Int = 3
scala> val i: Int = { println("Hello"); 3 }
Hello
i: Int = 3
scala> i
res2: Int = 3
Just to add on the top of the Kim's answer, you can override def by val.
// Entering paste mode (Ctrl+D to finish)
trait A {
def i: Int
def num: Long
}
class B extends A {
val i = 7
val num = 20L
}
// Exiting paste mode, now interpreting.
defined trait A
defined class B
scala> val b = new B
b: B = B#2d62bdd8
scala> b.i
res1: Int = 7
scala> b.num
res2: Long = 20
Related
I'd like to define a function that applies * 2 to its argument, that works for all types where it's meaningful. I tried using structural types:
import scala.language.reflectiveCalls
def double[T](x: Any{def * (arg0: Int): T}) = x * 2
It works for strings:
scala> double("a")
res85: String = aa
But not for numbers:
scala> double(4)
java.lang.NoSuchMethodException: java.lang.Integer.$times(int)
at java.lang.Class.getMethod(Class.java:1778)
at .reflMethod$Method1(<console>:18)
at .double(<console>:18)
... 32 elided
Why do I get this error message?
Is it possible to do what I want using structural types?
Is it possible to do it in some other way?
Edit: By "do what I want" I mean working for already existing types, such as numbers and strings, not just for classes that I define myself.
* is translated to $times, structural type checks existence of * method, but (I suppose that's a bug) calls it's internal ($times) representations). That works for String, because there is $times for them.
This approach should work for methods with names that only contain letters.
```
import scala.language.reflectiveCalls
def double[T](x: Any{def test (arg0: Int): T}) = x.test(2)
class A { def test(i: Int) = i * 10 }
class B { def test(i: Int) = i * 20 }
scala> double(new A)
res0: Int = 20
scala> double(new B)
res1: Int = 40
Yes, idiomatic answer is typeclasses. You choose what exactly "meaningfulness" is. And they can be applied to any already existing class:
```
trait Multiply[A]{
def times(a: A, x: Int): A
}
implicit val MultString = new Multiply[String] { def times(a: String, x: Int) = a * x }
implicit val MultInt = new Multiply[Int] { def times(a: Int, x: Int) = a * x }
def double[T](t: T)(implicit mult: Multiply[T]) = mult.times(t, 2)
scala> double("aaaa")
res0: String = aaaaaaaa
scala> double(111)
res1: Int = 222
Also note that structural typing uses reflection => is quite slow.
You could always just overload the method. To make it work in the REPL you have to :paste it in as a block.
def double(s:String):String = s * 2
def double[N](n:N)(implicit ev: Numeric[N]):N = {
import Numeric.Implicits._
n * ev.fromInt(2)
}
double("this") // result: String = thisthis
double(3L) // result: Long = 6
One more possibility I've found is to use macros. As of Scala 2.11.8 they are still experimental and, according to Martin Odersky, won't survive in this form. The current synax is clumsy, but so far it is the only method that is completely DRY (* 2 is written only once, and the function works on all types that support this operation).
Regardless of whether this is the best solution, I'm posting it for the sake of completeness:
import reflect.macros.Context
def doubleImpl[T](c: Context)(x: c.Expr[T]): c.Expr[T] = {
import c.universe._
c.Expr(q"${x.tree} * 2")
}
def double[T](x: T): T = macro doubleImpl[T]
By assigning a variable (or value?) a method name with a space and an underscore, you tell scala to treat the method as a function, which apparently means doing more than simply taking the value generated by a call to the method and assigning to the variable. What else is/can go on through such an assignment?
Since Scala runs on the JVM, it's easier to understand in terms of simple Java-like classes without Scala's syntactic sugar.
Remember that Scala functions are essentially members of a class similar to the following (signature deliberately simplified):
class Function[X, Y] {
def apply(x: X): Y
}
Application of a function f to an argument x is desugared into a method application f.apply(x).
Now suppose that you have another class Foo with method bar:
class Foo {
def bar(x: Int): String
}
If you now have an instance foo of type Foo, then whenever its method bar is transformed into a function by writing:
val f = foo.bar(_)
a new instance of an anonymous subclass of Function is created:
val f = new Function[Int, String] {
def apply(x: Int) = foo.bar(x)
}
If you use this syntax inside a class, this is closed over instead of an instance foo.
This is what all those weirdly named classes Main$$anon$1$$anonfun$1 are: they are the anonymous classes that represent functions. The functions can appear quite implicitly (for example, as blocks passed to the for-loops).
That's all there is to it semantically. The rest is just syntactic sugar.
Here is a complete runnable example that demonstrates the conversion of an instance method into a function:
with sugar, from the outside (a)
with sugar, from the inside (b)
without sugar, from the outside (c)
without sugar, from the inside (d)
You can save it into a file and execute with scala <filename.scala>:
/** A simple greeter that prints 'hello name' multiple times */
case class Hey(name: String) { thisHeyInst =>
def hello(x: Int): String = ("hello " + name + " ") * x
def withSugarFromInside = hello(_)
def noSugarFromInside = new Function[Int, String] {
def apply(y: Int) = thisHeyInst.hello(y)
}
}
val heyAlice = Hey("Alice")
val heyBob = Hey("Bob")
val heyCharlie = Hey("Charlie")
val heyDonald = Hey("Donald")
val a = heyAlice.hello(_)
val b = heyBob.withSugarFromInside
val c = new Function[Int, String] { def apply(y: Int) = heyCharlie.hello(y) }
val d = heyDonald.noSugarFromInside
println(a(3))
println(b(3))
println(c(3))
println(d(3))
In all four cases, a greeting is printed three times.
What _ actually does is an eta-conversion. It takes compile-time construction called method and returns runtime construction called anonymous function, which is actually an instance of scala's Function. Exactly the class depends on arity, so it might be Function1, Function2, Function3 and so on. The point here is to make First-class citizen, which may act like a value.
OOP needs a little more than some new object. Before making the code that creates instance, compiler generates a new class (extending FunctionN) in compile-time, but theoretically it shouldn't be necessary a whole new class. For Java 8 it could be native Java-lambdas.
Btw, you may extend Function1 by yourself and even eta-abstract it again:
scala> object f extends (Int => Int) { def apply(a: Int) = a }
scala> f(1)
res0: Int = 1
scala> f.apply _
res1: Int => Int = <function1>
scala> res1(5)
res2: Int = 5
As a conclusion a little copy-paste from #Daniel C. Sobral's answer:
the former can be easily converted into the latter:
val f = m _
Scala will expand that, assuming m type is (List[Int])AnyRef
into (Scala 2.7):
val f = new AnyRef with Function1[List[Int], AnyRef] {
def apply(x$1: List[Int]) = this.m(x$1)
}
On Scala 2.8, it actually uses an AbstractFunction1 class to reduce
class sizes.
Or simply saying val f = m _ is same as val f = (x: List[Int]) => m(x)
To make this answer more modern and precise let's see what's happening using scalac 2.11.2 and javap:
$ echo "object Z{def f(a: Int) = a}" > Z.scala //no eta-abstraction here
$ scalac Z.scala
$ ls
Z$.class Z.class Z.scala
$ echo "object Z{def f(a: Int) = a; val k = f _}" > Z.scala
$ scalac Z.scala
$ ls
Z$$anonfun$1.class Z.class //new anonfun class added for lambda
Z$.class Z.scala
$ javap -c Z\$\$anonfun\$1.class
Compiled from "Z.scala" // I've simplified output a bit
public final class Z$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp implements scala.Serializable {
public final int apply(int);
Code:
calling apply$mcII$sp(int)
public int apply$mcII$sp(int); //that's it
Code:
0: getstatic #25 // reading Field Z$.MODULE$:LZ$;, which points to `object Z`
3: iload_1
4: invokevirtual #28 // calling Method Z$.f
7: ireturn
public final java.lang.Object apply(java.lang.Object); //just boxed version of `apply`
Code:
unboxToInt
calling apply(int) method
boxToInteger
public Z$$anonfun$1();
Code:
AbstractFunction1$mcII$sp."<init>":()V //initialize
}
So it still extends AbstractFunction1
I'll try to provide some examples how a function or method are assigned to values with underscore.
If it's need to reference a zero-argument function
scala> val uuid = java.util.UUID.randomUUID _
uuid: () => java.util.UUID = <function0>
scala> uuid()
res15: java.util.UUID = 3057ef51-8407-44c8-a09e-e2f4396f566e
scala> uuid()
uuid: java.util.UUID = c1e934e4-e722-4279-8a86-004fed8b9090
Check how it's different when one does
scala> val uuid = java.util.UUID.randomUUID
uuid: java.util.UUID = 292708cb-14dc-4ace-a56b-4ed80d7ccfc7
In first case one assigned a reference to a function. And then calling uuid() generates new UUID every time.
In second, function randomUUID has been called and value assigned to a val uuid.
There are some other cases why _ might be useful.
It's possible to use a function with two arguments and create a function with a single argument out of it.
scala> def multiply(n: Int)(m: Int) = n*m
multiply: (n: Int)(m: Int)Int
scala> val by2 = multiply(2) _
by2: Int => Int = <function1>
scala> by2(3)
res16: Int = 6
To be able to do, it's crucial to define function multiply as curried. It's called function currying.
I've seen some blogs on the Pimp my Library pattern, and these seem to work well for adding behavior to classes.
But what if I have a case class and I want to add data members to it? As a case class I can't extend it (inheriting from a case class is deprecated/strongly discouraged). Will any of these pimp patterns allow me to add data to a case class?
No - I don't see how you could make this work because the enriched instance is usually thrown away (note: newly the pimp-my-library pattern is called enrich-my-library). For example:
scala> case class X(i: Int, s: String)
defined class X
scala> implicit class Y(x: X) {
| var f: Float = 0F
| }
defined class Y
scala> X(1, "a")
res17: X = X(1,a)
scala> res17.f = 5F
res17.f: Float = 0.0
scala> res17.f
res18: Float = 0.0
You would have to make sure you kept hold of the wrapped instance:
scala> res17: Y
res19: Y = Y#4c2d27de
scala> res19.f = 4
res19.f: Float = 4.0
scala> res19.f
res20: Float = 4.0
However, I find this not useful in practice. You have a wrapper; you're better off making this explicit
This is not the way to do. Just a proof of possibility. With this way you can get plenty of problems.
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class A(i: Int)
class B(a: A){
var s: String = ""
}
object B{
val as = scala.collection.mutable.WeakHashMap[A, B]()
}
implicit def a2b(a: A) = B.as.getOrElseUpdate(a, new B(a))
// Exiting paste mode, now interpreting.
defined class A
defined class B
defined module B
a2b: (a: A)B
scala> val a = A(1)
a: A = A(1)
scala> a.s = "test"
scala> a.s
res0: String = test
WeakHashMap: A hash map with references to entries which are weakly reachable. Entries are removed from this map when the key is no longer (strongly) referenced. This class wraps java.util.WeakHashMap.
Note that due to case class's overridden equals method you get this funny behavior:
scala> A(2).s = "test2"
scala> A(2).s
res2: String = test2
so you should not use case class or use it with override def equals(that: Any) = this eq that.asInstanceOf[AnyRef].
I've accidentally written this line of code:
scala> val f = Int
f: Int.type = object scala.Int
Seems to work for every subtype of AnyVal except for AnyVal itself.
Is there anything I can use f for or is it just an implementation detail of Scala leaking out?
The Int companion object is documented here. It doesn't provide a lot, but here are a couple things:
scala> val f = Int
f: Int.type = object scala.Int
scala> f.MaxValue
res1: Int = 2147483647
scala> f.box(2)
res2: java.lang.Integer = 2
Does anyone know if something like this is possible in Scala:
case class Thing(property:String)
def f(thing:Thing, prop:String = thing.property) = println(prop)
The above code doesn't compile; giving the error error: not found: value thing at thing.property
The following shows the expected behaviour:
f(Thing("abc"), "123") // prints "123"
f(Thing("abc")) // prints "abc"
I realise I could make the prop argument an Option[String] and do the check in the function definition, but I was wondering if there was a way around it with the new named/default argument support in 2.8.0.
Yes, it's possible in Scala 2.8. Here's a quote from the "Named and Default Arguments in Scala 2.8" design document:
Since the scope of a parameter extends
over all subsequent parameter lists
(and the method body), default
expressions can depend on parameters
of preceding parameter lists (but not
on other parameters in the same
parameter list). Note that when using
a default value which depends on
earlier parameters, the actual
arguments are used, not the default
arguments.
def f(a: Int = 0)(b: Int = a + 1) = b // OK
And another example:
def f[T](a: Int = 1)(b: T = a + 1)(c: T = b)
// generates:
// def f$default$1[T]: Int = 1
// def f$default$2[T](a: Int): Int = a + 1
// def f$default$3[T](a: Int)(b: T): T = b
According to this, your code may look as follows:
scala> case class Thing(property:String)
defined class Thing
scala> def f(thing:Thing)(prop:String = thing.property) = println(prop)
f: (thing: Thing)(prop: String)Unit
scala> f(Thing("abc"))("123")
123
scala> f(Thing("abc"))()
abc
Another simple solution is just to overload the method:
case class Thing (property: String)
def f(thing: Thing, prop: String) = println(prop)
def f(thing: Thing) = f(thing, thing.property)
This is exactly what Option is for. You can use the getOrElse method before the method call or inside the method f.
scala> val abc = Some("abc")
abc: Some[java.lang.String] = Some(abc)
scala> val none: Option[String] = None
none: Option[String] = None
scala> println(abc getOrElse "123")
abc
scala> println(none getOrElse "123")
123
scala> def f(o: Option[String]) = println(o getOrElse "123")
f: (o: Option[String])Unit
scala> f(abc)
abc
scala> f(none)
123
Oh here is something you could do via default arguments:
scala> case class Thing(property: String = "123")
defined class Thing
scala> def f(t: Thing) = println(t.property)
f: (t: Thing)Unit
scala> f(Thing("abc"))
abc
scala> f(Thing())
123
The expected behaviour can be achieved with simple overloading. I needed to put the method in an object because it looks like the REPL does not allow direct overloaded function declarations:
scala> object O {
def overloaded(t:Thing) = println(t.property)
def overloaded(t:Thing,s:String) = println(s)
}
defined module O
scala> O.overloaded(Thing("abc"), "123")
123
scala> O.overloaded(Thing("abc"))
abc