Jump to content

Duck typing

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by 142.179.26.211 (talk) at 06:53, 18 August 2007 (confusing, cluttered the page and had little point). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Duck typing is a principle of dynamic typing in which an object's current set of methods and properties determines the valid semantics, rather than its inheritance from a particular class.

The term is a reference to the duck test

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.

In this context though, it's more correct to say, "I can treat that bird as being like a duck, in at least some aspect".

Unfortunately the term has been popularised by its cute formation from a well-known quotation, rather than through its accuracy or ability to explain the concept. It's misleading in that it's usually applied to languages that actually contradict this "It's a duck" notion.

The scope of dynamic typing is just that of the method call(s), not the entire use of the object. For our purposes we don't care if the object supports both quacking and walking, just what's required at the time. It's fundamental that an inability to swim should not rule out use of the quack behaviour, even if it means that the object couldn't thus be "a true and complete duck".

Alex Martelli made an early (2000) use of the term in a message to the comp.lang.python newsgroup. He also highlighted this misunderstanding of the literal duck test, which may indicate that the term was already in use. [citation needed]

In other words, don't check whether it IS-a duck: check whether it QUACKS-like-a duck, WALKS-like-a duck, etc, etc,
depending on exactly what subset of duck-like behaviour you need to play your language-games with.

Java and other languages have explicit constructs called interfaces which Languages (e.g. Java) may define interfaces which are then used in an inheritance-like manner. These are not usually considered to be duck typed languages. However if they implement a duck interface that defines the set of expected behaviours as a single unit, then they are actually closer to the literal "duck test" view than languages considered to be duck typed (e.g. Python) that test compatibility on a method-by-method basis, in a more truly dynamic manner.

Dynamic typing across languages

Dynamic typing allows an object to be interchangeable with any other object so long as they both implement sufficiently useful interfaces, regardless of whether the objects have a related inheritance hierarchy. Duck typing is a feature of programming languages such as Smalltalk, Python, Objective-C, Ruby, JavaScript, and ColdFusion.

In Smalltalk, any object is interchangeable with any other at runtime. This is the most flexible kind of dynamic typing. Duck typing attempts to limit this flexibility while eliminating a source of possible errors before runtime. The Smalltalk architects sought to achieve true polymorphism at the expense of possible errors creeping in at runtime. In practice, these errors are dealt with, at runtime, via SUnit testing.

Abstract data types are static interfaces that exist only to guarantee, on paper, a particular interface. Smalltalk uses pure dynamic mechanisms, in a variety of ways, to extend the guarantee in practice. This can be as simple as generalizing the "method not found" exception handler into a catch-all lookup mechanism. But it can involve extending the language or environment, as in StrongTalk. Parallels to Smalltalk's exception handling came to be called duck typing in Java and Python, and a single reasonable syntax emerged.

C++ templates implement a static form of duck typing. An iterator, for example, does not inherit its methods from an Iterator base class.

Yet another approach similar to duck typing is OCaml's structural subtyping, where object types are compatible if their method signatures are compatible, regardless of their declared inheritance. This is all detected at compile time through OCaml's type inference system.

In Python

Duck typing is heavily used in Python. The Python Tutorial's Glossary defines duck typing as follows:

Pythonic programming style that determines an object's type by inspection of its method or attribute signature rather than by explicit relationship to some type object ("If it looks like a duck and quacks like a duck, it must be a duck.") By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using type() or isinstance(). Instead, it typically employs hasattr() tests or EAFP (Easier to Ask Forgiveness than Permission) programming.

The standard example of duck typing in Python is file-like classes. Classes can implement some or all of the methods of file and can be used where file would normally be used. For example, GzipFile implements a file-like object for accessing gzip-compressed data. cStringIO allows treating a Python string as a file. Sockets and files share many of the same methods as well. However, sockets lack the tell() method and cannot be used everywhere that GzipFile can be used. This shows the flexibility of duck typing: a file-like object can implement only methods it is able to, and consequently it can be only used in situations where it makes sense.

In Ruby

Duck typing is a fundamental part of ruby coding. The pickaxe book (Programming Ruby), written by Dave Thomas, has a more complete description of duck typing, explaining its perils and benefits.

In Java

In addition to C++-style inheritance, Java supports "interfaces" which allow for role-based typing, which provides the same benefit as duck typing: being able to view an instance of a class through different roles. Interfaces are explicitly defined in Java, and are therefore a bit more restrictive than duck typing.

In Objective-C

In Objective-C you can refer to a class using the type(less) id. The Objective-C runtime will then map a message to such an object by resolving the adequate method without checking for a type. The question, whether an object has a method for a message is not a question of class.

You can send such a message explicitly or implicitly:

id anObject = … // An object of any class implementing -walkAndQuack

[anObject walkAndQuack]; // implicit call
[anObject performSelector:@selector( walkAndQuack )]; // explicit call

You can check at run-time, whether a particular method is implemented using -respondsToSelector:.

The feature is used extensively with delegates delegates in many classes in the Cocoa API. You may assign a delegate using e.g. [foo setDelegate:bar], and at run-time, foo will check for whether bar responds to the message.[1]

In ColdFusion

The web application scripting language ColdFusion allows function arguments to be specified as having type any. For this sort of argument, an arbitrary object can be passed in and method calls are bound dynamically at runtime. If an object does not implement a called method, a runtime exception is thrown which can be caught and handled gracefully. An alternative argument type of WEB-INF.cftags.component restricts the passed argument to be a ColdFusion Component (CFC), which provides better error messages should a non-object be passed in.

Comparison with generics and structural subtyping

In C++ and some other languages, very flexible static binding capabilities, called generics, templates, and operator overloading, provide some of the same advantages, but typically not as late as run time. This static polymorphism is distinguished from runtime facilities for dynamic types.

References

  1. ^ Apple, Inc. (27 June 2005). "Delegating Authority - Cocoa Delegation and Notification". Retrieved 2007-08-01. {{cite web}}: Check date values in: |year= (help); Unknown parameter |= ignored (help)CS1 maint: year (link)