.

Tags:

Update: Read also the approach to detect Boolean traps (in JavaScript apps) using a simple script.

The nice thing working for Trolltech was (among others) learning the principles behind the good API. The article Designing Qt-Style C++ API from Matthias 6 years ago is still a good reading till today. The content itself is now expanded into the wiki page API Design Principles.

The major premise behind a good API is rather straightforward:

the code is usually written once but read many times.

When writing the code, the developer has the time she needs to look at the API documentation and digest it. When someone else reads the code (for review or bug fix), she may not always have the API documentation handy. While this is just common sense, wait until you finish reading and see why this important fact is still overlooked these days.

Note: Qt is in C++, but surprisingly the same API design principles apply to the (wonderful) world of JavaScript, which is the focus in this blog post.

George Boole, inventor of the Boolean logic.

For this particular discussion, I’ll pick my favorite API design mistake: boolean trap. On this topic, the above API Design Principle wiki page says that

it’s almost invariably a mistake to add a bool parameter to an existing function

Let’s start with the textbook example: guess what this code means?

widget.repaint(false);

Without looking at the documentation, the usual suspect is don’t repaint the widget. Then, you look at the documentation and it refers the function argument as immediate, which is true if you want immediate painting or false for deferred painting. Thus, the correct behavior implied by the above code is actually repaint this widget later, which is miles away from your initial guess.

One possible solution to this problem is to use explicit function argument. In the C++ world, this can be solved using enum, e.g. widget.repaint(WidgetClass::Deferred). In the JavaScript world, the alternative is using an object literal such as,

widget.repaint({ immediate: false });

or the more verbose variant:

widget.repaint({ mode: "immediate" });

or just create a different function for that purpose:

widget.repaintLater();

There will be a concern of performance since an object is more expensive than just a simple boolean literal. Thus, profile your code carefully and set a sensible compromise if this above line is in your hot path. On the other hand, I also do believe that modern future JavaScript engines would be smart enough to optimize such usages that the speed penalty is negligible.

Another classic is the confusion during construction. Your user interface needs a bunch of sliders to allow the user to choose some values. Here is one line in the code for you to review:

var opacitySlider = new Slider(true);

Mysteriously, there are also lines similar to:

var volumeSlider = new Slider(false);

It turns out that true there means a horizontal slider and false means a vertical slider. Of course, the easiest way to clear this confusion is to actually name the object HorizontalSlider and VerticalSlider and get rid of the boolean argument. Heck, who knows someday you’ll need a diagonal slider!

You may scream, "Of course, I won’t be too idiot to make those rookie mistakes!". Well, in the following paragraphs I’ll give examples of actual boolean traps in the API of several well-known JavaScript libraries and frameworks out there (I try to be unbiased). Consider that there are millions of developers using the libraries in real-world web applications, imagine the exposure of the traps.

For each of this case, imagine you are doing a code review. Your amazing coworker wants to commit a patch and he consults you to check your opinion.

to be or not to be

This is the same as the textbook example, but coming from a real framework:

stackView.updateHeight(false);

Yes, that false again refers to immediate or not. To the untrained developer, the above line feels like don’t update the height. A real crazy one might even stretch it to update the width!

Here is another one. To facilitate easy iteration of child widgets, you can use next() function which would get you the next sibling. But then, the code looks like:

widget.next(true);

which actually does the extra magic (because of the true value) that the very first child widget will be returned if you hit the last one. In other words, true there stands for circular. An innocent value which does too much behind your back. Well, good luck trying to review that kind of code.

Another dangerous venture:

widget.destroy(false);

which potentially leads you to think don’t destroy this widget. You can’t be more wrong, the function actually still destroys your widget, but it leaves the DOM associated with the widget intact. Only if the argument is true then actually every related DOM pieces is also tore torn down.

optionally undecipherable

Now that we have the slider for the UI, we need to preset the value:

volumeSlider.setValue(90, false);

Another boolean horror! The documentation reveals that false there indicates that the slider should not animate the movement of its indicator from the old value to the new value. By default, it will show the animation but since we want to set the initial value, the animation will be distracting and needs to be off. How about writing it like this instead?

volumeSlider.setValue(90, { animation: false } );

There is this list view of all your customers. We want to find out who live in a certain city. Can you guess what the last optional argument refers to?

customerView.filter('address', 'sunnyvale', false);

Oh, apparently the API documentation refers it to caseSensitive! Just by looking at it, this is not obvious and it could mean an entirely different thing, anything from exactMatch to highlightMatchedLine. One possible workaround:

customerView.filter('address', 'sunnyvale', { caseSensitive: false });

the more, the merrier

While one boolean argument is already confusing, two boolean arguments can’t be more fun.

To handle layout, often there is a line of code that looks like:

cmp.setCentered(true, false);

Again, a trip to the API doc enlightens the reviewer that the function signature is actually setCentered(centered, autoUpdate). This is confusing as setCentered(centered) only is probably fine, it’s just like a property setter, but the interplay of the autoUpdate argument forces the brain to think harder.

Note that a pair of values like that, especially in the context of centering/geometry purpose, might provoke a different interpretation: center vertically and horizontally. This is arguably the most sensible one which comes to mind if one sees that code.

Here is another one:

menu.stop(true, false);

The boolean values there refer to clear the animation queue or not and go to the animation or not, respectively. They are not even remotely related. What is your best educated guess if you did not know this beforehand?

Of course, why stop at two if you can have more?

event.initKeyEvent("keypress", true, true, null, null,
    false, false, false, false, 9, 0);

double negative

Now, coming back to property setter, this is one valid use of boolean argument, e.g. dialogBox.setVisible(true). However, care must be taken so that there is no such double negative. Especially for non-native speakers, double negative requires an extra careful measure to make sure that the right meaning is communicated.

If I wake you at midnight and ask you this question "if invisible is false, does that mean my component is shown or hidden?", there is a chance you answer it incorrectly.

Real-world examples of double negative follow:

volumeSlider.setThumbsDisabled(false);
component.setDisabled(false);
filter.setCaseInsensitive(false);

Would you be less confused if this is what you read instead?

volumeSlider.setThumbsEnabled(true);
component.setEnabled(true);
filter.setCaseSensitive(true);

The same principle applies to active vs inactive, modified vs unmodified, defined vs undefined, selected vs unselected, etc.

By now, hopefully you got the idea of various risky uses of boolean argument. Feel free to share your favorite freak-out moment as you encounter such a similar trap.

Most importantly, next time you design an API function, remember George Boole and don’t let him down!

Update: Some people on Reddit pointed out that they would not interpret widget.repaint(false) as do not repaint. First of all, it’s subjective. In some languages it can be understood as repaint not, which is effectively a negation. Also, the context might pollute, e.g. if there is fooWidget.show(false) (which means do not show) right before, then it may influence a similar conclusion for the repaint issue. I was also not clear that any crazy possible interpretations are just examples, substitute them with your own imaginations. The fact that everyone can propose a different interpretation is the premise: ambiguity begets insanity.

  • Blacktiger

    Even better, if you design your api correctly you can avoid the use of boolean setters. Instead of setVisible(visibility), try show() and hide().

    • ariya

      Boolean setter is to match its boolean getter. Having the getter, e.g. isVisible(), can lead to shorter code, e.g. vs isShown() and isVisible(). However, that needs to be evaluated on a case-by-case basis.

    • http://dan.cx/ Daniel15

      For some reason, Java’s Swing library did the opposite – Deprecated .hide() and .show() in favour of .setVisible(bool)

      • http://www.storytotell.org Daniel Lyons

        I tend to agree that proper OO design is to avoid using getters and setters. However, my day job is in Java. Unfortunately, for better or worse (mostly worse) the hammer we use in lieu of duck typing is making our objects beans and using the bean reflection system.

        My boss wrote an absolutely gorgeous OO library for dealing with our application domain. There was an upper-level mandate to use JSF for our web apps. The net result is that I spend a great deal of time making bean-like wrappers around my boss’s beautiful library, because JSF is fundamentally about propagating changes between beans, and it takes a lot of control away from you.

        I don’t get to do Swing, so I’m just guessing here, but I wouldn’t be surprised if the same kind of “design” pressure is going on in the Swing world and motivated this deprecation of show/hide in favor of bean properties.

    • https://plus.google.com/103858861030942060718 monitron

      I like it when APIs have a .setVisible(bool) as well as .show() and .hide() convenience methods. That way, if I want to toggle visibility or set it based on a boolean expression, I don’t need to do anything gross. This comes up fairly often in my JavaScript.

  • Blacktiger

    Even better, if you design your api correctly you can avoid the use of boolean setters. Instead of setVisible(visibility), try show() and hide().

    • ariya

      Boolean setter is to match its boolean getter. Having the getter, e.g. isVisible(), can lead to shorter code, e.g. vs isShown() and isVisible(). However, that needs to be evaluated on a case-by-case basis.

    • http://dan.cx/ Daniel15

      For some reason, Java’s Swing library did the opposite – Deprecated .hide() and .show() in favour of .setVisible(bool)

      • http://www.storytotell.org Daniel Lyons

        I tend to agree that proper OO design is to avoid using getters and setters. However, my day job is in Java. Unfortunately, for better or worse (mostly worse) the hammer we use in lieu of duck typing is making our objects beans and using the bean reflection system.

        My boss wrote an absolutely gorgeous OO library for dealing with our application domain. There was an upper-level mandate to use JSF for our web apps. The net result is that I spend a great deal of time making bean-like wrappers around my boss’s beautiful library, because JSF is fundamentally about propagating changes between beans, and it takes a lot of control away from you.

        I don’t get to do Swing, so I’m just guessing here, but I wouldn’t be surprised if the same kind of “design” pressure is going on in the Swing world and motivated this deprecation of show/hide in favor of bean properties.

    • https://plus.google.com/103858861030942060718 monitron

      I like it when APIs have a .setVisible(bool) as well as .show() and .hide() convenience methods. That way, if I want to toggle visibility or set it based on a boolean expression, I don’t need to do anything gross. This comes up fairly often in my JavaScript.

  • http://theamiableapi.com Ferenc Mihaly

    Many great examples to illustrate how Boolean API parameters destroy code readability. The one thing I would like to add is that often the presence of a Boolean parameter indicates a hidden if statement in the implementation. By passing either true or false the caller controls which path the implementation takes.

    That the caller controls the path the implementation takes could be made explicit by providing two functions instead of one, just like you showed with the widget.RepaintLater() example. This results in more readable client code, since the if statement moves where it logically belongs.

    Some would argue that increased number of methods increases API complexity. The counter-argument is that if a Boolean parameter significantly alters method behavior, it is essentially two methods merged into one. It does not make the API any simpler, just more confusing.

  • http://theamiableapi.com Ferenc Mihaly

    Many great examples to illustrate how Boolean API parameters destroy code readability. The one thing I would like to add is that often the presence of a Boolean parameter indicates a hidden if statement in the implementation. By passing either true or false the caller controls which path the implementation takes.

    That the caller controls the path the implementation takes could be made explicit by providing two functions instead of one, just like you showed with the widget.RepaintLater() example. This results in more readable client code, since the if statement moves where it logically belongs.

    Some would argue that increased number of methods increases API complexity. The counter-argument is that if a Boolean parameter significantly alters method behavior, it is essentially two methods merged into one. It does not make the API any simpler, just more confusing.

  • http://the-user.org The User

    Boolean Algebras are not limited to binary true/false, thus diagonal sliders might even be possible with boolen values, too, but that is not that kind of booleans implemented in most languages. ;)

  • http://the-user.org The User

    Boolean Algebras are not limited to binary true/false, thus diagonal sliders might even be possible with boolen values, too, but that is not that kind of booleans implemented in most languages. ;)

  • Christoph Bartoschek

    Whenever I have to pass a bool parameter to a C++ function, I use a comment to indicate the name:

    rectangle_set.union(set, /* ignore_one_dim = */ true);

    • b00g

      Excellent! Instead of merely being ambiguous, that is completely unintelligible!

  • Christoph Bartoschek

    Whenever I have to pass a bool parameter to a C++ function, I use a comment to indicate the name:

    rectangle_set.union(set, /* ignore_one_dim = */ true);

    • b00g

      Excellent! Instead of merely being ambiguous, that is completely unintelligible!

  • blah

    I get what you’re saying, but many of these examples are not convincing. For the various examples taking a single boolean argument, I would never think false meant take no action; the function would just not be called if no action was desired. I do like the object-parameter suggestion for readability (reminds me of Python’s calling mechanism), although I don’t see why that’s only applicable for boolean arguments. The nulls, 9, and 0 passed to initKeyEvent are just as opaque as the boolean at a glance.

    • ariya

      It always depends on the context. The example I have given was not the only possible interpretation, it is just one of the most possible crazy ones. Consider also non-English speakers as true/false values are associated heavily with yes/no combo. And yes, there is at least one toolkit where Show(false) means “do not show”.
      I agree that the problem with obscure parameters does not apply only to booleans (I never implied otherwise). Matthias’ original article has a section called “Convenience Trap” that discuss this.

    • Mike

      Unfortunately, “blah”, you’re incorrect. Several APIs do use the format of doSomething(false) to mean precisely, “do nothing”. The bools in those cases are actually negation of the entire method operation! It’s confusing and a poor way of writing code.

  • blah

    I get what you’re saying, but many of these examples are not convincing. For the various examples taking a single boolean argument, I would never think false meant take no action; the function would just not be called if no action was desired. I do like the object-parameter suggestion for readability (reminds me of Python’s calling mechanism), although I don’t see why that’s only applicable for boolean arguments. The nulls, 9, and 0 passed to initKeyEvent are just as opaque as the boolean at a glance.

    • ariya

      It always depends on the context. The example I have given was not the only possible interpretation, it is just one of the most possible crazy ones. Consider also non-English speakers as true/false values are associated heavily with yes/no combo. And yes, there is at least one toolkit where Show(false) means “do not show”.
      I agree that the problem with obscure parameters does not apply only to booleans (I never implied otherwise). Matthias’ original article has a section called “Convenience Trap” that discuss this.

    • Mike

      Unfortunately, “blah”, you’re incorrect. Several APIs do use the format of doSomething(false) to mean precisely, “do nothing”. The bools in those cases are actually negation of the entire method operation! It’s confusing and a poor way of writing code.

  • You could also create a temporary boolean parameter with a useful name to pass to the function for readability.
    It will usually be used for the actual decision making regarding the function’s use.

    • ariya

      Good trick!

  • You could also create a temporary boolean parameter with a useful name to pass to the function for readability.
    It will usually be used for the actual decision making regarding the function’s use.

    • ariya

      Good trick!

  • brendan

    My first thought when seeing setState(true, false), will my computer break from the paradox?

  • brendan

    My first thought when seeing setState(true, false), will my computer break from the paradox?

  • Girish

    Despite the article we managed to let through QWidget::focusNextPrevChild(bool) :-) Apart from using a bool argument, it also uses an abbreviation which shouldn’t be used in public API (unless universally recognized like XML, DOM etc).

  • Girish

    Despite the article we managed to let through QWidget::focusNextPrevChild(bool) :-) Apart from using a bool argument, it also uses an abbreviation which shouldn’t be used in public API (unless universally recognized like XML, DOM etc).

  • Soulwave

    Take a look at Objective-C:

    [self.navigationConroller pushViewController:myViewController animated:YES];

    Hard to get at first, but then I got the idea of their principle, make function arguments separated by different words, which are part of the prototype of the function “pushViewController:animated:”. For some reason, I can’t look at normal, comma-separated functions the same way.

    • http://blog.ivandemarino.me IvanDM

      Well, ultimately what you demonstrate is that it’s ALSO a matter of language.
      Obj-C does indeed provide a very verbose Signaturing-style, hence for those can be really hard to get confused, so “Boolean”, in my opinion, would be fine to be used.

      I’d say, any language without the support for naming parameters, so that you can’t qualify what your boolean will do, is very much prone to the issues described by Ariya.

      Another language that does something close to Obj-C? Python.

  • Soulwave

    Take a look at Objective-C:

    [self.navigationConroller pushViewController:myViewController animated:YES];

    Hard to get at first, but then I got the idea of their principle, make function arguments separated by different words, which are part of the prototype of the function “pushViewController:animated:”. For some reason, I can’t look at normal, comma-separated functions the same way.

    • http://blog.ivandemarino.me IvanDM

      Well, ultimately what you demonstrate is that it’s ALSO a matter of language.
      Obj-C does indeed provide a very verbose Signaturing-style, hence for those can be really hard to get confused, so “Boolean”, in my opinion, would be fine to be used.

      I’d say, any language without the support for naming parameters, so that you can’t qualify what your boolean will do, is very much prone to the issues described by Ariya.

      Another language that does something close to Obj-C? Python.

  • v0idnull

    Interesting. I’ve never really considered this before, even though I’ve always had a preference for named parameters in functions. I’ve just never thought about why before… just seemed more intuitive and that was that.

  • v0idnull

    Interesting. I’ve never really considered this before, even though I’ve always had a preference for named parameters in functions. I’ve just never thought about why before… just seemed more intuitive and that was that.

  • http://devgotchas.grgventures.com G

    What programmers are asleep at midnight?

  • http://devgotchas.grgventures.com G

    What programmers are asleep at midnight?

  • Alex

    The Win32 is a big offender in this area, especially if you include function calls with 4-5 NULL parameters. Interesting point above about Objective C partly designing the problem out of the language.

  • Alex

    The Win32 is a big offender in this area, especially if you include function calls with 4-5 NULL parameters. Interesting point above about Objective C partly designing the problem out of the language.

  • https://github.com/blackberry/Alice Laurent Hasson

    I think we are all compromising right left and center in the name of performance. But i ask this: is it better to have an API that is consistent everywhere, or one that does the right thing potentially differently in different places? If a boolean param is “better” because of some performance reasons (actual performance or verbosity), but it’s not performance critical somewhere else, you end up with two paradigms in your API set. I have always struggled with that and generally went for the performance, and relied on consistency to lesser the cognitive pain.

    One issue i have struggled with Alice is whether we should pass parameters traditionally (which code completion and code documentation can manage well), or pass in objects (which foil JSDocs and code completion engines), or even, as a special case in Alice because of its CSS likeness, simply a flat string. String was dismissed because of performance. Parameter Objects were dismissed because of JSDocs and code completion concerns.

    Opinions?

    • ariya

      There is no silver bullet. Try both approaches and write a lot of examples, using each approach. Ask someone else to review the code and see how he reacts.

      In short, write as much as code to exercise the API and you’ll find the enlightment :)

    • http://theamiableapi.com Ferenc Mihaly

      Ariya is spot on that writing client code that uses the API is the best way of finding out what design works best, but consistency is also important. If you insist on using what looks like the best design approach for each part, you may end up with frustrating inconsistencies in the API as a whole. I would say consistency is worth making a few carefully chosen compromises. Designing APIs is all about considering such trade-offs. As Ariya said: “no silver bullets”.

  • https://github.com/blackberry/Alice Laurent Hasson

    I think we are all compromising right left and center in the name of performance. But i ask this: is it better to have an API that is consistent everywhere, or one that does the right thing potentially differently in different places? If a boolean param is “better” because of some performance reasons (actual performance or verbosity), but it’s not performance critical somewhere else, you end up with two paradigms in your API set. I have always struggled with that and generally went for the performance, and relied on consistency to lesser the cognitive pain.

    One issue i have struggled with Alice is whether we should pass parameters traditionally (which code completion and code documentation can manage well), or pass in objects (which foil JSDocs and code completion engines), or even, as a special case in Alice because of its CSS likeness, simply a flat string. String was dismissed because of performance. Parameter Objects were dismissed because of JSDocs and code completion concerns.

    Opinions?

    • ariya

      There is no silver bullet. Try both approaches and write a lot of examples, using each approach. Ask someone else to review the code and see how he reacts.

      In short, write as much as code to exercise the API and you’ll find the enlightment :)

    • http://theamiableapi.com Ferenc Mihaly

      Ariya is spot on that writing client code that uses the API is the best way of finding out what design works best, but consistency is also important. If you insist on using what looks like the best design approach for each part, you may end up with frustrating inconsistencies in the API as a whole. I would say consistency is worth making a few carefully chosen compromises. Designing APIs is all about considering such trade-offs. As Ariya said: “no silver bullets”.

  • http://www.josscrowcroft.com Joss

    Awesome article! Reminds me of Backbone.js: `Model.set({a:1}, {silent: true})`

    Always wondered why that wasn’t just `.set({a:1}, true)` – this post pretty much sums that up.

    It’s actaully always been a gripe of mine with WordPress API functions in PHP – eg. `single_cat_title(”, false)` – if I haven’t read the docs in a while, it’s a very simple “WTF” response.

    (those args were `$prefix, $echo` – of all things.)

    • ariya

      Good spot on WordPress, Joss! And I can certainly related to that, every time I look at the template code, I wish I were not forced to do it.

  • http://www.josscrowcroft.com Joss

    Awesome article! Reminds me of Backbone.js: `Model.set({a:1}, {silent: true})`

    Always wondered why that wasn’t just `.set({a:1}, true)` – this post pretty much sums that up.

    It’s actaully always been a gripe of mine with WordPress API functions in PHP – eg. `single_cat_title(”, false)` – if I haven’t read the docs in a while, it’s a very simple “WTF” response.

    (those args were `$prefix, $echo` – of all things.)

    • ariya

      Good spot on WordPress, Joss! And I can certainly related to that, every time I look at the template code, I wish I were not forced to do it.

  • http://www.joshmatthews.net Josh Matthews

    I was looking into ways to avoid boolean arguments in the Firefox code recently, and came up with this interesting template trick:

    template
    class BooleanValue {
    public:
    BooleanValue(const PRBool& aValue) : mValue(aValue) {}
    operator const PRBool&() const { return mValue; }
    private:
    PRBool mValue;
    };

    template
    class TrueValue : public BooleanValue {
    public:
    TrueValue() : BooleanValue(PR_TRUE) {}
    };
    template
    class FalseValue : public BooleanValue {
    public:
    FalseValue() : BooleanValue(PR_FALSE) {}
    };

    This can be used as follows:

    class ShouldIgnoreSuppression;
    class ShouldIgnoreRootScrollFrame;

    static nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
    const booleanValue& aIgnoreSuppression,
    const booleanValue& aIgnoreRootScrollFrame);

    typedef TrueValue IgnorePaintSuppression;
    typedef FalseValue RespectRootScrollFrame;

    nsIFrame* frame = GetFrameForPoint(aFrame, aPt, IgnorePaintSuppression(), RespectRootScrollFrame());

    The benefit of this method over a traditional enumerated value is that you can’t put accidentally use the values in the wrong order without the compiler throwing an error. If the compiler can prevent a source of bugs, I definitely think it’s worth the extra verbosity. The increase in code size at -O3 was also negligible, making this solution even more attractive.

    • ariya

      I agree with the strong typing trick, I used a very similar approach in the past.

      Too bad we can’t do the same with JavaScript yet.

  • http://www.joshmatthews.net Josh Matthews

    I was looking into ways to avoid boolean arguments in the Firefox code recently, and came up with this interesting template trick:

    template
    class BooleanValue {
    public:
    BooleanValue(const PRBool& aValue) : mValue(aValue) {}
    operator const PRBool&() const { return mValue; }
    private:
    PRBool mValue;
    };

    template
    class TrueValue : public BooleanValue {
    public:
    TrueValue() : BooleanValue(PR_TRUE) {}
    };
    template
    class FalseValue : public BooleanValue {
    public:
    FalseValue() : BooleanValue(PR_FALSE) {}
    };

    This can be used as follows:

    class ShouldIgnoreSuppression;
    class ShouldIgnoreRootScrollFrame;

    static nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
    const booleanValue& aIgnoreSuppression,
    const booleanValue& aIgnoreRootScrollFrame);

    typedef TrueValue IgnorePaintSuppression;
    typedef FalseValue RespectRootScrollFrame;

    nsIFrame* frame = GetFrameForPoint(aFrame, aPt, IgnorePaintSuppression(), RespectRootScrollFrame());

    The benefit of this method over a traditional enumerated value is that you can’t put accidentally use the values in the wrong order without the compiler throwing an error. If the compiler can prevent a source of bugs, I definitely think it’s worth the extra verbosity. The increase in code size at -O3 was also negligible, making this solution even more attractive.

    • ariya

      I agree with the strong typing trick, I used a very similar approach in the past.

      Too bad we can’t do the same with JavaScript yet.

  • http://blog.ivandemarino.me IvanDM

    There is an API I use almost every day in my current job, and that the first time I met made me scream and wanted to “cut heads”.

    YUI.Attribute. This powerful library, integrated in the guts of YUI 3, has a tricky, hard to guess behaviour that drives you mad when you stumble upon it the first time.

    The library is designed to extend a JS Object with a set of “attributes”, that are enriched with get/set and a lot of “filtering” methods, all configurable. It’s documented here: http://yuilibrary.com/yui/docs/attribute/. Anyway, would you ever guess:

    myObjectWithAttrs.set("key", "new value");
    myObjectWithAttrs <---- at this stage, the value has not been set YET
    myObjectWithAttrs.get("key") <--- the previous value is ACTUALLY set, then returned
    

    Why? Ask Yahoo developers, they might know.
    The problem was that this behaviour was NOT documented in any way, and only posting comments on their forum and swearing at them on Twitter made them update the documentation with a nice:

    NOTE: When extending Base, all attributes are added lazily, so this flag can be used to over-ride lazyAdd behavior for specific attributes.

    Still, even if there is a documentation, I do believe that such “feature” should be disabled by default.

  • http://blog.ivandemarino.me IvanDM

    There is an API I use almost every day in my current job, and that the first time I met made me scream and wanted to “cut heads”.

    YUI.Attribute. This powerful library, integrated in the guts of YUI 3, has a tricky, hard to guess behaviour that drives you mad when you stumble upon it the first time.

    The library is designed to extend a JS Object with a set of “attributes”, that are enriched with get/set and a lot of “filtering” methods, all configurable. It’s documented here: http://yuilibrary.com/yui/docs/attribute/. Anyway, would you ever guess:

    myObjectWithAttrs.set("key", "new value");
    myObjectWithAttrs <---- at this stage, the value has not been set YET
    myObjectWithAttrs.get("key") <--- the previous value is ACTUALLY set, then returned
    

    Why? Ask Yahoo developers, they might know.
    The problem was that this behaviour was NOT documented in any way, and only posting comments on their forum and swearing at them on Twitter made them update the documentation with a nice:

    NOTE: When extending Base, all attributes are added lazily, so this flag can be used to over-ride lazyAdd behavior for specific attributes.

    Still, even if there is a documentation, I do believe that such “feature” should be disabled by default.

  • Ernest Shulikovski

    Robert C. Martin wrote about this in his “Clean Code” book some time ago, but this post is much more elaborate on the topic.
    To begin with, the bool param is a strong signal that function has to do more than one thing.

  • Ernest Shulikovski

    Robert C. Martin wrote about this in his “Clean Code” book some time ago, but this post is much more elaborate on the topic.
    To begin with, the bool param is a strong signal that function has to do more than one thing.

  • http://users.ecs.soton.ac.uk/cjg/ Christopher Gutteridge

    I god, how I have sinned in my foolish youth.

    I now think back to those terrible $foo->bar( 0,0,1 ); functions and shudder.

    Good article for anyone writing APIs. Thanks.

  • http://users.ecs.soton.ac.uk/cjg/ Christopher Gutteridge

    I god, how I have sinned in my foolish youth.

    I now think back to those terrible $foo->bar( 0,0,1 ); functions and shudder.

    Good article for anyone writing APIs. Thanks.

  • Pingback: hall of api shame: boolean trap | don't code today | Javascript Programming | Scoop.it

  • Pingback: hall of api shame: boolean trap | don't code today | Javascript Programming | Scoop.it

  • EricT

    I learned to avoid boolean parameters from Writing Solid Code (Steve Maguire, 1993), which has a lot of very pragmatic advice (apparently hard won) about how to avoid bugs, with a significant emphasis on writing APIs that are both readable *and* writable. He dissects a few of the C library routines, such as realloc (the one function memory manager), and shows how they could have been written to make certain common mistakes nearly impossible. One of my favorite excerpts is the opening paragraphs of a chapter titled Candy Machine Interfaces (http://tetzfiles.com/eric/candyMachineInterfaces.html).

    • ariya

      Eric, the candy machine story is classic! Thanks for sharing.

  • EricT

    I learned to avoid boolean parameters from Writing Solid Code (Steve Maguire, 1993), which has a lot of very pragmatic advice (apparently hard won) about how to avoid bugs, with a significant emphasis on writing APIs that are both readable *and* writable. He dissects a few of the C library routines, such as realloc (the one function memory manager), and shows how they could have been written to make certain common mistakes nearly impossible. One of my favorite excerpts is the opening paragraphs of a chapter titled Candy Machine Interfaces (http://tetzfiles.com/eric/candyMachineInterfaces.html).

    • ariya

      Eric, the candy machine story is classic! Thanks for sharing.

  • http://NA Hanibal Smith

    ” she may not always have the API documentation handy”

    What, is this some new thing, where only women read documentation?

    • ariya

      It’s actually a very interesting and progressive debate, google for “gender neutral pronoun”. See e.g. http://www.feld.com/wp/archives/2011/06/the-need-for-a-gender-neutral-pronoun.html (and the prominent example from Ben Horowitz, linked from there) and many others.

      Reading some of these discussions inspired me to experiment with “she” as the neutral pronoun.

      In short: yes, I did put some thought before using “she”.

    • http://timothy.green.name/ Timothy (TRiG)

      *Blink*

      And the times when only men read documentation pass you by unnoticed? Interesting.

      TRiG.

  • http://NA Hanibal Smith

    ” she may not always have the API documentation handy”

    What, is this some new thing, where only women read documentation?

    • ariya

      It’s actually a very interesting and progressive debate, google for “gender neutral pronoun”. See e.g. http://www.feld.com/wp/archives/2011/06/the-need-for-a-gender-neutral-pronoun.html (and the prominent example from Ben Horowitz, linked from there) and many others.

      Reading some of these discussions inspired me to experiment with “she” as the neutral pronoun.

      In short: yes, I did put some thought before using “she”.

  • http://www.diaryofaninja.com Doug Rathbone

    Great post – happy to have found your blog, will definitely be subscribing to later posts…

    hats off to George Boole!

  • http://www.diaryofaninja.com Doug Rathbone

    Great post – happy to have found your blog, will definitely be subscribing to later posts…

    hats off to George Boole!

  • JM

    Assumption is the mother of all fuckups.

  • JM

    Assumption is the mother of all fuckups.

  • Framp

    Great article :)
    I just wanted to add a little js tip:

    When we have boolean ambiguities in our library we can always write something like:

    var MyLibrary = {
    Good: true,
    Bad: false,
    [...]
    }

    [...]

    action.setType(MyLibrary.Good)

    I believe this should be lighter than handling an object per argument

  • Framp

    Great article :)
    I just wanted to add a little js tip:

    When we have boolean ambiguities in our library we can always write something like:

    var MyLibrary = {
    Good: true,
    Bad: false,
    [...]
    }

    [...]

    action.setType(MyLibrary.Good)

    I believe this should be lighter than handling an object per argument

  • Foobar

    Torn down not tore down

  • Foobar

    Torn down not tore down

  • Philippe

    The following method is explicit and safe, has no performance cost at all, and is easy…

    #define STRONG_BOOLEAN(name)
    namespace name
    {
    enum ENum { True = true, False = false };
    typedef ENum Bool;
    inline bool ToBool(const Bool& t) { return t != 0; }
    }

    For instance:

    STRONG_BOOLEAN(BSave)
    STRONG_BOOLEAN(BBackup)

    void foo(BSave::Bool save, BBackup::Bool backup)
    {
    }

    void main()
    {
    foo(BSave::True, BBackup::False);
    }

  • Philippe

    The following method is explicit and safe, has no performance cost at all, and is easy…

    #define STRONG_BOOLEAN(name)
    namespace name
    {
    enum ENum { True = true, False = false };
    typedef ENum Bool;
    inline bool ToBool(const Bool& t) { return t != 0; }
    }

    For instance:

    STRONG_BOOLEAN(BSave)
    STRONG_BOOLEAN(BBackup)

    void foo(BSave::Bool save, BBackup::Bool backup)
    {
    }

    void main()
    {
    foo(BSave::True, BBackup::False);
    }

  • Pingback: Pedro Newsletter 29.08.2011 « Pragmatic Programmer Issues – pietrowski.info

    • http://www.bashstreetkids.com Dal

      Why bother putting in a function call with a paramater of false if it isn’t going to do anything? Seems a bit pointless to me…

      • ariya

        This is a common pattern due to the use of property value, e.g. to write code without the need to have a branch: widget.repaint(parent.isDirty).

  • Pingback: Pedro Newsletter 29.08.2011 « Pragmatic Programmer Issues – pietrowski.info

    • http://www.bashstreetkids.com Dal

      Why bother putting in a function call with a paramater of false if it isn’t going to do anything? Seems a bit pointless to me…

      • ariya

        This is a common pattern due to the use of property value, e.g. to write code without the need to have a branch: widget.repaint(parent.isDirty).

  • Wade

    People do this because the code to create a vertical scrollbar is almost exactly the same as the code to create a horizontal one, and the “don’t repeat yourself” principle says you should not have two almost identical functions.

    Making a clear distinction between the interface and the implementation helps you have a good interface design and a good implementation. In C++, I would do this:

    public CreateVerticalScroller() { return CreateScroller_(true); }
    public CreateHorizontalScroller(){ return CreateScroller_(false); }
    private CreateScroller_( bool vertical );

    The people who use your interface see two public functions, each clearly named by what it does.
    The people who work on your implementation see one private function for creating scrollers, with the tiny differences between the two types encapsulated in a few “if” conditions.
    If, later on, you need to create diagonal scrollers, you create a new public function, and do whatever is needed in the implementation to make it work cleanly.

  • Wade

    People do this because the code to create a vertical scrollbar is almost exactly the same as the code to create a horizontal one, and the “don’t repeat yourself” principle says you should not have two almost identical functions.

    Making a clear distinction between the interface and the implementation helps you have a good interface design and a good implementation. In C++, I would do this:

    public CreateVerticalScroller() { return CreateScroller_(true); }
    public CreateHorizontalScroller(){ return CreateScroller_(false); }
    private CreateScroller_( bool vertical );

    The people who use your interface see two public functions, each clearly named by what it does.
    The people who work on your implementation see one private function for creating scrollers, with the tiny differences between the two types encapsulated in a few “if” conditions.
    If, later on, you need to create diagonal scrollers, you create a new public function, and do whatever is needed in the implementation to make it work cleanly.

  • http://raptureinvenice.com John Blanco

    Interesting tidbit on the double-negative. This is LOUD and CLEAR in IOS, where UIKit demands you specify visibility with [myControl setHidden:YES]. It’s mind-bending. In my iBoost framework, I add the -setVisible method to correct it, but most every programmer out there is using the hidden param.

    • ariya

      Spot on, John!

  • http://raptureinvenice.com John Blanco

    Interesting tidbit on the double-negative. This is LOUD and CLEAR in IOS, where UIKit demands you specify visibility with [myControl setHidden:YES]. It’s mind-bending. In my iBoost framework, I add the -setVisible method to correct it, but most every programmer out there is using the hidden param.

    • ariya

      Spot on, John!

  • http://andika-lives-here.blogspot.com/ andika

    Eye opening article! Thanks for writing this.

  • http://andika-lives-here.blogspot.com/ andika

    Eye opening article! Thanks for writing this.

  • Manny Brach

    What a bunch of junk. Write in an IDE that shows you the definition and forget about this horribly verbose way of coding. You’ll need the docs one way or another. If a function has 3 params, how will you know what they mean without the docs? Just because you assume that the params mean x by their type, how can you know they do? You’ll need the docs. Assumptions make bugs.

    Connect(’127.0.0.1′,’Jake’,’hwuq026′,’/info/data’);

    What does that mean? What if the username is ‘hwuq026′? How do you know? Maybe there is no username. And ‘/info/data’, is that some resource we’re accessing? Are we connecting to localhost? Are we sending the data item ’127.0.0.1′ to somewhere? It may be a call back address. Maybe connect always connects to my.test.com… But you’ll have to consult the docs. The code uses the API, it doesn’t describe it. It shouldn’t describe it. It should be described where it’s defined, not where it’s used. If you’re calling a function hundreds of times, writing so verbosely is just total overkill. Anyone who reads code should be familiar with the calls being made. If you’re trying to figure out what some piece of code does, you’re expected to know where it’ll run, what language it’s in, what libs and frameworks it uses, etc. If you cannot meet those expectations, then you’re not qualified to read that code until you brush up.

    Just because a property is called “Visibility” doesn’t mean it shows or hides something. Maybe Visibility=500 just means you can see 500 meters.

    Good luck deducing what a function does by the signature at the call site…

    • ariya

      It may sound strange but actually I fully agree with your sentiments here.

      If you allow me to summarize it, basically it boils down to:

      * Use an IDE (or in general, the best tools) when writing the code
      * If you can’t figure out what the code does, don’t deduce. Just consult the docs

      Maybe I misunderstand you, but is there anything in the blog post (read:”junk”) actually suggests that you should NOT do those two points?

      Also, since this post specifically addresses the issue of boolean parameter (and not other types), what if we tweak your example to be like this?

      Connect(’127.0.0.1′,’Jake’,’hwuq026′,’/info/data’, true);

      Assume you are familiar with calls being made. You have seen/reviewed the same calls in other places, over and over again. It’s imprinted in your brain that 127.0.0.1 is the server address, ‘Jake’ is the login, etc etc (you know it because you looked up the API docs a dozen time). It’s hard to mix it up and mistakenly think that ‘Jake’ is the server name and ’127.0.0.1′ is the login. But chance is, you can’t always accurately recall what the last argument ‘true’ (or ‘false’ in some other cases) actually does.

      It would be of course a bless if everyone of us has a photographic memory. In reality, we don’t.

      I wish every software engineer thinks exactly like you in terms of code review. I can imagine that when you read any piece of code (either because you need to review it or because you have to write a module that interacts with it or because of some other reasons), you will spot every single function call in that code, look up the API docs (or barring that, search the Internet for more info), analyze how each function works, and finally give your approval result.

      • DigDug2k

        If you’re ever reviewing code and see someone passing ambiguous string literals like this, you should r- it instantly. But odds are, they’re the same type of programmer who flails their arms wildly if they ever have to do anything outside and IDE.

  • Manny Brach

    What a bunch of junk. Write in an IDE that shows you the definition and forget about this horribly verbose way of coding. You’ll need the docs one way or another. If a function has 3 params, how will you know what they mean without the docs? Just because you assume that the params mean x by their type, how can you know they do? You’ll need the docs. Assumptions make bugs.

    Connect(’127.0.0.1′,’Jake’,’hwuq026′,’/info/data’);

    What does that mean? What if the username is ‘hwuq026′? How do you know? Maybe there is no username. And ‘/info/data’, is that some resource we’re accessing? Are we connecting to localhost? Are we sending the data item ’127.0.0.1′ to somewhere? It may be a call back address. Maybe connect always connects to my.test.com… But you’ll have to consult the docs. The code uses the API, it doesn’t describe it. It shouldn’t describe it. It should be described where it’s defined, not where it’s used. If you’re calling a function hundreds of times, writing so verbosely is just total overkill. Anyone who reads code should be familiar with the calls being made. If you’re trying to figure out what some piece of code does, you’re expected to know where it’ll run, what language it’s in, what libs and frameworks it uses, etc. If you cannot meet those expectations, then you’re not qualified to read that code until you brush up.

    Just because a property is called “Visibility” doesn’t mean it shows or hides something. Maybe Visibility=500 just means you can see 500 meters.

    Good luck deducing what a function does by the signature at the call site…

    • ariya

      It may sound strange but actually I fully agree with your sentiments here.

      If you allow me to summarize it, basically it boils down to:

      * Use an IDE (or in general, the best tools) when writing the code
      * If you can’t figure out what the code does, don’t deduce. Just consult the docs

      Maybe I misunderstand you, but is there anything in the blog post (read:”junk”) actually suggests that you should NOT do those two points?

      Also, since this post specifically addresses the issue of boolean parameter (and not other types), what if we tweak your example to be like this?

      Connect(’127.0.0.1′,’Jake’,’hwuq026′,’/info/data’, true);

      Assume you are familiar with calls being made. You have seen/reviewed the same calls in other places, over and over again. It’s imprinted in your brain that 127.0.0.1 is the server address, ‘Jake’ is the login, etc etc (you know it because you looked up the API docs a dozen time). It’s hard to mix it up and mistakenly think that ‘Jake’ is the server name and ’127.0.0.1′ is the login. But chance is, you can’t always accurately recall what the last argument ‘true’ (or ‘false’ in some other cases) actually does.

      It would be of course a bless if everyone of us has a photographic memory. In reality, we don’t.

      I wish every software engineer thinks exactly like you in terms of code review. I can imagine that when you read any piece of code (either because you need to review it or because you have to write a module that interacts with it or because of some other reasons), you will spot every single function call in that code, look up the API docs (or barring that, search the Internet for more info), analyze how each function works, and finally give your approval result.

  • Ken

    Funny how I wrote a function with TWO boolian operators in an article and not one person took me to task for using such a beginner’s mistake. Actually having an enum with three values makes better sense. I didn’t think of that when I wrote it.

    I fail to see the mistake when the parameter name is well named and properly documented so intellisense can tell you what it means. Yes, just reading hardcoded boolian values without the API handy isn’t easy to figure out. Having one enum with three values would be more explanitory. Nothing explains that both operators are “suggestions” that will be used if it is possible.

    I fail to see how a variable that goes through extensive logic to reach its final value is any more readable than a boolian value. (hardcoded or not.)

    • ariya

      Can you give a specific example about your last point?

  • Ken

    Funny how I wrote a function with TWO boolian operators in an article and not one person took me to task for using such a beginner’s mistake. Actually having an enum with three values makes better sense. I didn’t think of that when I wrote it.

    I fail to see the mistake when the parameter name is well named and properly documented so intellisense can tell you what it means. Yes, just reading hardcoded boolian values without the API handy isn’t easy to figure out. Having one enum with three values would be more explanitory. Nothing explains that both operators are “suggestions” that will be used if it is possible.

    I fail to see how a variable that goes through extensive logic to reach its final value is any more readable than a boolian value. (hardcoded or not.)

    • ariya

      Can you give a specific example about your last point?

  • Reinhard Neuwirth

    When in the second paragraph I struck the first ‘she’ (the developer) I flinched, when in that same paragraph the second ‘she’(that someone who reads the code) I abandoned the article and swooped right to the end. Shouldn’t that be “Most importantly, next time you design an API function, remember GEORGINA Boole and don’t let HER down!”? There is nothing quite so annoying as political correctness gone mad, silly mannerisms and cliches. Cheers.

    • ariya

      This has nothing to do with political correctness. Read my previous reply about this, search above for “gender neutral”. I actually spent a quite amount of time researching that topic (I have a lot of interest on languages) and decided to experiment with it.

    • Isabella

      And on what planet do you live? Many ‘shes’ write APIs and read documentation – and for that matter have studied Logic.

  • Reinhard Neuwirth

    When in the second paragraph I struck the first ‘she’ (the developer) I flinched, when in that same paragraph the second ‘she’(that someone who reads the code) I abandoned the article and swooped right to the end. Shouldn’t that be “Most importantly, next time you design an API function, remember GEORGINA Boole and don’t let HER down!”? There is nothing quite so annoying as political correctness gone mad, silly mannerisms and cliches. Cheers.

    • ariya

      This has nothing to do with political correctness. Read my previous reply about this, search above for “gender neutral”. I actually spent a quite amount of time researching that topic (I have a lot of interest on languages) and decided to experiment with it.

    • Isabella

      And on what planet do you live? Many ‘shes’ write APIs and read documentation – and for that matter have studied Logic.

  • Chiko

    Every time I review code and see bool arguments, I recommend developers to use enums, multiple apis instead. But most of them don’t listen as bool is easier to implement. I think I need to forward this article to all these guys.thanks. As well, I think it not just about Apis for others. All interface methods should follow this rule.

  • Chiko

    Every time I review code and see bool arguments, I recommend developers to use enums, multiple apis instead. But most of them don’t listen as bool is easier to implement. I think I need to forward this article to all these guys.thanks. As well, I think it not just about Apis for others. All interface methods should follow this rule.

  • Coding since birth

    Here is the sad but true fact of the matter. We all “F” up while programming. If you are a designer programmer it is different that being a programmer who follows what others tell them to do. When I have to design it all from scratch (Which often includes things such a companies internal business procedures) I will start programming after extensive thought and then I put in some arbitrary statements to work through a programming issue. Often there are many aspects of a project that the temporary arbitrary bool variable unfortunately gets used in. It is left in not so much from negligence but rather dependency. Most of the time this has zero significance. But then there are the other times when that code graduates to the next level and others have to deal with the arbitrary vars at a much later date when someone decides to expand on what I started.

    Most companies, when given the choice, will forgo the extra expense of fixing arbitrary variables and documenting coding. What’s a programmers to do?

    It is sad but true that we should not do these sorts of things as programmers, but we do. Sadly we get trapped using arbitrary code which at the particular moment made perfect sense to trouble shoot the issue at hand, but later got too deep to effectively change it.

    Let us all try a little harder to be more specific and adopt better Boolean habits and then maybe future generations of programmers will not have to not not try to figure out what the $#&*! is intended.

  • Coding since birth

    Here is the sad but true fact of the matter. We all “F” up while programming. If you are a designer programmer it is different that being a programmer who follows what others tell them to do. When I have to design it all from scratch (Which often includes things such a companies internal business procedures) I will start programming after extensive thought and then I put in some arbitrary statements to work through a programming issue. Often there are many aspects of a project that the temporary arbitrary bool variable unfortunately gets used in. It is left in not so much from negligence but rather dependency. Most of the time this has zero significance. But then there are the other times when that code graduates to the next level and others have to deal with the arbitrary vars at a much later date when someone decides to expand on what I started.

    Most companies, when given the choice, will forgo the extra expense of fixing arbitrary variables and documenting coding. What’s a programmers to do?

    It is sad but true that we should not do these sorts of things as programmers, but we do. Sadly we get trapped using arbitrary code which at the particular moment made perfect sense to trouble shoot the issue at hand, but later got too deep to effectively change it.

    Let us all try a little harder to be more specific and adopt better Boolean habits and then maybe future generations of programmers will not have to not not try to figure out what the $#&*! is intended.

  • SergueiS

    Authors, don’t pretend to be politically correct!
    You refer to a programmer as “she” while the only photo in the article is a male one!

    Not mentioning that among the last 100 programmers I worked with in various companies in various countries, the women were… none.

    • ariya

      Please read my other reply on the same subject.

  • SergueiS

    Authors, don’t pretend to be politically correct!
    You refer to a programmer as “she” while the only photo in the article is a male one!

    Not mentioning that among the last 100 programmers I worked with in various companies in various countries, the women were… none.

    • ariya

      Please read my other reply on the same subject.

  • Rob G

    That’s one thing I like about the Smalltalk family of languages the style of calls being keyword-value pairs means every parameter is documented:

    account receive: amount from: source

    makes it quite clear what the parameters are. It would force you to rethink the name in the instances you cite, quite correctly.

  • Rob G

    That’s one thing I like about the Smalltalk family of languages the style of calls being keyword-value pairs means every parameter is documented:

    account receive: amount from: source

    makes it quite clear what the parameters are. It would force you to rethink the name in the instances you cite, quite correctly.

  • metator

    Very interesting, Ariya!

    I come from the managed languages world (C#, Java) but decided to take a look at Qt this summer, just for fun. Pretty look stuff (and very well documented)! And you are absolutely right – code should speak for itself and those design principles you’ve mentioned are probably the reason why everyone who tries Qt, becomes fond of it.
    To add another example of good API design principles, take a look at NUnit, an unit test framework for C#. It’s designed in such a way that you can almost read the code like it was written in English.

    Regards

  • metator

    Very interesting, Ariya!

    I come from the managed languages world (C#, Java) but decided to take a look at Qt this summer, just for fun. Pretty look stuff (and very well documented)! And you are absolutely right – code should speak for itself and those design principles you’ve mentioned are probably the reason why everyone who tries Qt, becomes fond of it.
    To add another example of good API design principles, take a look at NUnit, an unit test framework for C#. It’s designed in such a way that you can almost read the code like it was written in English.

    Regards

  • Mark

    Not to mention that booleans (duh!) only handle two states. Im not sure how often, during development, Ive found that two states werent enough. You can make do with overloads, but Ive found its better to use enums up front.

  • Mark

    Not to mention that booleans (duh!) only handle two states. Im not sure how often, during development, Ive found that two states werent enough. You can make do with overloads, but Ive found its better to use enums up front.

  • Jeremy

    “may not always have the API documentation handy” – almost every language these days comes with intellisense, and arguments in parameters have names.

    Hence this line:

    widget.Repaint(false)

    Is not that confusing when your programming and you see it expects:

    widget.Repaint(bool deferRePaint)

    • ariya

      This is useful only for writing the code. The blog post address the potential issues raised when you read the code (for review or other reasons).

  • Jeremy

    “may not always have the API documentation handy” – almost every language these days comes with intellisense, and arguments in parameters have names.

    Hence this line:

    widget.Repaint(false)

    Is not that confusing when your programming and you see it expects:

    widget.Repaint(bool deferRePaint)

    • ariya

      This is useful only for writing the code. The blog post address the potential issues raised when you read the code (for review or other reasons).

  • Ivan

    In a well done API, you don´t need read code, just read jsdoc or similar.

    • ariya

      I think what you mean is don’t need to look at the source code. That totally misses the point, though. We are not talking about the source code of the API implementation, rather the code which uses the API (whatever it is).

  • Ivan

    In a well done API, you don´t need read code, just read jsdoc or similar.

    • ariya

      I think what you mean is don’t need to look at the source code. That totally misses the point, though. We are not talking about the source code of the API implementation, rather the code which uses the API (whatever it is).

  • */

    great post, but i can’t fully agree with first example.
    in javascript widget.repaint(false) is usually a user fault
    because it should be called as
    widget.repaint()
    in 99% of places, and
    widget.repaint(true) (or maybe even widget.repaint(“immediate”))
    in the rest.

    but you are absolutely right about functions with multiple arguments or balanced usage.

    • ariya

      And do you think you would not be confused when you see a line of code which contains that widget.repaint(true) ?

      • Corrie Engelbrecht

        Most of the time, a boolean means “force, or don’t force”, so I would not think repaint(false) means “don’t repaint”.

        Why call repaint at all if you don’t want to repaint?

        • http://roberthorvick.com/ RobertHorvick

          > Most of the time, a boolean means “force, or don’t force”

          That is a convention. Perhaps one that you and many others are familiar with.

          If the code reader has to understand every convention to successfully understand the code then the API has failed in that respect.

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Nah. It doesn’t matter what area you program in, there are domain conventions. You’re not going to get very far in life by pretending the API has to magically take care of conventions. So essentially you are the one who has failed in this respect. If you are not one of the many who are familiar with this convention, then you are the one who has not educated yourself, or does not have experience, in this domain.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            No need to be that extreme, nobody ever claimed that conventions are not needed at all.
            The million-dollar question is how far such conventions would go until things become confusing. For example, I haven’t met anyone who thinks the “convention” used in the initKeyEvent example is crystal clear.

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            How is your initKeyEvent example related to domain conventions? (It isn’t)

            I think you need to learn: a) what a domain is, b) what a convention is c) what a domain convention is

          • http://ariya.ofilabs.com/ Ariya Hidayat

            Last time I checked, Sams didn’t produce “Teach Yourself Domain Convention in 21 Days”. Thus, it would be appreciated if a known expert like you could kindly recommend some resources/proceedings/newsletters which would help a layman like me to further comprehend such a delicate topic. Thanks!

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            LOL. “Last time I checked, Sams didn’t produce “Teach Yourself Stuff Anyone Encounters in Programming in 21 Days”. Thus, it would be appreciated if a known expert like you could kindly recommend some resources/proceedings/newsletters which would help a layman like me to further comprehend such a delicate topic. Thanks!”

            My advice is to stop defending an untenable position once you realise you’ve said something stupid. To achieve growth, you have to learn, not tell everyone around you that they’re actually the ones who are wrong.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            At this rate, soon you’ll start insulting my ancestor.

            But why not? I’d encourage every honored guest to my blog (or my house, for that matter) to let off the steam since I still have this faint hope that some day, we will all go back discussing important matter.

          • Donald Rupert Carr

            I can’t help but notice that we are not having this conversation on Corrie’s blog. And that John Carmack is in the audience.

            What amazes me most though, is that there can be any kind of objection to “Design clear self describing APIs for your own consumption”. Such a precarious untenable position Ariya, you must be sweating profusely.

            With Qt, you could read the code if you wanted to; you rarely actually found yourself having to, due to the cited guideline which I had grown so accustomed to I thought it common sense.

            In any case:

            WickedAPI.repaint(true, false, true, true)

            Don’t drink the code downstream of Corrie, that much is apparent.

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            I have never objected to “Design clear self describing APIs for your own consumption”, actually.

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Lol. How pathetic. To try and gain sympathy by implying I’ll insult your ancestors, and trying to emphasize that this is your blog and I’m just a visitor.

            These are the actions of someone who’s desperate. If you cannot stand on facts, or logic, please consider that you should just wake up and learn something about programming. You clearly know nothing about it. And you are your own worst enemy as well.

            I’ll reiterate: if you realize you’ve made a mistake, just admit it. Why do you continue to argue about this? You’re wrong. You should learn from a mistake, not pretend that you’ve never made one!

          • http://ariya.ofilabs.com/ Ariya Hidayat

            After you threw all kinds of adjectives, from “stupid” to “pathetic” (surely you can’t just stop right there!), I can like to be prepared to admit my grave mistake.
            One last question: do you want it in writing?

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Yes. Please write another blog post in which you explain your journey of discovery. You have much, much to learn, but I can help you get there.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            What kind of discovery you are referring to? What makes you seriously think you are qualified to help here?

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Well, you’ve admitted above that this entire article was based on a mistaken belief that you know even a little bit about programming. Now that you’ve admitted that, and you’ve discovered that your two weeks of blogging isn’t the same as 20 years of programming, I think we can really start to make progress in your personal journey of growth.

            I won’t take any credit for your idea to blog about this revelation you’ve achieved, because you have already alluded to thanking me in writing.

            However, I think it’s clear that without my mentorship and guidance, you would even now still be under the impression that your knowledge about programming is enough to teach other people, which of course you now know is hardly the case.

            I’d like to congratulate you on this most humble of steps in the growth cycle, however. Not everyone who starts off clueless, and clueless about the fact that they’re clueless, can make this leap of intuition! So well done!

          • Burt

            I will just leave this here:

            clueless twonk

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Lol. So that is your logical, fact based response, is it?

          • http://ariya.ofilabs.com/ Ariya Hidayat

            What is this “two weeks of blogging” you referred to?

            It would have been very nice if there is a real “mentorship and guidance”. Unfortunately, all I’ve seen from you is just a mixture of homeopathic technical substance with tons of personal attacks.

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Well those are attacks all all in your mind. Also, lookup homeopathic. It doesn’t mean what you think it does.

            Lastly, you are not someone who can accept mentorship. All you want to do is cry about how I want to insult your mommy. You never respond with any knowledge or facts to anything. All you ever do is whine.

            When I told you that you need to obtain domain knowledge, you just ignored it and repeated your original position. That means you haven’t evaluated anything I’ve said. So you can never learn anything, because your personality won’t let you.

          • http://ariya.ofilabs.com/ Ariya Hidayat

            Nice try, but you still dodged the question: What is this “two weeks of blogging” you referred to?

          • http://www.selectioneffect.info/ Corrie Engelbrecht

            Lol. Are you trolling on your own blog, or something?

          • http://ariya.ofilabs.com/ Ariya Hidayat

            Counter-trolling, to be precise.

          • Guest

            Lol. You get funnier as time goes by.

            Have you considered that “counter-trolling” is actually just trolling? The reason you’re trolling is irrelevant.

            This is another reason why you are unmentorable: you believe in logical impossibilities, and you’re not even aware of how flawed your thinking process is:)

          • http://ariya.ofilabs.com/ Ariya Hidayat

            Why must you care that I am (or any others, for that matter) unmentorable or not?

  • */

    great post, but i can’t fully agree with first example.
    in javascript widget.repaint(false) is usually a user fault
    because it should be called as
    widget.repaint()
    in 99% of places, and
    widget.repaint(true) (or maybe even widget.repaint(“immediate”))
    in the rest.

    but you are absolutely right about functions with multiple arguments or balanced usage.

    • ariya

      And do you think you would not be confused when you see a line of code which contains that widget.repaint(true) ?

      • Corrie Engelbrecht

        Most of the time, a boolean means “force, or don’t force”, so I would not think repaint(false) means “don’t repaint”.

        Why call repaint at all if you don’t want to repaint?

  • http://www.facebook.com/people/Tim-Rowe/503925725 Tim Rowe

    Sounds like user error to me. What kind of inexperienced programmer goes around assuming a boolean parameter means “don’t do what the function name says it does”?
    I would suggest that those still insisting they’d do things as in your update are actually Business Analysts – failed, CompSci drop-outs who couldn’t program but still wanted the 6 figure salary.

    • http://ariya.ofilabs.com/ Ariya Hidayat

      Don’t forget, there are other real-world cases like that stop(true, false). Regardless what the inexperienced programmer assumes, that is still an API design error (from whoever responsible for that).

  • http://www.facebook.com/MisinformedDNA Dan Friedman

    If you are concerned with reading code, then the implemented could just create a well-named variable and then pass it into the method. It’s not the API that’s the problem, it’s the implementer. So repaint(isImmediate).

    • http://ariya.ofilabs.com/ Ariya Hidayat

      A variable looks more a workaround to me, rather than a real solution. But yeah, it works.

  • http://twitter.com/katox Kamil Toman

    This book elaborates on code readability a lot http://www.lulu.com/shop/andres-valloud/a-mentoring-course-on-smalltalk/paperback/product-3788890.html

    And it is a great book. Even if not directly applicable to your pet language don’t let smalltalk scare you.

  • Nobody

    “The nice thing working for Trolltech was (among others) learning the principles behind the good API.”
    I certainly did not expect to see “Trolltech” (or “Qt”) and “good API” in a single sentence (without a bold negation, that is).

    If I was to name the worst framework API to ever have worked with I’d certainly go with Qt. No-brainer.
    (signed int indexing, lack of text ranges or just good old QRegExp’s indexIn() & Co anybody? Sheesh… don’t get me started.)

    • http://ariya.ofilabs.com/ Ariya Hidayat

      That’s one data point. But then, everyone’s is entitled to his own opinion.

  • Pingback: Michael Tsai - Blog - Boolean Trap

  • Pingback: Michael Tsai - Blog - Boolean Trap

  • Kevin Smith

    Load of bollocks – the difficulties presented by unnamed parameters (boolean or otherwise) are insignificant compared to the difficulty in providing a consistent and elegant conceptual model.

  • Pingback: hall of api shame: boolean trap | 다물의 디지털 세상

  • Hatchre

    Here’s another reason never to use bool in an API:

    https://news.ycombinator.com/item?id=4695587

    Curl upgraded a bool to an integer flag, but integers and bools are silently converted and Curl’s users carried on using an insecure compatibility value without reading the Curl changelog.

  • patternbuffer

    Working link to API Design Principles: http://qt-project.org/wiki/API-Design-Principles

  • Karl

    Boolean Traps are only a symptom; the real disease is Boolean Blindness:

    http://existentialtype.wordpress.com/2011/03/15/boolean-blindness/

  • http://getify.me/ getify

    While I agree with the spirit of this post, I don’t see something particularly special about booleans. An API where you pass “magic numbers” would be equally (or more) confusing. So would an API where you pass in an array of various values.

    The object-literal workaround for named-parameters is certainly a popular one to suggest, but it’s often really clunky too. It’s not really a magic bullet, but it shifts the burden around just enough that sometimes it makes you feel slightly better about your API design. But I don’t think users instinctively prefer to pass big hashes.

    You also suggest creating different API names for the different option permutations. In very limited cases, this is OK, but a lot of times it creates “API fatigue” where the API surface is just so cluttered with dozens of different closely related API calls, you get lost in documentation (or code!) trying to use it. Don’t make two API calls where one will suffice.

    On the other end of the spectrum, you could design your API to take natural language strings like `widget.show(“but don’t animate”) and that would be perfectly semantic and readable, but then it shifts the burden of implementation too far back inside the API of having to do crazy things like parsing natural language strings.

    FWIW, I’m no PHP fan or supporter, but they do have an awful lot of mature (or, at least, old) APIs with an awful lot of parameters of various types, whether they be numbers or booleans, and it seems like a lot of those APIs suggest the use of constants in place of the magic values. With numbers, it even allows you to do value masking, which I think is also a powerful technique but extremely non-idiomatic in the JS world (for some reason!?).

    In another comment here you mention using a named-variable is a workaround/hack, but I disagree: I think it’s actually a great balance.

    `widget.show(widget.NO_ANIMATION)` has the appearance of named-parameter, but is less clunky than `widget.show({ animate: false })`.

    Last point: on APIs that I am completely in control of, I would try to follow a balance of these various “best practices”. But for APIs I don’t control, but which are poorly designed, I do stuff like this:

    `widget.show( /*animate=*/ false )`

    • Joe Shelby

      the object workaround is more expensive not just in the need to create the object, but on the receiving side, the need to add a null-check and handle that correctly.

      you mention enums, and that’s still perfectly valid.

      Widget.prototype.ANIMATE = true; Widget.prototype.NO_ANIMATION = false;

      and later, widget.slide(90, widget.NO_ANIMATION)

      all boolean, nothing polluting the global/window workspace, and no need to remember the ‘class’ of the widget in question. one level of indirection is far faster than make-an-object-and-check-its-existence.

  • Donald Rupert Carr

    http://developer.qt.nokia.com/wiki/API_Design_Principles

    is unfortunately no longer a valid URL, you need to spruce that dude up to be:

    http://qt-project.org/wiki/API-Design-Principles

  • Paul Therrien

    the moral is: Don’t pass parameters into functions without first understanding what your function is doing!

  • skaue

    I agree with using a more explicit language when programming, allowing the developer to read out loud what the code actually does, however in many development environments, these crappy booleans would carry a tooltip or signature tooltip revealing the name of the parameter, and then explain to the developer the intention of the boolean. I remember prefixing all variables with one or two letters just to reveal its native type… I don’t do that any more.

  • Pingback: Four short links: 16 August 2013 - O'Reilly Radar

  • Vitaly

    How about removeAll(true, false) in Sencha Touch? I’ve always found it a bit confusing. The first argument stands for ‘destroy’ and second for ‘everything’, which means docked items won’t be removed if ‘everything’ is set to false.

  • sergeyrozhenko

    C++ IDE would easily show you what these boolean parameters do in a tooltip or at a press of a button (otherwise it’s garbage that has no right to be called IDE). So, avoiding “boolean trap” is something to consider, but not always the right choice.

    • http://ariya.ofilabs.com/ Ariya Hidayat

      IDE is only useful when writing the code and occasionally when reading it. For code review and/or analysis, it hardly matters. How many times you read the code from somewhere and always paste it in your IDE?

  • Donald Rupert Carr

    Hah!

    “If I wake you at midnight and ask you this question “if invisible is false, does that mean my component is shown or hidden?”, there is a chance you answer it incorrectly.”

    I am not asleep by midnight you fool! Vanishing chance of said error!

    • http://ariya.ofilabs.com/ Ariya Hidayat

      Well, the sun never sets on the British empire…

  • touist

    In Ada (designed to be read) you have named parameters : Repaint (Widget => My_Widget, Later => True);

  • MBR

    I’d have to agree with others here — to say that someone would interpret:
    repaint(false);
    as
    // repaint();

    seems rather bizzare – and I’d have to also agree that the “force” pattern here has been around (in my memory at least) since the advent of event-driven GUI’s, and probably before that, retained-mode display list processors.
    Your wording of “do not repaint” doesn’t even make sense, as typically it’s impossible to tell the computer *not* to do something (with the exception of non-monotonic reasoning/planning systems) – kind of the procedural equivelent of “Don’t_think_of_pink elephants()”
    I do not disagree with your API design tennants here however, just with how low you set the bar and the level to which the code reader is going to misread the sematics of the statements.
    The issue isn’t just with bools, but with positional args in general.
    In the Javascript world, object option parameters are used quite a bit it lieu of (typechecked) named parameters, and C# (like Ada) has named parameters, but typically people like short code over readable code – but it’s fairly common to switch from positional to keyword after a certain # of parameters. The Smalltalk keyword selector syntax is probably the best of all worlds, where the method atPut is called (only) as “foo at: 7 put:9″ rather than “foo.atPut(7,9)” that is common elsewhere.

    • cHao

      `repaint(false);` could very easily be interpreted as “ignore future `repaint()` calls til i call `repaint(true)`. It’s quite common to disable updates while you’re doing a bunch of them, and then having a single big update at the end.

      Of course, a decent design would have a `disableUpdates()` and `enableUpdates()` rather than relying on a rather cryptic boolean parameter. But that’s kinda the point of the whole article.

  • Pingback: A Platform game in F# and SpriteKit – Part 7 – DSLs baby! | Neil Danson's Blog

  • Pingback: It just works(™)! | Neil Danson's Blog