Cache#asMap has different behavior from MapMaker#makeComputingMap

82 views
Skip to first unread message

JasonQR

unread,
Mar 6, 2012, 4:01:45 AM3/6/12
to guava-discuss
In cleaning up some compiler warnings, my team discovered that
Cache#asMap is not a drop-in replacement for
MapMaker#makeComputingMap. Specifically, calling get() on a computing
map loads the desired value, whereas the same method called on the Map
returned from Cache#asMap will only return a value if already loaded.

It's pretty trivial for us to implement a "loading map" view of the
Cache, i.e., a Map whose #get() method calls Cache#get(), but I wanted
to first ask whether this is something that might be included in Guava
in the future, or if there's another way to do this that I missed.

My reason for not wanting to just use Cache in place of Map is that it
would change our interfaces and expose implementation details to our
callers.

Cheers,
--J.

Charles Fry

unread,
Mar 6, 2012, 10:10:08 AM3/6/12
to JasonQR, guava-discuss
In fact, one of the big motivating factors for creating the Cache interface in the first place was to get rid of a magic Map.get that auto-loaded values. So no, we won't be adding that back to the asMap view, which was very intentionally just a view of the cached content.

Charles

Jason Roselander

unread,
Mar 6, 2012, 11:48:53 AM3/6/12
to Charles Fry, guava-discuss
Right. I understand there are times when auto-loading is not what you
want. That doesn't necessarily mean there are no times when you do
want it, or that the previous calling pattern can't be preserved in a
new class or API.

Colin Decker

unread,
Mar 6, 2012, 11:57:05 AM3/6/12
to Jason Roselander, Charles Fry, guava-discuss
The previous calling pattern is preserved in a new API: the LoadingCache API. It just doesn't implement the Map interface for the reasons Charles described: a Map's get() method shouldn't cause a value to be loaded into it, it should only return the value if the map already contains it.

-- 
Colin

Kevin Bourrillion

unread,
Mar 6, 2012, 11:58:38 AM3/6/12
to Jason Roselander, Charles Fry, guava-discuss
Having a Map that auto-creates entries on get() was simply a big mistake. It breaks type-safety (you can use it to store a key in the map that isn't of the map's key type!).  Bad things will happen if that Map accidentally gets passed to another Map's equals() method.  Common idioms for Map usage (in the absence of null values) are based on the assumption of interchangeability of containsKey(k) and (get(k) != null), and those coding patterns will break.  Etc.

We studied this issue very closely, and have concluded that our library will be easier to use when collections are just collections, iterators are just iterators, and things that are fancier than those have public types that convey their behavior sufficiently.  My personal opinion is that your library will also be better off if you stop exposing Maps that don't act like Maps, but it's your right to do that if you want (Guava simply isn't going to help you do it anymore).

I am sorry that our fixing this mistake has caused you trouble! But I still feel we had to fix it.

--
Kevin Bourrillion @ Google
Java Core Libraries Team
http://guava-libraries.googlecode.com

Jason Roselander

unread,
Mar 7, 2012, 4:23:48 AM3/7/12
to Kevin Bourrillion, Charles Fry, guava-discuss
I had previously thought that the computingMap could auto-load while
still obeying the contract of a Map, but obviously that's not the
case. Thanks Kevin for the detailed response.
Reply all
Reply to author
Forward
0 new messages