13

Using Clojure, how do I create the following object? The object is taken from java code (From Effective Java):

NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();

5 Answers 5

26

While it's hard to argue with the concision in the other answers1, .. has somewhat fallen out of favor, replaced by the more versatile ->. Personally I prefer :

(-> (NutritionFacts$Builder. 240 8) 
    (.calories 100)
    (.sodium 350)  
    (.carbohydrates 27) 
    (.build))

It's a couple more characters, but you gain two things:

  • Explicitness. I can look at the sodium line (for example) and tell it's a Java method call, because the . is right there.
  • Flexibility. If I need to, I can chain some non-method call in the middle there (printing it to stdout, say), or at the end of all this feed it in to some other function call.

Most importantly, every other answer to this question has gotten the classname wrong: Java's NutritionFacts.Builder is language sugar over the real JVM class named NutritionFacts$Builder, and that class is the one Clojure must refer to (since we are not using javac to compile our code).

1 I do disagree with the doto suggestion: it works only because this Builder class happens to implement its method-chaining by mutating a single instance and then returning it. doto is great for Java objects that require in-place mutation, but when a class is kind enough to pretend it's immutable you should really be using the method-chaining version (ie, ->).

Sign up to request clarification or add additional context in comments.

Comments

9

Use .. macro. It's two consecutive dots. It allows just what you need - to consecutively call next Java method on the result of the previous.

I don't have a REPL around, but your line should translate to something like:

(.. (NutritionFacts.Builder. 240 8) 
    (calories 100)
    (sodium 350)  
    (carbohydrates 27) 
    (build))

Comments

3

I'm only starting with Clojure, but it looks like standard method invocation to me:

(doto
  (NutritionFacts.Builder. 240 8)
  (.carbohydrates 27)
  (.sodium 35)
  (.calories 100)
  (.build)
)

EDIT:
As @Goran Jovic points out, this calls all methods on the object created in the first form.
So it works in this case since the Java code uses method chaining, but is not more generally applicable.

4 Comments

The only reason it isn't idiomatic is because you mutate a var in several separate forms. Just wrap it in a doto and it's fine!
@Goran Jovic I have changed the code as you suggested. Thanks!
Yup, that's it. Note that the main difference between doto and .. is that doto calls methods on one object defined by the first form, and .. does each invocation on the result of the previous one. In this case it is the same since Java methods keep returning the object being built.
@GoranJovic: that was worth being added to the answer; it makes a difference that the user should be aware of. Thanks again!
2

(.. (NutrionalFacts.Builder. 240 8) (calories 100) (sodium 35) (carbohydrates 27) (build))

Comments

0

This thread is a couple of years old, and the thread-first macro is still preferred way as far as i can tell, but the $ syntax is not needed. The slash (/) works as well:

(-> (Caffeine/newBuilder)
      (.maximumSize 10000)
      (.build))

2 Comments

(Caffeine/newBuilder) is a call to a static method (Java Caffeine.newBuilder()) whereas (NutritionalFacts$Builder.) is a call to the constructor of a static class (Java new NutritionalFacts.Builder()), so this really isn't any different from the accepted answer.
ahh, ok. i thought there was some update for the syntax. thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.