The Evils Of Positional Arguments

A few days ago I found myself writing pure ansi C code, after over two years of not touching it at all. In fact, these two years consisted mostly of Python, and a little of C#, both very far from it. While coding away, trying to get re-accustumed to mallocs and frees, return values instead of exceptions and pointer arithmatic, I had to perform a memcpy. Very easy, of course, but I could not for the life of me remember how to call it. I remembered rather vividly that it had 3 arguments, named 'dst', 'src' and 'len', the first two being void* and the latter.. perhaps plain int? But in which order they came, I could not recall. Now, that is not so evil, of course, because a quick look at the C reference refreshed my memory (until next time). This repeated with other functions (such as memset). But only when it started to happen with my own functions, I realized how unnatural it is for me, to remember things by order and not by name. Names allow us to establish a context, to find reasoning. Also, we are (relatively) good at remembering names.

By using position as a way for transferring parameters, we are essentially calling them "one", "two", "three" and etc., which are still names, but are devoid of context or meaning, and are the same for every function. It is not only hard to remember the right order; we can endure it (as reality proves), but it makes our code less readable, less natural.

Also, it complicates changing existing APIs. Move an argument from its position, and you have to change the position everywhere in the code. This can easily lead to subtle bugs (consider switching dst and src, it may be very hard to find where this happened!). So if you append parameters, they must come in the end, which somtimes does not make much sense.

While all programming languages (that I know of) sin in this evil of positionality , one device takes it one step ahead: Regular expressions. Specfically, RE Substitution. Not only do you address its matches using numbers, but actually figuring out which number goes to which match can be confounding. I cannot count how many bugs this must have produced.

In conclusion:

Design your systems differently.
Let computers count. Let humans use names!


Categorised in: ,

4 Comments

  • lorg says:

    You're both wrong and right.
    Positional arguments aren't really fun, but they are a lot more concise than named arguments. With smart tips (intellisense or however it's called) you can usually manage.
    Still, memcpy is indeed a classic example of the problem. It is even compounded by the fact that various platforms use different versions of memcpy, with the argument order changed. ugh.

    Regarding regexps - at least in Python, I use named groups. Much more readable, doesn't change every time you change your regexp, and much more fun.

  • erezsh says:

    Ah, but conciseness comes at the price of clarity. Shorthand function names are also more concise, and the software industry already stirs away from these (fopen would probably not be chosen today, nor would strpbrk).
    The same IDEs that report the order of arguments for you as you edit (but not read, mind you!) can also assist you with overcoming this lack of conciseness.

    Using named groups in regexps is indeed the solution, yet sadly it is not a common practice.

  • arkon says:

    What about passing params in a dictionary? Or you don't count that?

  • erezsh says:

    Passing params in a dictionary is great, as long as there's some mechanism that makes sure names aren't misspelled etc. Of course there's ease-of-use to consider.
    Python's keyword arguments are excellent! Many other languages have that too, but still 'positional' is the most popular method of transferring arguments. That's what I protest.

Leave a Reply

Your email address will not be published. Required fields are marked *