Null value constraints in Immutable[Map|List]

6,000 views
Skip to first unread message

ryan...@gmail.com

unread,
Jun 24, 2008, 2:17:27 PM6/24/08
to Google Collections Library - users list
Can someone explain the rationale for imposing a not-null constraint
on the value of ImmutableMap and ImmutableList? I do note that
ImmutableMap never used to have this constraint, and a large volume of
my code cannot be upgraded to recent snapshots because of the
introduction of this constraint. I imagine the same is the case for
ImmutableList.

(I, too, have a hatred of nulls, but they are everywhere in idiomatic
Java; in my case as the returns from result sets...)

Is there a possibility that ImmutableMap could be made available with
this constraint as an option?

The only alternative for me is to copy-and-paste the ImmutableMap code
internally, which I am loathe to do.

kevin bourrillion

unread,
Jun 24, 2008, 2:26:41 PM6/24/08
to ryan...@gmail.com, Google Collections Library - users list
Hello Ryan,

Sometimes you want a map to be allowed null values, and sometimes you don't.  In the cases where you do, we'd recommend just continuing to use Collections.unmodifiableMap(), or you can make a simple wrapper for ImmutableMap that masks/unmasks nulls.  Or use AtomicReference or a similar NullableReference class as the value in the map.

In the cases where you don't, you're better served by an ImmutableMap that rejects nulls.  This map can perform better, and lets your code fail fast instead of having NPE's discovered far from where the error really happened.  And you don't have to clutter your code with precondition checks that look for nulls in the map -- you just ImmutableMap.copyOf(map) and that's it.

We have found the latter case to be much more prevalent in well-designed code, so we tailored the library to that case.
--
Kevin Bourrillion @ Google
internal: go/javalibraries
google-collections.googlecode.com
google-guice.googlecode.com

ryan...@gmail.com

unread,
Jun 24, 2008, 2:39:28 PM6/24/08
to Google Collections Library - users list
I understand the inelegance of nulls. I also think it's terrible to
have to break consistency (use unmodifiableMap) in order to accomodate
the 90% of libraries (such as, say, JDBC) that force us to use nulls.
I also can't see what performance penalties lie in having the
container hold null values -- keys yes, values, no.

Nevertheless I can't argue with you; it's your library, apparently.

Ryan

On Jun 24, 2:26 pm, "kevin bourrillion" <kev...@google.com> wrote:
> Hello Ryan,
>
> Sometimes you want a map to be allowed null values, and sometimes you
> don't.  In the cases where you do, we'd recommend just continuing to use
> Collections.unmodifiableMap(), or you can make a simple wrapper for
> ImmutableMap that masks/unmasks nulls.  Or use AtomicReference or a similar
> NullableReference class as the value in the map.
>
> In the cases where you don't, you're better served by an ImmutableMap that
> rejects nulls.  This map can perform better, and lets your code fail fast
> instead of having NPE's discovered far from where the error really
> happened.  And you don't have to clutter your code with precondition checks
> that look for nulls in the map -- you just ImmutableMap.copyOf(map) and
> that's it.
>
> We have found the latter case to be much more prevalent in well-designed
> code, so we tailored the library to that case.
>
> On Tue, Jun 24, 2008 at 11:17 AM, r...@thimbleware.com <ryan.d...@gmail.com>

kevin bourrillion

unread,
Jun 24, 2008, 2:57:31 PM6/24/08
to ryan...@gmail.com, Google Collections Library - users list
On Tue, Jun 24, 2008 at 11:39 AM, ry...@thimbleware.com <ryan...@gmail.com> wrote:

I understand the inelegance of nulls.  I also think it's terrible to
have to break consistency (use unmodifiableMap) in order to accomodate
the 90% of libraries (such as, say, JDBC) that force us to use nulls.

I'd like to get some opinions from the list on whether using nulls as values in a map feels more like a 90% use case to you, or a 50 or a 10 or what.

I don't feel any sense of loss at this idea of inconsistency -- as developers we look at each case and use the right library for the job.  Consistency is what we strive for when all other factors are equivalent; it should not outweigh more practical considerations.


I also can't see what performance penalties lie in having the
container hold null values -- keys yes, values, no.

It's quite true that that shouldn't be the central thrust of our argument. 

I'm more concerned with sacrificing the ideal behavior that non-nullable use cases want to have; treatment of null as a first class citizen is known to be fraught with peril and an anti-pattern, and I don't mind our library being one more way in which dealing with nulls is a little more annoying than not.  I'm ok with users feeling some motivation to find other, more null-less approaches to their code.

You may want to look into what the reasoning has been behind the JDK's sea change away from null-friendly to null-rejecting collections as of around Java 5 and see what you find out.

 
Nevertheless I can't argue with you; it's your library, apparently.

"Apparently"?  :-)  Yes, of course it's our library, and we're responsible for its quality.  And of course you can argue with us, and you are; that's what mailing lists are for.  We appreciate and value your feedback, and we always listen whether we agree or not.  Thanks!


ryan...@gmail.com

unread,
Jun 24, 2008, 4:06:28 PM6/24/08
to Google Collections Library - users list
I'm down with the philosophy of forcing users to be aware and in some
cases feel the pain of using NULLs. However I think it's most
reasonable to cause this pain at insert time rather than retrieval
time in order to continue to fulfill the contract and expectations of
Map<K,V>. Wrapping all nulls in a shell (ala Maybe in Haskell) means
ruling out a reader (which could likely be a third party API ala
Spring, etc.) that is not aware of the shell.

Perhaps the following, since I can't think of anything more elegant at
this time:

ImmutableMap.<K,V>nullableBuilder() // user is aware they are
choosing a nullable container
.put(k, v)

behaves like normal put, will not allow null -- could even declare
checked exception

.putNull(k2)

explicit placing of null value

.putNullable(k3, v3)

allows nulls always.

Ryan

On Jun 24, 2:57 pm, "kevin bourrillion" <kev...@google.com> wrote:
> On Tue, Jun 24, 2008 at 11:39 AM, r...@thimbleware.com <ryan.d...@gmail.com>

Geoffrey Wiseman

unread,
Jun 24, 2008, 3:39:35 PM6/24/08
to Google Collections Library - users list
On Jun 24, 2:57 pm, "kevin bourrillion" <kev...@google.com> wrote:
> I'd like to get some opinions from the list on whether using nulls as values
> in a map feels more like a 90% use case to you, or a 50 or a 10 or what.

I'd say maybe a 30% to 50% case -- depends a lot on the particular use
of the map. There are lots of scenarios where I'd want to avoid using
nulls in a map, and equally lots of scenarios where having null values
in a map would be useful.

It's certainly true that many projects have data structures that may
contain nulls (database records, POJOs with object references). Null
handling can be a problem in Java applications, and over-use of null
values can be a 'code smell'. It's interesting to consider options
like Nice's null-handling (http://nice.sourceforge.net/safety.html)
and other approaches in languages yet to come. There are alternatives
even in Java like the 'null object' pattern, but ultimately I often
find that judicious use of null is simpler than the alternatives. I'm
open to the idea that may be a failing on my part, but for the moment,
I'll note that I'd be surprised to find that many projects eliminate
uses of null in their objects altogether.

An implementation of Map that restricts my choices and/or forces me to
consider making refactorings which will certainly cost time (even if
they may be beneficial in other respects) is probably an
implementation I'll end up using less often. (Which doesn't mean that
invalidates the idea of a null-value-free collection, just means I
won't use it as often as I might otherwise).

> I'm more concerned with sacrificing the ideal behavior that non-nullable use
> cases want to have; treatment of null as a first class citizen is known to
> be fraught with peril and an anti-pattern, and I don't mind our library
> being one more way in which dealing with nulls is a little more annoying
> than not.  I'm ok with users feeling some motivation to find other, more
> null-less approaches to their code.

Although I sympathize, I wonder how often you'll find that users feel
motivation to find other, more null-friendly approaches to Map. ;)

- Geoffrey

limpb...@gmail.com

unread,
Jun 24, 2008, 5:38:41 PM6/24/08
to Google Collections Library - users list
I quite enjoy the fact that with an ImmutableMap,
this statement is unambiguous:

String value = immutableMap.get(5);
if (value != null) {
// handle the case where there's a mapping for 5
} else {
// handle the case where there isn't a mapping
}

With regular Maps, it's necessary to do the gross
containsKey() nonsense:

String value = immutableMap.get(5);
if (value != null || immutableMap.containsKey(5)) {
// handle the case where there's a mapping for 5
} else {
// handle the case where there isn't a mapping
}

By making get() return null if there's no mapping
found, the Map interface treats null values as a
second-class citizen.

I prefer to handle nulls before putting them into
collections.

kevin bourrillion

unread,
Jun 24, 2008, 5:51:01 PM6/24/08
to Geoffrey Wiseman, Google Collections Library - users list
On Tue, Jun 24, 2008 at 12:39 PM, Geoffrey Wiseman <geoffrey...@gmail.com> wrote:

Although I sympathize, I wonder how often you'll find that users feel
motivation to find other, more null-friendly approaches to Map.  ;)

And that's perfectly fine. We don't get paid on commission. :-)

It's the same thing for ConcurrentHashMap, ArrayDeque, etc. etc. -- if you really need nulls, you find something else or you wrap, etc.

Anyway the issue of the right thing to do for ImmutableMap values is still open.  Thanks for contributing your perspectives, everyone.
Reply all
Reply to author
Forward
0 new messages