for example,
> (some #{nil} #{nil 1 2 3})
nil
> (some #{} #{nil 1 2 3})
nil
I know I could use
(some nil? #{nil 1 2 3})
to check nil value. I can't think of any good example at the moment.
But generally, when nil is returned, how do I determine if nil means nothing is found or the value nil is found?
nil is just a value, and its meaning depends on context.
It's just like all other values in that regard: the only thing to be aware of is that it is falsy, i.e. counts as false in conditional expressions.
Three particular cases to be aware of:
nil is the return value used to indicate an empty sequence, e.g. in (seq [])
nil is often used as a return value to indicate false, e.g. in (or false nil)
nil is returned by default when a map lookup can't find a given key, e.g. in ({:a 1} :b)
These cases can on occasion cause ambiguity: if so then you need to use a different function. Your example is a good one:
(some #{nil} #{1 2 3}) => nil (failure - no result found)
(some #{nil} #{nil 1 2 3}) => nil (success - nil result found!!!)
In this case you've simply chosen the wrong function: you can't use the set #{nil} to detect nils.... instead you can just use nil? or you could even do something fancy with an alternative return value like #(get #{nil} % :not-found)
Isn't this a question of the question you're asking, rather than anything particular to Clojure ?
You could ask:
> (filter nil? #{nil 1 2 3})
> (nil)
which tells you there was one nil in the set; you get what you ask for - you asked an ambiguous question and got a suitably ambiguous response.
Related
Write a function which, given a key and map, returns true if the map contains an entry with that key and its value is nil.
Solution I came across:
#(nil? (get %2 % true))
Can someone please explain the use of true in
(get %2 % true) ?
Thank you!
that's a default value that will be returned in the case of absence of the key
;; key exists
(get {:a 1} :a 2)
#=> 1
;; key doesn't exist (default value is returned)
(get {:a 1} :b 2)
#=> 2
;; key exists and it's value is nil
(get {:a nil} :a 2)
#=> nil
;; key doesn't exist, nil is returned
(get {:a 1} :b)
#=> nil
some docs could be found here
https://clojuredocs.org/clojure.core/get
so the idea is that (get {:a 1} :b) will always return nil because key doesn't exist. In this case (nil? (get {:a 1} :b)) will return true, which is not what we want. That's why adding this default value is necessary. So nil will be returned only in the case when the actual value is nil.
The value true is not special here. 85 would work just as well: any value other than nil fixes the problem.
I am learning clojurescript and i came across this snippet.
:on-click (fn [] (swap! state/order update (:id gig) inc))
I looked up the docs for update function and it said that update takes in a key and a functions. Passes the old value from the atom to the function and then update the atom. If there is no existing value for the key in atom nil is passed as input to the function.
When i tried the same thing in the repl it did not work
(def atom-test (atom {}))
(swap! atom-test update :aa inc)
NullPointerException clojure.lang.Numbers.ops (Numbers.java:1013)
Adding fnil to catch this NullPointerException worked.
user=> (swap! atom-test update :aa (fnil inc 0))
{:aa 1}
I cannot understand why it works in case 1 in clojurescript and why it does not work in case 2 in clojure repl. Can anyone explain whats the trick here.
For cljs, it is common for operations to safely handle nil without causing exceptions.
cljs.user=> (update {} :a inc)
{:a 1}
cljs.user=> (inc nil)
1
cljs.user=> (+ 1 nil)
1
https://cljs.github.io/api/syntax/nil
The inc function requires an argument that satisfies number?. This is true in Clojure and ClojureScript.
If you pass something else, like nil, the program is incorrect: (inc nil) has undefined behavior. This is not safe to do. It just so happens to return 1 but that is not guaranteed and is an accident of implementation.
If, for example, you instead pass a literal string to inc, ClojureScript will emit a warning at compile time:
cljs.user=> (inc "a")
WARNING: cljs.core/+, all arguments must be numbers, got [string number] instead at line 1 <cljs repl>
Perhaps in the future, the compiler could similarly emit a warning for (inc nil), but what is more likely to happen is that specs will be written covering core functions, with cljs.core/inc being specified to accept an argument satisfying number?.
TL;DR: using fnil is the correct thing to do here.
I am using funcool/cats, append monoid with the following code :
(m/mappend (maybe/just [1 2 3])
nil
(maybe/just [4 5 6])
(maybe/nothing)) ;;=> #<Just [1 2 3 4 5 6]>
What is the rationale for treating nil as maybe/nothing ?
Note : the version is [funcool/cats "1.2.1"]
From the commit log, it seems like it's
just for (sic) avoid accidental null pointer exceptions
This is also documented here: http://funcool.github.io/cats/latest/#nil
Given the fact that nil is both a value and a type, we have extended
the nil type to be equivalent to Maybe monad’s Nothing.
Following up from this question: Idiomatic clojure map lookup by keyword
Map access using clojure can be done in many ways.
(def m {:a 1}
(get m :a) ;; => 1
(:a m) ;; => 1
(m :a) ;; => 1
I know I use mainly the second form, and sometimes the third, rarely the first. what are the advantages (speed/composability) of using each?
get is useful when the map could be nil or not-a-map, and the key could be something non-callable (i.e. not a keyword)
(def m nil)
(def k "some-key")
(m k) => NullPointerException
(k m) => ClassCastException java.lang.String cannot be cast to clojure.lang.IFn
(get m k) => nil
(get m :foo :default) => :default
From the clojure web page we see that
Maps implement IFn, for invoke() of one argument (a key) with an
optional second argument (a default value), i.e. maps are functions of
their keys. nil keys and values are ok.
Sometimes it is rewarding to take a look under the hoods of Clojure. If you look up what invoke looks like in a map, you see this:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L196
It apparently calls the valAt method of a map.
If you look at what the get function does when called with a map, this is a call to clojure.lang.RT.get, and this really boils down to the same call to valAt for a map (maps implement ILookUp because they are Associatives):
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L634.
The same is true for a map called with a key and a not-found-value. So, what is the advantage? Since both ways boil down to pretty much the same, performance wise I would say nothing. It's just syntactic convenience.
You can pass get to partial etc. to build up HOFs for messing with your data, though it doesn't come up often.
user=> (def data {"a" 1 :b 2})
#'user/data
user=> (map (partial get data) (keys data))
(1 2)
I use the third form a lot when the data has strings as keys
I don't think there is a speed difference, and even if that would be the case, that would be an implementation detail.
Personally I prefer the second option (:a m) because it sometimes makes code a bit easier on the eye. For example, I often have to iterate through a sequence of maps:
(def foo '({:a 1} {:a 2} {:a 3}))
If I want to filter all values of :a I can now use:
(map :a foo)
Instead of
(map #(get % :a) foo)
or
(map #(% :a) foo)
Of course this is a matter of personal taste.
To add to the list, get is also useful when using the threading macro -> and you need to access via a key that is not a keyword
(let [m {"a" :a}]
(-> m
(get "a")))
One advantage of using the keyword first approach is it is the most concise way of accessing the value with a forgiving behavior in the case the map is nil.
I've started learning Clojure this week. I'm working my way through the conditional koans and don't understand the following assertions:
"Some of them leave you no alternative"
(= [] (if (> 4 3)
[]))
"And in such a situation you may have nothing"
(= nil (if (nil? 0)
[:a :b :c]))
The second one does what I would expect -- the condition evaluates to false-- [EDIT: Actually, it's true and I'm just still not used to 'operator-first' reasoning!], if tries to return the second alternative, finds none, and so returns nil. So, why doesn't the first return nil? Is it because an empty structure is 'close enough' to nil?
Because the first if evaluates to true (as 4 is indeed greater than 3), so else-clause is irrelevant. It returns the then-clause, which is defined and equal to [].