The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Clojure: fnil

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jay Fields

Posts: 765
Nickname: jayfields
Registered: Sep, 2006

Jay Fields is a software developer for ThoughtWorks
Clojure: fnil Posted: Jan 11, 2011 9:00 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Jay Fields.
Original Post: Clojure: fnil
Feed Title: Jay Fields Thoughts
Feed URL: http://feeds.feedburner.com/jayfields/mjKQ
Feed Description: Blog about Ruby, Agile, Testing and other topics related to software development.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Jay Fields
Latest Posts From Jay Fields Thoughts

Advertisement
The fnil function was added to Clojure in version 1.2. The fnil function is a great addition that allows you to write code that works for all cases where an argument isn't nil, and handle the case where it is nil.

From the documentation: The fnil function takes a function f, and returns a function that calls f, replacing a nil first argument to f with a supplied value.

A simple example is working with + and nil.
user=> (+ nil 1)
java.lang.NullPointerException (NO_SOURCE_FILE:0)
user=> (def new+ (fnil + 0))
#'user/new+
user=> (new+ nil 1)
1
As you can see, the + function throws an exception if an argument is nil; however, we were easily able to create our own new+ function that handles the first argument being nil.

In isolation, it might be hard to see how this is valuable. However, once combined with high order functions it's easy to see the benefit.

Several months ago I wrote about composing functions and used the update-in function as my final example of what I thought was the best implementation. What I didn't address in the blog entry was how to handle the first update.

As you can see from the following code, the first update will fail if a default value isn't populated.
user=> (def current-score {})                          
#'user/current-score
user=> (defn update-score [current {:keys [country player score]}]
(update-in current [country player] + score))
#'user/update-score
user=> (update-score current-score {:player "Paul Casey" :country :England :score -1})
java.lang.NullPointerException (NO_SOURCE_FILE:0)
At the time of the writing Clojure 1.2 was not production ready, and I used a definition of update-score that was much more verbose, but did handle nil.
user=> (defn update-score [current {:keys [country player score]}]                    
(update-in current [country player] #(+ (or %1 0) score)))
#'user/update-score
user=> (update-score current-score {:player "Paul Casey" :country :England :score -1})
{:England {"Paul Casey" -1}}
While the above code works perfectly well, it's obviously not nearly as nice to read as the example that doesn't need to concern itself with nil.

However, Clojure 1.2 is now production ready and the fnil function is available. As a result, you can now write the following version of the update-score function that is obviously preferable to the version that uses the or function.
user=> (defn update-score [current {:keys [country player score]}]                    
(update-in current [country player] (fnil + 0) score))
#'user/update-score
user=> (update-score current-score {:player "Paul Casey" :country :England :score -1})
{:England {"Paul Casey" -1}}
I'll admit that fnil wasn't my favorite function when I first found it; however, it's become indispensable. Looking through my code I find (fnil + 0) and (fnil - 0) a few times, and I definitely prefer those to the versions that use the or function.

Read: Clojure: fnil

Topic: Clojure: fnil Previous Topic   Next Topic Topic: I've been sucked in to Quora

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use