3 ms·
This isn't really a Clojure specific question but is there any benefit to making 'if' a special form? Meaning you can't do: (map if [true false true] [1 1 1] [
by Avshalom 17y ago
This isn't really a Clojure specific question but is there any benefit to making 'if' a special form? Meaning you can't do:
(map if [true false true] [1 1 1] [2 2 2])
not that I can think of any reason why you'd want to do that (specifically) but Picolisp, Factor, REBOL and I'm sure a couple other languages implement if as a normal function. To take an example from some edition of programming clojure:
(defmacro unless [expr form] (list 'if expr nil form))
in factor:
: unless ( ? quote -- ) swap [ drop ] [ call ] if ; inline
no macro needed to futz with if's.
Does it have any advantages or is it just one of those things that "that's just how it's always been"?
- Rayne 17y agoWell, it's actually impossible to write if as a function in Clojure.
- Avshalom 17y agoI think it's impossible to write if as a function in anything, I'm pretty sure that at some point you need a branching primitive, but the if the VM uses and the if exposed to the user don't have to be the same thing. Like I said though, it's not a Clojure specific question, CL and Scheme both use a special form for if as well. Even if it can't be done in a JVM language it can be done. I'm just curious if there's any particular reason it isn't done, like being way easier for a compiler/interpreter to optimize or something or if it's mostly historical.
- stonemetal 16y agoThe first problem you run into is call by value. As a function the args to if would be evaluated before the function call. You could force the user to quote the branches to the if call to get around it but the special form is less error prone.
- geocar 17y agoMaking "if" a special form means that it can short-circuit, and I'd rather write (if x big_expensive_expression y) than (funcall (if x (lambda () big_expensive_expression) (lambda () y)))
- deleted 17y ago[deleted]
- deleted 16y ago[deleted]
- geocar 16y agoAre you familiar with python? Perhaps this will help: if cnd: return do_big_stuff else: return do_other_big_stuff has different semantics than a hypothetical "if" function call: def a(): return do_big_stuff def b(): return do_other_big_stuff return if(cnd,a(),b()) Note here, both "do_big_stuff" and "do_other_big_stuff" are evaluated, regardless of the value of "cond". A short-circuiting if (only possible if "if" is a special form) will ONLY evaluate a() (and thus "do_big_stuff") if "cond" returns a truth-value. Now, Factor's "if" works like this (in python): return if(cnd,a,b)() That's fine- and it still has the short-circuiting semantics, but there's still a question of taste here.
- Avshalom 16y agoYeah okay I got it. I think the funcall/lambda stuff got me confused, it's kind of obvious in hindsight. In which case I agree it's a matter of taste. I guess I just like the taste of Factor/REBOL always passing blocks to if, having to say t [ 0 ] [ 3 ] if instead of simply say t 0 3 if is the trade off I suppose[1]. I'm guessing it works for picolisp because it's purely interpreted? because it certainly doesn't seem to be passing lambdas to 'if'. Can anyone confirm/deny? [1]well actually the word ? does that but to make it work for both you need to do: : myif ( ? true false -- ) ? dup quotation? [ call ] [ ] if ; inline
- geocar 16y agoIt works in picolisp because the author foolishly implemented FEXPRs instead of special forms, and rather than fix this problem, spends time trying to convince people that this is actually a feature, and that it offers a certain succinctness that can't be achieved in other ways.
- weavejester 16y agoYou could have 'if' as a function, but it would mean you'd have to encase any non-literal condition in a function: (if (zero? x) 0 #(dec x)) To me, this seems a rather counter-intuitive step with very little benefit. People rarely need to use "if" as a function, so having "if" as a macro optimizes for the common case.