4

I'm pretty new to scala and basically I want to have a couple of functions coupled to a string in a hashmap. However I get an error at subscribers.get(e.key)(e.EventArgs); stating Option[EventArgs => Unit] does not take parameters... Example code:

object Monitor {
    val subscribers = HashMap.empty[String, (EventArgs) => Unit ]

    def trigger(e : Event){
      subscribers.get(e.key)(e.EventArgs);

    }

    def subscribe(key: String, e: (EventArgs) => Unit) {
      subscribers += key -> e;
    }

}
Seba Kerckhof
  • 1,294
  • 1
  • 14
  • 23

4 Answers4

5

The get method of a Map gives you an Option of the value, not the value. Thus, if the key if found in the map, you get Some(value), if not, you get None. So you need to first "unroll" that option to make sure there is actually a value of a function which you can invoke (call apply on):

def trigger(e: Event): Unit =
  subscribers.get(e.key).foreach(_.apply(e.EventArgs))

or

def trigger(e: Event): Unit =
  subscribers.get(e.key) match {
    case Some(value) => value(e.EventArgs)
    case None =>
  }

There are many posts around explaining Scala's Option type. For example this one or this one.

Also note Luigi's remark about using an immutable map (the default Map) with a var instead.

0__
  • 66,707
  • 21
  • 171
  • 266
3

Since the get method returns Option, you can use 'map' on that:

subscribers.get(e.key).map(f => f(e.EventArgs))

or even shorter:

subscribers.get(e.key) map (_(e.EventArgs))
Marimuthu Madasamy
  • 13,126
  • 4
  • 30
  • 52
1

get only takes one argument. So subscribers.get(e.key) returns an Option, and you're trying to feed (e.EventArgs) to that Option's apply method (which doesn't exist).

Also, try making the subscribers a var (or choosing a mutable collection type). At the moment you have an immutable collection and an immutable variable, so your map cannot change. A more idiomatic way to declare it would be

var subscribers = Map[String, EventArgs => Unit]()
Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180
0

HashMap.get() in Scala works in a bit different way, than in Java. Instead of returning value itself, get() returns Option. Option is a special type, that can have 2 values - Some(x) and None. In first case it tells "there's some value with such a key in a map". In second case it tells "nope, there's nothing (none) for this key in a map". This is done to force programmers check whether map actually has an object or not and avoid NullPointerException, which appears so frequently in Java code.

So you need something like this:

def trigger(e: Event) {
  val value = subscribers.get(e.key)
  value match {
    case None => throw new Exception("Oops, no such subscriber...")
    case Some(f) => f(e.EventArgs)
  }
}

You can find more info about Option type and pattern matching in Scala here.

ffriend
  • 27,562
  • 13
  • 91
  • 132
  • The link you gave is not very useful on it's own. Bub the link referenced in there actually is so let's give it credit here : http://blog.tmorris.net/scalaoption-cheat-sheet/ – AndreasScheinert Nov 16 '11 at 08:58
  • @AndreasScheinert: the link I provided is not just about `Option` class, but about safe programming overall and in particular about why they use it in HashMap. So nope, I don't think that your link is more useful _in this concrete case_ than the original. – ffriend Nov 16 '11 at 10:29
  • Useful to a very low degree IMO the author didn't ask how to use Option to stay away from null. He used a map and was surprised that he didn't 'get' what he was expecting. So 3 single statements seem important here: 1. You get Option wrapped values 2. You can get (but IMO you shouldn't 3. With map on Option you can use a 'ignore None' strategy . If then the OP still asked why Map . get values are wrapped the link could give an explanation. Plus I don't like the example because it puts null onside the map... – AndreasScheinert Nov 16 '11 at 12:10
  • @AndreasScheinert: Seba K was confused with an error. I explained why he gets it - pointer to `Option`. If I was new to Scala and saw such unusual behavior (`get` returning not the value, but some wrapper), my next question would be "what is this wrapper and why they put it there". You may agree or disagree with me, but 1) the question is answered; 2) answer is correct. All additional infos may be useful or useless for the author, but conditions of a good answer on SO rules are met. – ffriend Nov 16 '11 at 18:34