Re:Map.merge() – One method to rule them all
by browda on Sunday March 31, 2019 @01:17PM
(#19536776)
Yes, the final example code reads reasonably nicely, but alas -- unless ConcurrentHashMap.merge() has been rewritten since Java 8 time -- it is definitely not as performant as the author appears to think it is since the actions will be contained in a fairly long synchronized block. This is not to say the code is bad, but you can't get around that.
Somewhat surprisingly, the code the author pooh-poohs is actually more performant (although it's better if the test is for the presence of the key rather than the "putIfPresent/computeIfAbsent combination) because the JVM will properly optimize a membership test (in keyset) and the use of a ternary expression makes the action clear.
Re:Map.merge() – One method to rule them all
by rienbdj on Sunday March 31, 2019 @10:20AM
(#19535693)
Anyone else disappointed by the Java implementation of these ideas? It feels less ergonomic than previous solutions and came considerably later. That said, it is better than nothing.
Re:Map.merge() – One method to rule them all
by vbsteven on Sunday March 31, 2019 @11:19AM
(#19536013)
The streams api is a little verbose but this is mainly because of Java’s backwards compatibility policy. They want older code to still compile and run on new JDKs.
Default methods on interfaces help to add features to existing collections but they are limited in what they can do, hence streams.
If you really want more ergonomic collections while staying close to Java then use Kotlin which can be easily added to most Java code bases and has all the modern functional methods like map/reduce/filter/group on standard collections.
Re:Map.merge() – One method to rule them all
by _old_dude_ on Sunday March 31, 2019 @03:32PM
(#19537779)
It's also to separate the methods doing computation lazily (Stream) from the one doing computation eagerly (Collection).
Otherwise a simple call like isEmpty() can trigger the whole computation like in Haskell.
As a user of the API, you have to wrap your code into a Stream to be lazy evaluated, the Stream being a computation monad, so you always know if a code is evaluated eagerly or lazily.
Re:Map.merge() – One method to rule them all
by vbsteven on Sunday March 31, 2019 @12:03PM
(#19536282)
I know these functional concepts are far from new.
I use "modern" in this context because other contemporary languages like Python/Ruby/Scala/Rust etc all have versions of those and FP-style collection usage using these names has become popular in the last 10 years.
Re:Map.merge() – One method to rule them all
by meddlepal on Sunday March 31, 2019 @11:41AM
(#19536125)
Yea I meant lock free and ready for multi-threaded use without a GIL. I didn't mean to dump on Python either, I write a lot of Python and Java but comparisons like yours aren't really fair because the JVM is just considerably more powerful than Python's runtime. I could take a huge list of words, hand subsets to threads and let them all update the same map using the same API and without needing a lock.
Re:Map.merge() – One method to rule them all
by detaro on Sunday March 31, 2019 @10:42AM
(#19535830)
dict.get() does the same in Python (optional second parameter for a default value). But I've wondered too why there isn't a form of the default dict that can take parameters like the key for the factory function.
Re:Map.merge() – One method to rule them all
by kazinator on Sunday March 31, 2019 @11:59AM
(#19536252)
This is a poor semantics. The function should always be called. In the non-existent-key case, it should be invoked on the default value that is supplied. Thus the example of the histogram tabulation would use 0 as the initial value.
The name is ill-chosen; this mutator doesn't "merge" at all; it "updates" the map entry through a function, with a default value.
"merge" might be a somewhat good name for an operation that combines two maps, with a function that resolves key clashes; though since that is a kind of set union, that provides better terminology.
Re:Map.merge() – One method to rule them all
by vojtisek on Sunday March 31, 2019 @12:20PM
(#19536373)
I like how the more mathematical concepts get their way to the mainstream languages. It's making concepts such as monoids and semigroups more accessible to general public.
Re:Map.merge() – One method to rule them all
by twic on Sunday March 31, 2019 @11:25AM
(#19536046)
The one thing that frustrates me about merge is that it returns the value inserted, rather than the value being replaced (as Map::put does).
There are good uses cases for what it does - but there are also good use cases for returning the previous value, and when i have one of those, i can't use merge, and have to fall back to a get followed by a put.
Perhaps what i would really like is a Rust-style entry API, where i could use a key to obtain a Map.Entry, which i could then inspect and mutate how i liked. It might look like:
Re:Map.merge() – One method to rule them all
by stingraycharles on Sunday March 31, 2019 @09:44AM
(#19535549)
This is a toxic attitude as this can be said about pretty much any language / thing, "lol Ruby developers discovering what LISP developers have been doing since the 80s", "lol LISP developers discovering lambda calculus", etc.
A better attitude would be to appreciate that these solid practices are being rediscovered everywhere, and focus on the good rather than the "us versus them". It's not productive.
Somewhat surprisingly, the code the author pooh-poohs is actually more performant (although it's better if the test is for the presence of the key rather than the "putIfPresent/computeIfAbsent combination) because the JVM will properly optimize a membership test (in keyset) and the use of a ternary expression makes the action clear.
There is also another variation, using map.getOrDefault()
and then at some points you discover the Stream APIDefault methods on interfaces help to add features to existing collections but they are limited in what they can do, hence streams.
If you really want more ergonomic collections while staying close to Java then use Kotlin which can be easily added to most Java code bases and has all the modern functional methods like map/reduce/filter/group on standard collections.
As a user of the API, you have to wrap your code into a Stream to be lazy evaluated, the Stream being a computation monad, so you always know if a code is evaluated eagerly or lazily.
"Modern". Lol.
I use "modern" in this context because other contemporary languages like Python/Ruby/Scala/Rust etc all have versions of those and FP-style collection usage using these names has become popular in the last 10 years.
And you can use Scala or Clojure with Java APIs/Libraries/Frameworks
https://www.scala-lang.org/ https://typelevel.org/cats/ http://dotty.epfl.ch/
https://clojure.org/ https://clojure.org/guides/spec https://github.com/clojure/spec-alpha2/wiki/Schema-and-selec...
edit: I should have foreseen the derailment caused by and nitpicking to follow a comment like this. Sorry folks!
import scala.collection.mutable.Map
> val map = Map.empty[String, Int]
> List("hi", "there", "hi").map { x =>
> map(x) = i
> }
The name is ill-chosen; this mutator doesn't "merge" at all; it "updates" the map entry through a function, with a default value.
"merge" might be a somewhat good name for an operation that combines two maps, with a function that resolves key clashes; though since that is a kind of set union, that provides better terminology.
There are good uses cases for what it does - but there are also good use cases for returning the previous value, and when i have one of those, i can't use merge, and have to fall back to a get followed by a put.
Perhaps what i would really like is a Rust-style entry API, where i could use a key to obtain a Map.Entry, which i could then inspect and mutate how i liked. It might look like:
And then i could write: To collect my prize potatoes into a map, and sell the rest. Still ugly, but hey, at least it's not Go.A better attitude would be to appreciate that these solid practices are being rediscovered everywhere, and focus on the good rather than the "us versus them". It's not productive.
The best languages borrow from each other.