Optional arguments are evil

When it comes to version and API changes, Python optional arguments are evil.
Say you define a function like this:

  1.  
  2. def someFunction(param1, param2, optParam=None)
  3. # code
  4.  

And you are calling it from module whatever.py like this:

  1.  
  2. retValue = someFunction(x, y, z)
  3.  

A few weeks later you need to change the API adding a new mandatory parameter:

  1.  
  2. def someFunction(param1, param2, param3, optParam=None)
  3. # code
  4.  

But you forget to update the call at whatever.py. It does not raise any exception but there is a big semantic error, "someFunction" is considering "z" as the "param3" where the caller is considering it the "optParam".
I try to avoid optional arguments as much as I can.

Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.
  • http://hcoder.org Esteban

    Hey!

    I’d say it’s evil to add arguments *before* existing optional arguments 😀

    I always try not to break any API when refactoring (either by using new optional arguments with defaults, or using a different method name, or…). Once you know you have migrated all the client code, you can remove/deprecate/whatever the old function.

  • http://carlosble.com Carlos Ble

    Hey Esteban!
    Python does not allow optional arguments before non-optional:
    def mySUT(optParam=None, x, y):
    SyntaxError: non-default argument follows default argument

    This wasn’t a refactoring but a new requirement. The problem is that, because of the lack of compiler you don’t know when your client code is completely migrated. (Thanks *grep* for the help!)

    However, optional arguments are good for mocking and constructor overloads.

    Espero que te vaya bien en Noruega!!! 🙂

  • http://carlosble.com Carlos Ble

    By the way, I’ve got your blog now in my blogroll 🙂

  • http://knocte.blogspot.com Andrés G. Aragoneses

    This is why I hate dynamic languages in general and Python in particular: you cannot refactor API knowing at compile-time if you need to refactor the consumers of the API because of changes in the API!

    BTW, in C# 4.0 there are optional parameters. I’m not a big fan of them either, but I think they got them right, not like Python, because every optional paramter *must be* a named-parameter as well!

    Cheers,

    Andrés

  • http://hcoder.org Esteban

    Sorry, my wording was really confusing 🙂 I didn’t mean to say that you should have added the new parameters after the existing optional ones 😀 Just that adding more mandatory parameters in a method that already has optional parameters was kind of asking for trouble… in a language like Python.

    Was it a requirement that the API of exactly that method changed like that? Requirement from whom? Not the “customer” I hope 🙂 It seems more natural to me what I mentioned, using a different method name while you’re making the migration. But I guess I’m used to not having proper refactoring tools and thinking in terms of what works fine for Perl/Python/Ruby.

    I don’t really remember having had any problems like this when improving APIs, but I think I’m starting to understand Java programmers when they whine about lack of refactoring tools in Perl/Python/Ruby 😀

    It’s great here in Norway BTW! 🙂 Cold, but still really interesting at work, and really busy 🙂 See you!

  • http://carlosble.com Carlos Ble

    Hi Andres! Thanks a lot for your comment. Dynamic languages have many advantages IMHO.
    People are always on one side, interpreted or compiled languages, but I think we can leverage the best of both worlds. It just depends on your problem.
    Hope you enjoying your current job.
    ——-

    Thanks very much Esteban! I see you point. And I think you’re right. Fortunately the code I was changing wasn’t under production yet so it wasn’t that bad to change its API. I miss refactoring tools, yeah, as well as a powerful IDE like VisualStudio 🙂
    You see, people say one can learn a new programming language within 2 weeks but when it comes to a big jump like java2ruby or c#2ruby or c#2python, … it is just a lie. You need much more time to wire things up properly.
    Take care man.

  • http://knocte.blogspot.com Andrés G. Aragoneses

    IMO (and it’s an opinion shared by bright minds like Anders Hejlsberg) static languages are just *better*, for the sake of maintainability, safety, security, efficiency, etc. You already have the “best of both worlds” with the latest features of the static languages (like C#: support for “var” and the like). Dynamically typed languages should be used only with very small projects (that is, which will never receive refactorings) or automated tests. Nothing more.

  • http://carlosble.com Carlos Ble

    Man, I wouldn’t say that in front of 10 guys from the Ruby community 🙂
    I get what you mean and agree with you quite a bit. However, I wouldn’t go that radical.
    Dynamic languages may be good for many things.
    Thanks for your brave comment

  • Pingback: Optional arguments are evil (II) « El blog de Carlos Ble()

  • http://www.sellwinterboots.com boots

    In Case B it tries to lock the files in the Bin-directory, which then leads to the locking-conflict described above.