How is duck typing different from the old 'variant' type and/or interfaces?

后端 未结 10 996
无人及你
无人及你 2021-01-30 03:32

I keep seeing the phrase \"duck typing\" bandied about, and even ran across a code example or two. I am way too lazy busy to do my own research, can someone tel

相关标签:
10条回答
  • 2021-01-30 03:39

    The simple answer is variant is weakly typed while duck typing is strongly typed.

    Duck typing can be summed up nicely as "if it walks like a duck, looks like a duck, acts like a duck, then it's a duck." It computer science terms consider duck to be the following interface.

    interface IDuck {
      void Quack();
    }
    

    Now let's examine Daffy

    class Daffy {
      void Quack() {
        Console.WriteLine("Thatsssss dispicable!!!!");
      }
    }
    

    Daffy is not actually an IDuck in this case. Yet it acts just like a Duck. Why make Daffy implement IDuck when it's quite obvious that Daffy is in fact a duck.

    This is where Duck typing comes in. It allows a type safe conversion between any type that has all of the behaviors of a IDuck and an IDuck reference.

    IDuck d = new Daffy();
    d.Quack();
    

    The Quack method can now be called on "d" with complete type safety. There is no chance of a runtime type error in this assignment or method call.

    0 讨论(0)
  • 2021-01-30 03:42

    Everything you can do with duck-typing you can also do with interfaces. Duck-typing is fast and comfortable, but some argue it can lead to errors (if two distinct methods/properties are named alike). Interfaces are safe and explicit, but people might say "why state the obvious?". Rest is a flame. Everyone chooses what suits him and no one is "right".

    0 讨论(0)
  • 2021-01-30 03:44

    @Kent Fredric

    Your example can most certainly be done without duck typing by using explicit interfaces...uglier yes, but it's not impossible.

    And personally, I find having well defined contracts in interfaces much better for enforcing quality code, than relying on duck typing...but that's just my opinion and take it with a grain of salt.

    public interface ICreature { }
    public interface IFly { fly();}
    public interface IWalk { walk(); }
    public interface IQuack { quack(); }
    // ETC
    
    // Animal Class
    public class Duck : ICreature, IWalk, IFly, IQuack
    {
        fly() {};
        walk() {};
        quack() {};
    }
    
    public class Rhino: ICreature, IWalk
    {
        walk();
    }
    
    // In the method
    List<ICreature> creatures = new List<ICreature>();
    creatures.Add(new Duck());
    creatures.Add(new Rhino());   
    
    foreach (ICreature creature in creatures)
    {
        if (creature is IFly)        
             (creature as IFly).fly();        
        if (creature is IWalk) 
             (creature as IWalk).walk();         
    }
    // Etc
    
    0 讨论(0)
  • 2021-01-30 03:45

    A variant (at least as I've used them in VB6) holds a variable of a single, well-defined, usually static type. E.g., it might hold an int, or a float, or a string, but variant ints are used as ints, variant floats are used as floats, and variant strings are used as strings.

    Duck typing instead uses dynamic typing. Under duck typing, a variable might be usable as an int, or a float, or a string, if it happens to support the particular methods that an int or float or string supports in a particular context.

    Example of variants versus duck typing:

    For a web application, suppose I want my user information to come from LDAP instead of from a database, but I still want my user information to be useable by the rest of the web framework, which is based around a database and an ORM.

    Using variants: No luck. I can create a variant that can contain a UserFromDbRecord object or a UserFromLdap object, but UserFromLdap objects won't be usable by routines that expect objects from the FromDbRecord hierarchy.

    Using duck typing: I can take my UserFromLdap class and add a couple of methods that make it act like a UserFromDbRecord class. I don't need to replicate the entire FromDbRecord interface, just enough for the routines that I need to use. If I do this right, it's an extremely powerful and flexible technique. If I do it wrong, it produces very confusing and brittle code (subject to breakage if either the DB library or the LDAP library changes).

    0 讨论(0)
  • 2021-01-30 03:46

    In regards to your request for an example of something you'd need to use duck typing to accomplish, I don't think such a thing exists. I think of it like I think about whether to use recursion or whether to use iteration. Sometimes one just works better than the other.

    In my experience, duck typing makes code more readable and easier to grasp (both for the programmer and the reader). But I find that more traditional static typing eliminates a lot of needless typing errors. There's simply no way to objectively say one is better than another or even to say what situations one is more effective than the other.

    I say that if you're comfortable using static typing, then use it. But you should at least try duck typing out (and use it in a nontrivial project if possible).

    To answer you more directly:

    ...so again i'm just not getting it. Is it a fantastic time-saver, or the same old thing in a brand new sack?

    It's both. You're still attacking the same problems. You're just doing it a different way. Sometimes that's really all you need to do to save time (even if for no other reason to force yourself to think about doing something a different way).

    Is it a panacea that will save all of mankind from extinction? No. And anyone who tells you otherwise is a zealot.

    0 讨论(0)
  • 2021-01-30 03:47

    Try reading the very first paragraph of the Wikipedia article on duck typing.
    Duck typing on Wikipedia

    I can have an interface (IRunnable) that defines the method Run().
    If I have another class with a method like this:
    public void RunSomeRunnable(IRunnable rn) { ... }

    In a duck type friendly language I could pass in any class that had a Run() method into the RunSomeRunnable() method.
    In a statically typed language the class being passed into RunSomeRunnable needs to explicitly implement the IRunnable interface.

    "If it Run() like a duck"

    variant is more like object in .NET at least.

    0 讨论(0)
提交回复
热议问题