Hacker News new | ask | show | jobs
by kasey_junk 4501 days ago
An example I use a lot because it is terse:

From MapLike.scala def apply(key: A): B = get(key) match { case None => default(key) case Some(value) => value }

From HashMap.scala def get(key: A): Option[B] = { val e = findEntry(key) if (e eq null) None else Some(e.value) }

That is to say that the default behaviour of a Scala hash map is to create a new object for every access (notice I say access, not for every insert) even when I ask it to pretty please give me the one that doesn't have the null safe Option code involved.

2 comments

Doing an extra object allocation (which will likely be elided by escape analysis in the JVM) is hardly "weird and terrifying behaviour". It is an implementation detail which has absolutely no bearing on the behaviour or functionality of the map.
In my use cases escape analysis does not elide these accesses out (and I was unable to reason about why not). Further, I had an immutable map that had ~hundreds of items in it that was generating hundreds of millions of objects. I found that weird and terrifying especially given that I was specifically asking it not to give me Options back.

I frequently hear that memory/performance are "implementation" details and don't have bearing on functionality. For my use cases that isn't true.

Even if it was, the surprising upside down nature of that API (de reference the option, instead of wrap the reference) is of itself weird.

This is just the most terse example of oddities in the library I've encountered. Other's include streams being created (and not GC'd) when they weren't necessary, collections losing performance characteristics due to the monadic calls (IndexedSeq's passed into functions as Seq's use LinkedLists for builders instead of Vectors), etc.

Finally, I fundamentally disagree with the idea that eager evaluation should be the default in the collection library. Views mitigated this somewhat, but after working with more sane libraries, have to remember that every time is tedious (though I'll grant that is a debatable point).

If your software is not performance critical, or you aren't implementing your own collections libraries, maybe you don't encounter these problems. But for the standard library, it is a problem.

So to summarize the collections library has "weird and terrifying behaviour" because there are cases where the performance is not quite as good you expected?

You might be interested in the AnyRefMap work being done here: https://groups.google.com/forum/#!topic/scala-internals/R4fT... Perhaps you could add your voice to the discussion if you have concerns around performance.

Another way to summarize might be to say, "If you discount the many examples of incorrect behaviour that paulp mentions, and you don't care about performance, and you are comfortable enough looking through the extremely deep collections hierarchy code to diagnose the reasons for these problems, then the standard scala collections library is almost as good as collection libraries available in other languages".

The AnyRefMap may be a good solution to many of my issues with the default map implementation once it is widely available. It won't help with the more general lack of cohesion in the library though.

apply?
apply is the function called when you use brackets and nothing else e.g. val x = myMap("myKey")