On Thu, Jul 2, 2009 at 1:59 PM, Raoul Duke<rao...@gmail.com> wrote:
>
>> clojure functions should return a value.  This is good advice, but I
>> have code that sometimes return nil.  Is it better to return 'nil' or
>> an object with no data.  I guess a simple example, if you have a
>
> imho, null/nil/etc. are more often than not pretty evil.
>
> random related links:
> http://lukeplant.me.uk/blog.php?id=1107301659
> http://weblogs.asp.net/fmarguerie/archive/2009/02/12/null-object-design-pattern.aspx

That may be somewhat less relevant:

(map int "foo")  ==> (102 111 111)
(map int "")  ==> ()
(map int nil)  ==> ()

In general, almost anything that can handle an empty
collection will behave the same when given nil.

So when designing your API you may want to consider:

1. Do you need to differentiate between an empty collection
   an nil?

   For example, perhaps an empty string means the user left
   a field blank, but nil means they've not yet been given
   the opportunity to fill it out.  Or some other more useful
   example. :-P

2. Will your user want to conj onto the thing you return?

   In some cases it's convenient to take, say, a vector
   returned by some function and just 'conj' onto it.
   Returning nil would cause such user code to build an list
   instead of a vector, and this may not be what you want.

3. Do you want to make plain truth tests useless?

   On the other hand, returning an empty collection forces
   the user to use 'empty?' like this:

   (when-not (empty? (my-things x))
     (do something with my-things))

   ...obscuring the main point of the test in layers of
   'not' and 'empty?'.  While returning nil allows
   nil-punning like:

   (when (my-things x)
     (do something with my-things))

   It gets worse if the user was hoping to use when-let...

4. Is laziness a factor?

   If a collection is empty 'rest' returns an empty seq, but
   'next' returns nil.  In fact, this is a defining
   difference between the two functions.

   The reason in this case is that in order to return nil for
   an empty collection, you first need to find out if the
   collection is empty which forces the realization of more
   of a lazy seq than you sometimes want, so 'rest' refuses
   and simply returns the un-realized rest of the seq.

   Conversely, you often don't care about that extra laziness
   and want the convenience of nil-punning in which case
   'next' is perfect.

So these are all things to keep in mind, and there are
probably others as well.  However in practice it often turns
out that what's easiest to write in your API code is also
what will be most convenient for your users.  For example,
for cases where point 2 resonates with you, it's also likely
you're getting that empty vector by doing something like
'pop', which will itself return an empty vector rather than
nil.  Conversely, if 3 seem more important in your case,
it's like you're could you 'when' in your API code, which
returns nil (not an empty collection) in false cases.

--Chouser

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to