Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala Map.getOrElse - how to provide function for default

Tags:

scala

Odd...

    val h = new HashMap[Long, Int]()

    def mydefault0():Int = 101
    println( h.getOrElse(99, default=mydefault0 _ ) )  // Prints <function0>

    def mydefault1(key:Long):Int = 102
    println( h.getOrElse(98, default=mydefault1 _ ) )  // Prints <function1>

The docs say that default must be of type: => B

If I understand correctly, a no-arg function returning an Int, in this case.

  1. Why does the example taking mydefault1 compile, as it takes an argument and so does meet the specification?

  2. Why are functions returned, instead of functions being called to yield a default value? Apparently the typesafety has been broken because the getOrElse must return an Int, not a function. (if I misunderstood the docs and incorrectly provided a function where an Int value was required, why did the compiler let me provide a function, instead of an Int?).

edit

Clearly:

  • extends HashMap and overriding default, or
  • using HashMap.withDefault

also let a function by used to specify a default value. What I'd like is to be able to override the default with a function that's provided at the point of performing the lookup (i.e. the function may change during the life of the Map)

Is this possible?

like image 780
user48956 Avatar asked Dec 23 '13 21:12

user48956


People also ask

How does getOrElse work in Scala?

As we know getOrElse method is the member function of Option class in scala. This method is used to return an optional value. This option can contain two objects first is Some and another one is None in scala. Some class represent some value and None is represent a not defined value.

How do you add a value to a map in Scala?

Add Elements to a Map Using the Assignment Operator in Scala We need to pass the key into the constructor and assign a value using the assignment operator. We can also use the += operator to avoid using a constructor and directly add the element to the Map.

How do you access map elements in Scala?

Scala Map get() method with exampleThe get() method is utilized to give the value associated with the keys of the map. The values are returned here as an Option i.e, either in form of Some or None. Return Type: It returns the keys corresponding to the values given in the method as argument.


1 Answers

The definition of getOrElse:

getOrElse[B1 >: B](key: A, default: => B1): B1

The default argument does not take a function—which would be () => B1, but a lazily accessed value of type B1. This parameterless "function" => B1 is also sometimes called thunk. The correct way to use it is as follows:

import collection.mutable

val h = new mutable.HashMap[Long, Int]()

def mydefault0(): Int = 101

println(h.getOrElse(99, default = mydefault0()))

So what is it that you are seeing with mydefault0 _? Clearly, the returned value has type B1 which must be a common supertype of the map's value type Int and the default value's type. The default value's type is Function0. If you assign the result, you see that the supertype is Any:

val x = h.getOrElse(99, default = mydefault0 _ )  // x: Any = <function0>

So the mistake is to assume that you must pass in a function, when actually you are stating an expression which is lazily evaluated. The call mydefault0() will only be invoked when the default value is needed. Formally, the argument is defined as a call-by-name argument.


Edit: Regarding your comment. Call-by-name means that you do get a new array each time.

val m = Map("foo" -> Array(1, 2, 3))

def myDefault = {
  println("called-default")
  Array(4, 5, 6)
}

val a1 = m.getOrElse("foo", myDefault)  // myDefault not called
val a2 = m.getOrElse("bar", myDefault)  // myDefault called
val a3 = m.getOrElse("baz", myDefault)  // myDefault called
a2 == a3  // false!!
like image 151
0__ Avatar answered Nov 11 '22 12:11

0__