Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nullpointer in clojure when running doseq with multiple expressions in the body

Tags:

clojure

The following expression in clojure works great:

(doseq [x '(1 2 3 4)] (println x))

This one gives me a nullpointer:

(doseq [x '(1 2 3 4)] ((println x)(println "x")))

It produces the following output:

user=> (doseq [x '(1 2 3 4)] ((println x)(println "x")))
1
x
java.lang.NullPointerException (NO_SOURCE_FILE:0)
user=> (.printStackTrace *e)
java.lang.NullPointerException (NO_SOURCE_FILE:0)
  at clojure.lang.Compiler.eval(Compiler.java:4639)
  at clojure.core$eval__5182.invoke(core.clj:1966)
  at clojure.main$repl__7283$read_eval_print__7295.invoke(main.clj:180)
  at clojure.main$repl__7283.doInvoke(main.clj:197)
  at clojure.lang.RestFn.invoke(RestFn.java:426)
  at clojure.main$repl_opt__7329.invoke(main.clj:251)
  at clojure.main$legacy_repl__7354.invoke(main.clj:292)
  at clojure.lang.Var.invoke(Var.java:359)
  at clojure.main.legacy_repl(main.java:27)
  at clojure.lang.Repl.main(Repl.java:20)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  at java.lang.reflect.Method.invoke(Method.java:597)
  at jline.ConsoleRunner.main(ConsoleRunner.java:69)
Caused by: java.lang.NullPointerException
  at user$eval__266.invoke(NO_SOURCE_FILE:26)
  at clojure.lang.Compiler.eval(Compiler.java:4623)
  ... 14 more
nil

Just adding an extra set of parentheses around the body of a doseq gives me that nullpointer. What am I doing wrong?

like image 734
Hans Sjunnesson Avatar asked Oct 07 '09 09:10

Hans Sjunnesson


1 Answers

Well, you already figured out the solution, so just a few hints to explain the behavior:

In Clojure (just like in Lisp, Scheme, etc) everything is an expression and an expression is either an atom or a list. With regard to lists, the Clojure manual says

Non-empty Lists are considered calls to either special forms, macros, or functions. A call has the form (operator operands*).

In your example, the body ((println x) (println x)) is a list and the operator is itself an expression which Clojure has to evaluate to obtain the actual operator. That is, you're saying "evaluate the first expression and take its return value as a function to invoke upon the second expression". However, println returns, as you noticed, only nil. This leads to the NullPointerException if nil is interpreted as an operator.

Your code works with (do (println x) (println x)) because do is a special form which evaluates each expression in turn and returns the value of the last expression. Here do is the operator and the expressions with println ar the operands.

To understand the usefulness of this behavior, note that functions are first-class objects in Clojure, e.g., you could return a function as a result from another function. For instance, take the following code:

(doseq [x '(1 2 3 4)] ((if (x > 2)
    (fn [x] (println (+ x 2)))
    (fn [x] (println (* x 3)))) x))

Here, I am dynamically figuring out the operator to invoke upon the element in the sequence. First, the if-expression is evaluated. If x is larger than two, the if evalutes to the function that prints x + 2, else it evaluates to the function that prints x * 3. This function is than applied to the x of the sequence.

like image 102
janko Avatar answered Sep 28 '22 06:09

janko