Reputation: 58
I know basic difference between defining functions in scala using def/val: if I use val, my function is defined once, as
scala> val valRandom = Random.nextInt
valRandom: Int = 2032538454
scala> valRandom
res0: Int = 2032538454
But my question is why Random.nextInt is calculated every time I use function like:
scala> val valRandom2 = (_:Int) + Random.nextInt
valRandom2: Int => Int = $$Lambda$1100/1597979904@1a6dc5ea
scala> valRandom2(0)
res2: Int = 486047489
scala> valRandom2(0)
res3: Int = 1573520480
Upvotes: 0
Views: 148
Reputation: 36229
My repl responses:
scala> val valRandom2 = (_:Int) + Random.nextInt
valRandom2: Int => Int = <function1>
so valRandom2 is something, which takes an Int and returns an Int, and is of type function1. For example:
scala> val valRandom3 = (_:Int) + (_:Int) + Random.nextInt
valRandom3: (Int, Int) => Int = <function2>
This is of type function2.
The numbers (1, 2) indicate, how many parameters are passed into it. A function always returns one value, so that doesn't matter. Even if there is no return, because it is a procedure, probably called for a side effect, it implicitly returns Unit (). If it returns a List of something or a tuple, that is just one thing, which you have to break apart, to get to one of the multiple values.
A function isn't identic with a method. Function can be passed around and execution is delayed, while methods are invoked directly, but it's easy to pass a method as a function.
scala> def add (a: Int, b:Int) : Int = a + b
add: (a: Int, b: Int)Int
scala> def mul (a: Int, b:Int) : Int = a * b
mul: (a: Int, b: Int)Int
scala> def printIt (a: Int, b:Int, f:(Int, Int) => Int) = {
| val c = f (b, a)
| println (s"b $b (X) a $a = c $c")
| }
printIt: (a: Int, b: Int, f: (Int, Int) => Int)Unit
scala> printIt (3, 4, add)
b 4 (X) a 3 = c 7
scala> printIt (3, 4, mul)
b 4 (X) a 3 = c 12
This example, while simple to understand, doesn't explain why it is useful, but useful examples are more complex to setup. But imagine a List which can sort numerical values. If you have a List of Employees, you can sort them by handing a function to the List, to get a Numeric out of an Employee, be it Employee.id, *.age, *.maxSalary (), .address.zipCode or whatever, which gives you maximal flexibility.
To the comment:
scala> val valRandom2 = {println ("vR2 called"); (_:Int) + Random.nextInt}
vR2 called
valRandom2: Int => Int = <function1>
scala> val x = valRandom2 (0)
x: Int = -1231081
scala> val x = valRandom2 (0)
x: Int = 1421497830
Why is the print performed on declaration, but the nextInt on usage?
Because
scala> val valRandom2 = {println ("vR2 called"); (_:Int) + Random.nextInt}
vR2 called
valRandom2: Int => Int = <function1>
scala> val valRandom2 = {println ("vR2 called"); (_:Int) + Random.nextInt}
vR2 called
valRandom2: Int => Int = <function1>
scala> val x = valRandom2
x: Int => Int = <function1>
The result of the rhs is the function, which gets assigned to valRandom2 or x while the print was a side effect on declaration. The block returned, as its last expression, the function.
Swap the inner calls on valRandom2 and you get nothing (Unit).
Add the parameter Int to the second call:
scala> val valRandom3 = {Random.nextInt; (_:Int) => println ("vR2 called") }
valRandom3: Int => Unit = <function1>
scala> valRandom3 (0)
vR2 called
scala> valRandom3 (0)
vR2 called
Upvotes: 0
Reputation: 27356
In valRandom2 the random offset is computed inside the function body, so it is computed every time the function is called.
You need to compute the random offset outside the function, like this:
val valRandom3 = { val rand = Random.nextInt; (_:Int) + rand }
Upvotes: 0
Reputation: 3250
In your first approach,
scala> val valRandom = Random.nextInt
valRandom: Int = 2032538454
If you notice the type of valRandom
is int
. Basically, you have initialized valRandom using Random.nextInt
.
But, in the second approach,
scala> val valRandom2 = (_:Int) + Random.nextInt
valRandom2: Int => Int = $$Lambda$1100/1597979904@1a6dc5ea
You notice the type of valRandom2
is mapping from Int -> Int
valRandom2 is a function value, which is nothing but an anonymous function or a lambda expression.
So, it will always generate new value whenever you make a call to it.
The difference in both approaches is that first approach is creating a variable and assigning it random value. But in the second approach, you are calling anonymous function so it will evaluate every time
Upvotes: 2