Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm a C++/C# developer and recently I've started to learn Python. I think I understand the concept of duck typing right now except for one thing.

When I'm coding in C++ or C# I sometimes create completely unrelated classes that have similar methods with similar signatures, for example: Create(), Open(), Close(), ProcessData(), etc. It's not a big deal in C++ or C# (unless you want to mess with C++ templates), but in languages with duck typing like Python this could cause a disaster. Consider the following example:

class DbTransaction:
    def rollback(self):
        pass

class SourceControlChangeset:
    def rollback(self):
        pass

def rollback_transaction(transaction):
    transaction.rollback()

transaction = DbTransaction()
changeset = SourceControlChangeset()
rollback_transaction(transaction)
rollback_transaction(changeset) # Oops!

Maybe be example is a bit artificial, but I think this could happen pretty easily in a big project with many classes.

What should I do in this situation? I think that type checking is not "pythonic" so my only idea is to change naming convention for class methods like this:

class DbTransaction:
    def rollback_transaction(self):
        pass

class SourceControlChangeset:
    def rollback_changeset(self):
        pass

Any ideas?

share|improve this question

2 Answers 2

up vote 3 down vote accepted

In Clean Code, Robert Martin argues that even with static typing, you should avoid what he calls "punning," meaning giving the same name to two methods that aren't semantically similar. That means if you consider transaction.rollback and changeset.rollback to be semantically different, you should try to choose another name for one of them, whether you are doing duck typing or not.

In your particular example the name makes the semantics of each case obvious, even though the context is different, so it's okay to leave the name the same. You're mostly concerned with preventing accidentally passing one kind of object into a context meant for the other.

To be blunt, that's the trade-off you make when choosing duck typing. You increase the risk of using the wrong type, which requires somewhat more testing, but in exchange you gain increased reusability with less hassle. If you want the benefits of strong static typing, you should choose your language and architecture accordingly. You can't have your cake and eat it too.

share|improve this answer
1  
+1 for "that's the trade-off you make when choosing duck typing". –  Ross Patterson May 4 at 1:45
    
One use of interfaces, in a sense, is to say that if Collection and NumericVector both have Add methods, then one may think of the methods as though they had distinct names Collection_Add and NumericVector_Add. Many languages with interfaces require that any particular reference be bound to a single interface, but conceptually duck-typing and interfaces could work very well together if it was possible to cast any object which implements both IWalkLikeDuck and IQuackLikeDuck to {IWalkLikeDuck,IQuackLikeDuck}. –  supercat Jun 12 at 16:29

The unfortunate side effect of Duck Typing is that sometimes it isn't a duck, even if it walks like a duck and quacks like a duck. Duck Typing only works in limited areas of similarity.

Your example, however, is itself a problem. You should never rollback_transaction(transaction), you should always transaction.rollback(). If you have a valid reason to wrap the behavior of a method, you should do it "objectally", not procedurally, by creating a wrapper object whose method wraps the inner object's method.

share|improve this answer
    
-1 for "procedural is bad, object is good". No matter what somebody thinks about those approaches, procedural functions have their place. And this have nothing to do with the issue at hand. –  Javier May 3 at 14:56
1  
I wouldn't go as far as downvoting this, but I don't understand the answer. Could you clarify what is meant by “If you have a valid reason to wrap the behavior of a method, you should do it "objectally", not procedurally, by creating a wrapper object whose method wraps the inner object's method”, and how this solves the problem in the question? –  amon May 3 at 15:30
    
@Javier Actually, procedural vs. object is exactly the issue. Duck mis-Typing doesn't happen in the procedural world. Which, although you wouldn't know it from my answer, is my world. I'm more of a "procedural good, object likely misused" kind of guy. –  Ross Patterson May 4 at 1:40
    
@amon The point, which I obviously didn't get across, is that this sort of problem happens when you try to apply procedural techniques to objects. Duck Typing is a peculiarity of certain object systems, and it doesn't happen if you wrap objects to add/augment methods instead of applying functions to them. –  Ross Patterson May 4 at 1:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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