Re: [guava] why does CacheBuilder.newBuilder() return CacheBuilder<Object,Object> instead of CacheBuilder<K,V>?

486 views
Skip to first unread message

Louis Wasserman

unread,
Nov 9, 2012, 1:20:35 PM11/9/12
to Ron Reynolds, guava-...@googlegroups.com
IIRC, in practice, the result of CacheBuilder<Object, Object> newBuilder() is that you don't have to specify the type arguments at all in most cases -- Java manages to figure it all out by itself.


i know folks are in the habit of chaining Builder invocations without ever storing the ref to the builder (so build() does the type binding).  i notice that build() is <K1 extends K, V1 extends V> Cache<K1,V1> so you can create a Cache<DerivedKey,DerivedValue> from a CacheBuilder<Key,Value> - isn't it more typical to create a Builder of the specific Derived* types?

The current design of CacheBuilder makes it so K and V are typically Object and Object, so, nope!

Louis Wasserman

unread,
Nov 9, 2012, 1:30:03 PM11/9/12
to Ron Reynolds, guava-...@googlegroups.com
To put it another way: Java's automatic type inference works well at the end of a chain of operations, but not nearly as well at the beginning.

So the current of organization of CacheBuilder defers the decision of what type of Cache you want to build for as long as possible -- either build(), or build(CacheLoader<K, V>).

The only reason CacheBuilder has to have generics at all is because of e.g. removalListener(RemovalListener<K, V>) and weigher(Weigher<K, V>), which return CacheBuilder<K, V> with the narrowed <K, V>, which makes sense, I hope?
--
Louis Wasserman

Kevin Bourrillion

unread,
Nov 9, 2012, 2:16:25 PM11/9/12
to Ron Reynolds, guava-...@googlegroups.com
It's natural to expect that the meaning of CacheBuilder's K and V should be the same as the meaning of Cache's K and V themselves.  But it isn't; they track "what are the most general types this cache builder is capable of creating caches for?"  Until you supply a removalListener, there's nothing preventing you from creating caches of any type under the sun, so the type is CacheBuilder<Object, Object>.


On Fri, Nov 9, 2012 at 9:36 AM, Ron Reynolds <tequi...@gmail.com> wrote:
wondering what i'm missing since i would expect this:
public static <K,V> CacheBuilder<K,V> newBuilder() { return new CacheBuilder<K,V>(); }

to be easier to use than something like this:
@SuppressWarnings("unchecked")
private static <K,V> CacheBuilder<K,V> newCacheBuilder() { return (CacheBuilder<K,V>)CacheBuilder.newBuilder(); }

i know folks are in the habit of chaining Builder invocations without ever storing the ref to the builder (so build() does the type binding).  i notice that build() is <K1 extends K, V1 extends V> Cache<K1,V1> so you can create a Cache<DerivedKey,DerivedValue> from a CacheBuilder<Key,Value> - isn't it more typical to create a Builder of the specific Derived* types?



--
Kevin Bourrillion | Java Librarian | Google, Inc. | kev...@google.com

Chris Povirk

unread,
Nov 9, 2012, 2:22:39 PM11/9/12
to Kevin Bourrillion, Ron Reynolds, guava-...@googlegroups.com
From an earlier internal discussion:

"Would it be any less confusing if K and V were the names of the
generic parameters on build() itself only, and the parameters on
CacheBuilder had to have slightly different, surprising-looking names
like <K0, V0> (which somehow in my mind alludes to "the base K" and
"the base V" more than other things I've thought of)? These might
drive the user to read and understand why they're named that way?"

(For the person who started the discussion, the answer was "no," so we
didn't explore further.)
Reply all
Reply to author
Forward
0 new messages