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:
quack
like a duck ? yesfeathers
? yesand 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 ... ?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With