Working with full-time now I, more often, have insights about its way of doing things (or for some people). One thing that blows my mind every time I find out in my daily saga is the duck typing thing. Being honest, it is not a python exclusive feature, since almost every dynamic language presents that behavior. But be nice, I like Python. python Zen of python If some reader doesn’t know what it is, duck typing is a feature of a type system where the semantics of a class is determined by his ability to respond to some message (method or property). The canonical example (and the reason behind the name) is the : duck test If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck. class Duck:def quack():print('Quack!') class Goose:def quack():print('Quack') Goose().quack()>> Quack! Duck().quack()>> Quack! Ok, but what is the catch? There is nothing new here. Yes, nothing new. What I’m trying to show is the implications that this behavior has in the architecture of a system. And I’m advocating that this is a good implication. Let me explain. Imagine a class named : Car class Car:def __init__(self, engine):self.engine = engine def run():self.engine.turn_on() This is a classical example of dependency injection. My class receives an instance of an engine and use it in the run method, where it calls the method. Note that my does not depends on any concrete implementation of engine. And I'm not importing any other type! Just using a dependency injected instance of something that responds to a message. I could say my class depends on an interface. But I did not have to declare it. It is an automatic interface! Car turn_on Car turn_on Car In a language without duck typing I'll probably have to declare an explicit interface named for example , have the implementation (for example ) and explicit define my parameter to be an implementation of . IEngine EngineV1 Car IEngine interface IEngine {void turnOn();} public class EngineV1 implements IEngine {public void turnOn() {// do something here}} public class Car {public Car(IEngine engine) {this.engine = engine;} public void run() { this.engine.turnOn(); } } Ugh! How much code. So, as you can see the effect is the same. My class in both cases depends on an interface. But in the first case there are less code and I don't need to explicit implement the interface. It's already implemented if I define the method . Car turn_on The weakness I can see two problems here. Fat interface The first is an incentive to . As we don’t explicit define the API this can result in an interface with too much granular methods. interface bloat 2. Unnamed dependencies As we don’t know the name of the interfaces that a class depends we don’t have an automatic dependency tree. Because of this, all dependency injection frameworks have to workaround the dependency resolution in some way. , for example, was obligated to implement the concept of to allow dependency tree to be resolved automatically. Keys, in injector terms, are nothing more than a way to name/identify an interface that a class implements. Injector lib Keys Conclusion I don't think that duck typing was intentionally designed to have this behavior. I don't even think that duck typing is intentionally designed in a language at all but instead it is a side-effect of the dynamic nature of those type systems. But it is interesting what it can brings in terms of conciseness and low-coupling to the system and architecture. design
Share Your Thoughts