Design principles: no bool arguments

Thomas 'PointedEars' Lahn PointedEars at web.de
Thu Aug 25 11:29:01 CEST 2011


Stefan Behnel wrote:

> Maarten, 25.08.2011 09:52:
>> On Aug 25, 9:13 am, Steven D'Aprano wrote:
>>> One design principle often mentioned here (with a certain degree of
>>> disagreement[1]) is the idea that as a general rule, you shouldn't write
>>> functions that take a bool argument to switch between two slightly
>>> different behaviours.
>>>
>>> This is a principle often championed by the BDFL, Guido van Rossum.
>>>
>>> Here's a Javascript-centric article which discusses the same idea, and
>>> gives it a name: the Boolean Trap.
>>>
>>> http://ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html
>>>
>>> No doubt there are counter arguments as well. The most obvious to me is
>>> if the flag=True and flag=False functions share a lot of code, it is
>>> poor practice to implement them as two functions with two copies of
>>> almost identical code.
>>
>> A simple one: C and C-like languages only have arguments, not keyword-
>> parameters. That alone makes a world of difference.

The logic is flawed, for one because keyword arguments can be emulated.
For example in C, you can (and would) OR-combine binary flag constants:

  open("foo", O_RDONLY);

instead of

  open("foo", TRUE);

(assuming the latter function existed).  Other approaches can be found in C 
as well:

  fopen("foo", "r");

In ECMAScript implementations like JavaScript (which I count as C-like), you 
can define the API so that it accepts object references (as explained in the 
article):

  foo(bar, {baz: true});

instead of (or in addition to)

  foo(bar, true);

(But this is a trade-off readability vs. runtime and memory efficiency, as 
each time the function is called an object needs to be created, if it is not 
cached, and an additional property access is necessary in the 
function/method.  Python has much the same problem, see below.)

And there can hardly be an argument that W3C DOM Level 3 Events init…Event() 
methods are *unnecessarily* FUBAR.  Even OMG IDL supports constants (as 
showed by the HTMLElement interface of DOM Level 2 Core), and passing of 
object instances to methods.
 
> Right. It's totally unreadable to find this in the code:
> 
>      data1.merge_with(data2, true);
> 
> Requires you to either a) know the underlying signature by heart, or b)
> look it up before understanding the code.
> 
> It's a lot harder to argue against this:
> 
>      data1.merge_with(data2, overwrite_duplicates=True)

Both variants work (even in Py3) if you only define

class Data(object):
  def merge_with(self, bar, overwrite_duplicates):
    pass

data1 = Data()
data2 = Data()

You have to define

class Data(object):
  def merge_with(self, bar, **kwargs):
    # do something with kwargs['overwrite_duplicates']
    pass

data1 = Data()
data2 = Data()

so that

data1.merge_with(data2, True);

is a syntax error ("TypeError: merge_with() takes exactly 2 arguments (3 
given)").

IOW, this advantage of Python in readability is not only caused by API 
definition, but also by how the API is used.  It might turn into a 
disadvantage if key lookups make the code expensive memory- and runtime 
wise.

And you will still have to know the underlying signature to name the 
argument.  Worse, with keyword arguments you *have to* look up the 
documentation (i. e., it needs to be well-documented as well) to know its 
name (as the compiler can only tell you "kwargs").

So no doubt there are advantages to keyword arguments, but there are 
disadvantages, too.

-- 
PointedEars

Bitte keine Kopien per E-Mail. / Please do not Cc: me.



More information about the Python-list mailing list