> if does not have a return value in a language like Java. In other words, it is not an expression, but a statement. Because everything in Clojure is an expression, there is no equivalent construct to Java’s if in it. Anyone know the language design rationale behind the way Java does it? It seems much easier to make everything an expression. Ive always disliked that part of Javascript and being forced to use ternary…
If your control structures are expressions then they can lead to code that the maintainers of the language might not want to promote. Remember that language design is not just about being as flexible as possible. If it were we would have stopped with Lisp. Languages are also designed with readability, portability, and simplicity in mind. Imagine if you could write this (nonsense) code in Java: bool a = (while (b) { i…
I am a horse in the land of booleans
61–70 of 89 posts
Re: I am a horse in the land of booleans
#62Because Java’s if does not return a value, you cannot say: return if (x This would have been a nice place to make an analogy to the question mark operator, since a java programmer would probably be familiar with it and it allows you to write: return if (x as return x
And also C, C++, and Objective-C programmers. I'm sure there are more languages that use that operator that I have not mentioned here.
Re: I am a horse in the land of booleans
#63Because Java’s if does not return a value, you cannot say: return if (x This would have been a nice place to make an analogy to the question mark operator, since a java programmer would probably be familiar with it and it allows you to write: return if (x as return x
>>java programmer would probably be familiar with it And also C, C++, and Objective-C programmers. I'm sure there are more languages that use that operator that I have not mentioned here.
$ php -a
Interactive mode enabled
php > echo 1 == 1 ? "foo" : "bar";
foo
php > echo 1 == 2 ? "foo" : "bar";
bar
Looks like javascript has it too: 1 == 1 ? "foo" : "bar"
"foo"
1 == 2 ? "foo" : "bar"
"bar"Re: I am a horse in the land of booleans
#64Earlier quoted context omitted.
i haven't checked it thoroughly, but it looks like all the desired properties of boolean arithmetic are preserved when false = 0 true = [1] (i.e. the equivalence class of all n > 0) && = + || = * spelling it out: || / + (or): 0+0 = 0 0+[1] = [1]+0 = [1] [1]+[1] = [1] && / * (and): 0*0 = 0 0*[1] = [1]*0 = 0 [1]*[1] = [1] where [1] stands for "any nonzero number". (please let me know if i missed anything!) so natural n…
`[1]+[1] = [1]` also doesn't hold for natural numbers if you are programming in a language with integer overflow. Neither does the multiplication `[1]*[1] = [1]`
Re: I am a horse in the land of booleans
#65Earlier quoted context omitted.
0 is the value integral types get default initialized too, it's the equivalent of default initializing a boolean to false.
But the fact that some types have a reasonable default value doesn’t make the values intrinsically equivalent to Boolean false. Plus, implicit default initialization is itself not necessarily a desirable feature. Especially not the kind that just default initializes to an all-zeroes bit pattern.
There are really only two reasons I can think of for not wanting default initialization.
1. performance
2. to catch mistakes on the edges of your system.
A good example of the second is converting incoming data to enumerations. If you're not explicitly checking for it, you can accidentally default initialize to a valid enumeration. This is why I always set the first enumeration to 1 for any language that allows me to. If someone makes that mistake, the missing data causes an error rather than silently doing the wrong thing.
But I can't really think of any reason outside of those two cases where you wouldn't want default initialization.
And my point was that one of the reasons 0 is chosen as false because it's consistent with respect to default initialization of booleans. I realize that isn't the original reason, but today it's a good reason for having the behavior.
Re: I am a horse in the land of booleans
#66I’m used to 0 and [] being falsy. Upsides and downsides to Clojure’s choice here?
The major advantage of empty collections being falsy is that you can kill two birds with one stone - it enables you to reduce your use of nil/null/None dramatically, since empty collections will fail a very idiomatic "if items" check just as well as null. But at the same time, you don't have to depend on users (library or otherwise) being careful to provide an empty list rather than null when they mean 'no value' - if they pass a null then your code will take the exact same shortcut with the exact same simple, idiomatic test. Whereas the alternative is needing to do both the null check AND the empty check any place you cannot trust the users of your function/library/whatever to pass real empty collections rather than nulls, which not only becomes tedious but is quite easy for new programmers to fail to do consistently.
In my own experience, the number of cases where an empty collection implies that data is effectively 'missing' is far greater than the number of cases where an empty list being provided would be semantically different from a null - in both cases "there is nothing there". And being freed to then create and pass around empty lists means that my own code is no longer littered with the necessary guards against Nullness in cases where I am the consumer of my own functions and want to be able to write simple list comprehensions without any guards.
In Clojure this is somewhat less of an issue because, as others have mentioned, it's idiomatic to pass `nil` around in the place of an empty collection, and so it's _generally_ safe to do so where in another language like Python or Javascript the function you're calling might not expect it. But in my opinion there was no real advantage to establishing this convention when it could just as easily have been the other way around, and there would therefore be somewhat less opportunity for inconsistent or inexperienced programmers causing NullPointerExceptions.
Re: I am a horse in the land of booleans
#67Earlier quoted context omitted.
0 being falsy makes no sense outside of the C family of programming languages. But there 0 is overloaded both as a number and pointer (it's a bit more complicated though, as the value of the null pointer doesn't need to be zero but assigning 0 to a pointer will assign the null pointer). In languages with more elaborate type systems, you usually have the pointer and number representation separated. 0 has no special me…
>But making zero elements evaluate to falsy is problematic. "" would be falsy as well then. In Python 0, [], and "" are all falsy. In my experience it's only been useful - why do you consider it problematic?
I do think it would've been better to have 0, specifically, not be falsy - unlike the other cases, 0 is not 'the absence of any actual data' but rather a special case of the data. I assume Python stuck with tradition on this one mostly because it is so tightly tied to C and UNIX-style scripting that changing it would've been confusing for most early users.
Re: I am a horse in the land of booleans
#68> if does not have a return value in a language like Java. In other words, it is not an expression, but a statement. Because everything in Clojure is an expression, there is no equivalent construct to Java’s if in it. Anyone know the language design rationale behind the way Java does it? It seems much easier to make everything an expression. Ive always disliked that part of Javascript and being forced to use ternary…
If your control structures are expressions then they can lead to code that the maintainers of the language might not want to promote. Remember that language design is not just about being as flexible as possible. If it were we would have stopped with Lisp. Languages are also designed with readability, portability, and simplicity in mind. Imagine if you could write this (nonsense) code in Java: bool a = (while (b) { i…
Indeed, if anything, if the intention is to communicate that the Boolean value is the result of some process that runs through a while loop, then explicitly saying that in the assignment seems to me to almost be the best way to do it :\
ymmv.
Now deeply nested while/assignment/ifs, that's a bad-pattern, but I'm not inherently convinced that's an expression/statement problem.
Re: I am a horse in the land of booleans
#69Earlier quoted context omitted.
I'm also used to 0 being false. A possible upside to this is that you can use multiplication and addition as boolean AND and OR, which might not seem that useful, but I remember that BASIC on a ti99/4a had neither AND nor OR, but boolean expressions evaluated to 0 or 1, so you could use this trick. Instead of if x = 5 and y = 7 then goto 10 use if (x = 5) * (y = 7) then goto 10 Good to know when you're 11 years old t…
It sounds like that was only useful because the language actually had no Boolean type (hence no operations for Boolean types). It doesn't really demonstrate that there is value to a "falsey" 0 in a language that already has a perfectly good value for false.
Re: I am a horse in the land of booleans
#70Earlier quoted context omitted.
"p" makes sense if you know that it stands for "predicate". It's not nearly as arcane as car and cdr. Also can we finally settle on a name for these things now? If car and cdr are too arcane we can do away with them (though I like being able to do caddadadr) but why do we need "first" and "rest" rather than the already established "head" and "tail"? I particularly dislike "rest" since it's a relative term, i.e. in no…
In Clojure, first and rest apply to sequences, which are a logical list abstraction. They apply to lists, but they can also be used on sequential views of indexed vectors, maps, sets, database result sets, files in a dir, lines in a file, and an open world of "things that can be seen in some order". head and tail I suspect are much more tied to linked lists and data structure than the more plain first and rest.