Clojure: Truthy and Falsey
blog.jayfields.com
blog.jayfields.com
(0) if foo() then do_something() else do_something_else()
It turned out that it was unnecessary to do anything in the "then" branch: (1) if foo() then no_op else do_something_else()
My friend, quite naturally, changed that to this: (2) if not foo() then do_something_else()
After several hours of frustration, my friend finally realized that the transformation from (1) to (2) is not valid in Visual Basic. How can this be? As I recall, there is some false value in VB such that its negation is also false.This is the kind of hell languages create when they try to be helpful by having lots of different false values (0, the empty string, the empty list, and of course "false") and at the same time have lots of implicit conversions.
So, be glad that Clojure has only two "falsey" values.
True is defined as -1.
This allowed there to be a single, type-agnostic "not" operator. There was no distinction between binary and logical negation.
C, of course, has ~ and ! operators and uses 0 and non-zero for truthiness. When calling into non VB "Classic" modules, the mapping of boolean values can be unnecessarily confusing.
http://docs.python.org/py3k/reference/datamodel.html#object....
Edit: though I wish the standard library used its configurable truthiness a little more. I'd like a closed filehandle to evaluate to False, for instance.
I meant to say false :(
I actually prefer this system in dynamically typed languages, as it seems to get the right balance between simplicity and practicality.
A system that just uses explicit true and false values would result in more redundancy in conditionals, e.g.
(if (not (nil? x)) ...)
Compared to: (if x ...)
On the other hand, a boolean system that's any more complex tends to be hard to remember. For instance, I could never remember whether a blank string was considered true or false in Python, and I certainly can't remember all of the Javascript edge conditions relating to booleans.Your example is also sort of a degenerate case for Lisp syntax. (Hey, it can't all be upside with no downside.) In languages that actually have a syntax it is, again, not something that is anywhere near as bad as you might think. I generally only notice when I actually want to have 0 be the false case and there is something to be said for putting the == 0 there anyhow; someone once said explicit is better than implicit.
I'm also not convinced this is a special case for Lisp syntax. In Ruby, one often finds code like:
hash[key] ||= value
find_resource(key) or not_found
And even if it is a special case, aren't we talking about how suitable this is for Clojure specifically?"Weak" and "strong" type system are meaningless terms if you don't define them for your local usage. As I suggested, I don't care if the check occurs at runtime or compile time.
"And even if it is a special case, aren't we talking about how suitable this is for Clojure specifically?"
You may be. I'm talking about it in general.
The reason I brought up "degenerate case of the lisp syntax", since apparently nobody had a clue :-/, is that you complained about the "redunduncy" in
(if (not (nil? x)) ...)
and what I meant is that that may be how Clojure spells it, but Clojure is being very verbose here. On the macro scale you don't pay much for Lisp's syntax with the parentheses because other languages need punctuation too and it tends to just come out in the wash, but sometimes you do get hammered on the micro scale. (And sometimes Lisp says something concisely few other languages can. But you never get pure win in the real world.) If you spell it something more like if !nil(x): ...
there's much less redundancy. Assuming you mean "verbosity" by that, which I'm not sure of, since I don't see anything redundant in the Clojure example except too many parentheses but generally we don't call that redundancy in a Lisp program.Again, I'm talking about the principles of managing conditionals in general, not just Clojure. And again, across the several languages I've used that require booleans and only booleans it just doesn't come up as an actual problem that often to actually check for the relevant falsity if you need to. Besides, the real problem is that there is no universal idea of truthiness and falsyness, you should have to say exactly which one you are using. A lot of bad mistakes get made precisely because people don't think about it. How many times have I seen conditionals break because they got passed an empty string when they meant to check for nil/NULL/None/whatever and do something frightfully wrong as a result? I've long since lost count.
hash[key] = value if !hash[key].nil?
Can be written as: hash[key] ||= value
And: response = find_resource(key)
response.nil? ? response : not_found
Can be written as: find_resource(key) or not_found
I also can't think of any instance where a function has used an empty string to denote a failure condition. In a language that treats nil as being false, generally functions are quite careful as to the value they return.[1] http://docs.racket-lang.org/reference/if.html?q=if&q=fal...)
puts (i = nil || 1) => 1
puts i => 1
puts (i = nil or 1) => 1
puts i => nil
puts i = nil || 1 => 1
puts i => 1
puts i = nil or 1 => nil
puts i => nil