3

I'm wondering what the arguments for/against Falsy values are. On what principles would you decide to add or exclude them from a language? Are there any problems you could see them causing off-hand?

For users of languages that support Falsy values:

  • Where specifically have you used them to your advantage?
  • Where have you had unpleasant run-ins with them?
  • Are there any rules or finer points in your language/project/team about where it's appropriate or inappropriate to use them?

For users of other languages:

  • Have you ever seen a situation where you've thought "I wish I could use a Falsy value here"?

I'm tagging the question haskell and python because AFAIK those two represent opposite ends of the spectrum (Haskell demanding Bools when you use if, and Python treating None and some "empty" values as Falsy), but feel free to talk about your experience from other languages. Just mention where on the spectrum they stand.

11
  • I'd think the extreme falsey language would be javascript not python . . . May 25, 2013 at 13:21
  • 2
    @WyattBarnett: JavaScript got it from C, where anything can be a Boolean, including a freaking assignment statement. May 25, 2013 at 13:24
  • @MasonWheeler : ceratainly true, on the other hand james.padolsey.com/javascript/truthy-falsey May 25, 2013 at 13:27
  • @WyattBarnett: Yeah, those are essentially the same rules that C follows, with the exception that you can't "box" a number in an object and get Number(0) == true the way you can in JS. (At least, not as a language feature.) May 25, 2013 at 13:32
  • 1
    @Inaimathi: Yeah, but Lisp (and JavaScript, for that matter) has an excuse for that behavior: it's dynamically typed. C isn't. May 25, 2013 at 13:51

5 Answers 5

2

I use them to my advantage in Javascript all the time. In Javascript, the falsy values are undefined, null, false, NaN, 0 and ""

It is just much easier to read:

if( !str ) {

}

instead of

if( str == null || str.length() == 0 ) {

}

or str == null || str.equals("") or bunch of other just as bad equivalents that you need to use in Java.

I do recall an instance where I was bitten by this, doing x || y, when a certain falsy value was desirable as x. But this is very rare.


However, the check is relatively sane in Javascript. Consider PHP, where additionally the string "0", an empty array or, and I quote:

SimpleXML objects created from empty tags

are considered falsy values. Also, NaN is truthy in PHP! So in this mess of completely arbitrary inconsistency, I wouldn't find the truthy/falsy concept as good.

10
  • 1
    I consider "if( !str )" to be bad style. You are not making it clear what kind of value you have here, and if you have null for some reason while it should always be a boolean, the code will happily continue running. May 25, 2013 at 13:50
  • 1
    @JeroenDeDauw it should be a null, undefined, or string. If it's not, it's the callers fault - this is how we think in Javascript culture anyway.
    – Esailija
    May 25, 2013 at 13:52
  • I do prefer static typing (even though my main lang is PHP), so you might be right on this being a cultural difference. May 25, 2013 at 13:55
  • 1
    JS also does some odd things with regard to "0". Specifically, "0" == 0, but !!"0". Which leads to the very odd situation that "0" == 0 && 0 == "" && "0" != "". Once you've decided that 0 is Falsy, and that a number should compare to its stringified version under ==, making "0" Falsy seems more consistent, if anything. Thanks for the insight.
    – Inaimathi
    May 25, 2013 at 13:58
  • 1
    @Inaimathi: Sorry, I guess I wasn't really clear with that. There are two different concepts here. I don't think that, in a strongly typed language, anything but the value false, of type Boolean, should be evaluate as "false". The way that Java (and .NET) screw strings up by allowing you to have a string that contains no information, and yet is not the same as null (the constant that means "no information"), thus making checks for existence that much more complicated, is completely unrelated to the "falsy-ness" issue. May 25, 2013 at 17:33
2

Haskell too has the concept of falsy and I use them all the time.

Assume I have a handful of values and I need to fail if any one of those values are "false" (bools would be false, lists would be empty...). I can use the Maybe monoid to easily check if any of them are considered false based on their type.

True, the "if" statement in Haskell still only allows a boolean test condition, But Haskell makes it easy enough to create your own control structures to circumvent the problem.

The key is that in Haskell they are completely type checked so you know exactly what's happening. I've longed for them in C# but got around it by just explicitly checking for "false"

2

In Python it's more of a something vs nothing concept, and it's incredibly convenient, plus much more readable, to have one's custom classes set to show as nothing (False) if they don't have a meaningful value when used in boolean tests.

Nearly all my own classes support it (lot's of container-type classes).

2

The problem with "falsy" values is that they inevitably lead to ambiguities between in- and out-of-bounds responses: cases where an operation returns a "falsy" value that could mean either failure to produce an answer or success at producing an answer whose value is the "falsy" value.

One familiar example would be Java's Map<K,V>.get(K key) method, which returns null in two situations:

  1. The map doesn't have an entry for the key you asked for.
  2. The map has an entry that maps that key to null.

Contrast Haskell, where not only are a and Maybe a different types, but also Maybe (Maybe a) and so on. In Haskell, if you need to (and most of the time you don't), you can distinguish between Nothing ("outer" failure) and Just Nothing ("inner" failure).

2
  • I'm kinda new to functional programming (via F#, not Haskell) but I thought that it was a requirement for Monad a to equal Monad (Monad a) (from here: ericlippert.com/2013/03/04/monads-part-four). That is, amplifying an amplified type, produces the same amplified type. Considering that Maybe is a monad... Does that apply? Jun 3, 2013 at 22:54
  • 4
    No, Monad m => m (m a) does not have to be isomorphic to Monad m => m a, and is only so in special cases. There just needs to exist a join :: Monad m => m (m a) -> m a operation that obeys the Monad laws. Usually monads are explained in terms of >>=, which applies an a -> m b function "inside" the monad and then collapses the result, but the two operations can be factored out; ma >>= f = join (fmap f ma). And collapsing, in general, destroys some information; Maybe is one example, another one would be concat :: [[a]] -> [a], which destroys the grouping of the nested list.
    – sacundim
    Jun 4, 2013 at 4:40
1

On what principles would you decide to add or exclude them from a language?

I don't think that's the right question. Every language designer has something in mind when they design their language, and that often will dictate some of the answers. For example, if you are designing for type-safety, then you won't allow numbers to be true or false. If you are designing for "easy scripting", you will allow lots of short-cuts.

For example, SQL treats NULL and false as so different that you have to use different operators on them ("is null" vs "= false"). Ruby thinks 0 is true, but Perl thinks it's false.

In Ruby, the set of things that are false is small enough to be easy to remember (Just false and nil).

Where specifically have you used them to your advantage?

When picking up default values from various places:

my_name = env.name || command_line_swich.name || default_name
value = config['value'] || raise("no value found")

Are there any problems you could see them causing off-hand?

Yes. In Perl, doing the above with numbers is a bad idea (because 0 could be valid, but will be ignored because it's false). Even in Ruby, it breaks when you have boolean values.

Are there any rules or finer points in your language/project/team about where it's appropriate or inappropriate to use them?

Not really. We use them wherever we can get away with it, which proves their value.

Not the answer you're looking for? Browse other questions tagged or ask your own question.