Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duck typing and (java) interface concept

Tags:

I just read the Wikipedia article about duck typing, and I feel like I miss an important point about the interface concept I used to in Java:

"When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck."   class Duck:     def quack(self):         print("Quaaaaaack!")     def feathers(self):         print("The duck has white and gray feathers.")     def swim(self):         print("Swim seamlessly in the water")  class Person:     def quack(self):         print("The person imitates a duck.")     def feathers(self):         print("The person takes a feather from the ground and shows it.")     def name(self):         print("John Smith")  def in_the_forest(duck):     duck.quack()     duck.feathers()  def game():     donald = Duck()     john = Person()     in_the_forest(donald)     in_the_forest(john)  game() 

what if, in in_the_forest, I write:

  • does it quack like a duck ? yes
  • does it have a duck feathers ? yes
  • great, it's a duck we've got !

and later, because I know it's a duck, I want it to swim? john will sink!

I don't want my application to crash (randomly) in the middle of its process just because John faked to be a duck, but I guess it wouldn't be a wise idea to check every single attributes of the object when I receive it ... ?

like image 440
Kevin Avatar asked Jul 05 '11 08:07

Kevin


1 Answers

Duck typing isn't really about checking whether the things you need are there and then using them. Duck typing is about just using what you need.

The in_the_forest function was written by a developer who was thinking about ducks. It was designed to operate on a Duck. A Duck can quack and feathers, so the coder used those features to get the job at hand done. In this case, the fact that a Duck can also swim wasn't used, and wasn't needed.

In a static language like Java, in_the_forest would have been declared to take a Duck. When the coder later discovered that they had a Person (which could also quack and feathers) and wanted to reuse the function, they're out of luck. Is a Person a subclass of Duck? No, that doesn't seem at all appropriate. Is there a QuacksAndFeathers interface? Maybe, if we're lucky. Otherwise we'll have to make one, go modify Duck to implement it, and modify in_the_forest to take a QuacksAndFeathers instead of a Duck. This may be impossible if Duck is in an external library.

In Python, you just pass your Person to in_the_forest and it works. Because it turns out in_the_forest doesn't need a Duck, it just needs a "duck-like" object, and in this case Person is sufficiently duck-like.

game though, needs a different definition of "duck-like", which is slightly stronger. Here, John Smith is out of luck.

Now, it's true that Java would have caught this error at compile time and Python won't. That can be viewed as a disadvantage. The pro-dynamic-typing counter argument is to say that any substantial body of code you write will always contain bugs that no compiler can catch (and to be honest, Java isn't even a particularly good example of a compiler with strong static checks to catch lots of bugs). So you need to test your code to find those bugs. And if you're testing for those bugs, you will trivially find bugs where you passed a Person to a function that needs a Duck. Given that, the dynamic-typist says, a language that tempts you into not testing because it finds some of your trivial bugs is actually a bad thing. And on top of that, it prevents you from doing some really useful things, like reusing the in_the_forest function on a Person.

Personally I'm torn in two directions. I really like Python with its flexible dynamic typing. And I really like Haskell and Mercury for their powerful static type systems. I'm not much of a fan of Java or C++; in my opinion they have all of the bad bits of static typing with few of the good bits.

like image 74
Ben Avatar answered Jan 01 '23 22:01

Ben