Fork me on GitHub
#clojure-uk
<
2017-04-01
>
mattford12:04:52

I find this weird as I continue my Clojure journey.

mattford12:04:57

``````maws.core> (if [] (print "Hello"))
Hello
nil
maws.core> (if nil (print "Hello"))
nil``````

mattford12:04:29

The empty list is not nil and not false? Yet nil can be used in place of an empty seq, list, map. So nil = [] but [] != nil Equality is no longer commutative.

mattford12:04:10

Just seems wrong somehow.

mattford12:04:02

Well for actual clojure equalities it’s always false so at that level it is commutative.

mattford12:04:10

``````maws.core> (= nil [])
false
maws.core> (= [] nil)
false
maws.core> (:matt nil)
nil
maws.core> (:matt {})
nil``````

mattford12:04:26

Up to the point I can switch nil in for an empty map. But I can’t swap in an empty map for a condition.

mattford12:04:59

I guess people write `not-empty` everywhere in conditions?

mattford12:04:06

Oh well 🙂

bronsa12:04:28

if what you're asking were true what'd follow would be that `() = [] = {} = nil` which is clearly nonsensical

mattford12:04:35

yes that’s the point

mattford12:04:48

nil is all those things in certain contexts

mattford12:04:27

but those things are not nil and not false in conditionals (like in other lisps)

jasonbell13:04:29

A vector is a vector, which just happens to be empty.

bronsa13:04:33

@mattford no, nil is not the empty list/vector/map in any context. some functions will coerce nil to either one of those but it doesn't imply equality

mattford13:04:48

`(nil :matt)`

bronsa13:04:09

that's a NPE, nil is not an IFn, what's surprising about that?

mattford13:04:41

Isn’t nil in that context an empty map?

bronsa13:04:53

why would it be?

bronsa13:04:59

nil is always just nil

mattford13:04:03

it acts exactly like one

bronsa13:04:06

no it doesn't

bronsa13:04:20

``````user=> (:foo 123)
nil
``````

bronsa13:04:42

it just so happens that `get` will return nil if trying to access elements from a non associative data structure

bronsa13:04:57

doesn't mean that anything that get returns nil from is a map

mattford13:04:07

bronsa13:04:09

it's garbage in garbage out

bronsa13:04:26

@mattford the distinction you have to understand is that `nil` isn't or doesn't behave like an empty collection in some contexts, some functions decide to return the same result when invoked on nil as they do if invoked on an empty collection but that's up to the specific function

bronsa13:04:57

e.g. if you have a function that acts on maps and you pass nil, it's likely that `(f nil)` will produce the same result as `(f {})`

bronsa13:04:04

but that's up to the implementation of `f`

mattford13:04:36

Seems a bit dangerous no?

bronsa13:04:48

not really

bronsa13:04:52

after getting used to writing clojure you'll realize it really isn't an issue

mattford13:04:02

That explanation is a big help 🙂

bronsa13:04:55

btw that blog post says `because nil is a seq` which is not really accurate

mattford13:04:17

bronsa13:04:32

altho it's true that almost all functions that operate on seqs, behave on `nil` as if they were acting on `()`

mattford13:04:43

except when they don’t 😉

bronsa13:04:46

well to be fair i can't think of any sequence function right now that doesn't operates differently on nil than it does on empty seqs

bronsa13:04:21

(in clojure the concept of a sequence is different from the more general concept of a collection)

mattford13:04:02

I started on this road by using `cond` and assuming the empty list,seq, map would be false.

bronsa13:04:23

no values in clojure other than `false` and `nil` are considered falsey

mattford13:04:43

Yep - but I noticed that nil (mostly) worked as the empty list and couldn’t understand how that would work. Until you explained.

bronsa13:04:00

fair enough

bronsa13:04:21

i guess if you come from other lisps this might be a bit confusing :)

seancorfield15:04:33

@mattford does it help to consider that `(seq [])`, `(seq '())`, `(seq {})`, and `(seq nil)` all produce `nil` -- and all sequence functions start by call `seq` on their argument to handle an empty sequence. This makes it much easier to compose sequence functions since you don't have to worry about `nil` -- it will just pass through safely.

mattford15:04:12

Say I’m collecting the results of a bunch of functions in a vector, they return nil if they don’t do anything. Normally I’d just flatten it.

mattford15:04:30

But as I have a whole load of nils that doesn’t work.

bronsa16:04:06

flatten is rarely what you want

bronsa16:04:43

`(mapcat identity your-coll)` usually is enough

mattford16:04:00

That breaks down my strings also - hows about `(keep identity collection)`

seancorfield23:04:40

@mattford You can drive boot from the REPL, don’t think you can with Leiningen.