On duck typing and interfaces

I was looking at different type systems (apparently there are 4 dimensions) in different languages and ran across this use of duck typing in C# :

For example, the C#’s foreach operator already uses duck typing. This might be surprising to some, but to support foreach in C# you don’t need to implement IEnumerable! All you have to do is:



Provide a public method GetEnumerator that takes no parameters and returns a type that has two members: a) a method MoveMext that takes no parameters and return a Boolean, and b) a property Current with a getter that returns an Object.

Do you have multiple fine-grained interfaces (like IEnumerable and IEnumerator and ISupportsAdd) or a single interface with all the methods and maybe they throw UnsupportedOperationExceptions if they don’t actually support a particular call (like in a mutable versus immutable collection)?

The closer you get to more fine grained interfaces like ISupportsAdd<T> or Closeable, defining a contract for a single method Add(T obj) or Close is that you might as well just ask the class if it has that method (if it “quacks”) instead of whether it implemented a single method interface. Better yet, just assume it and let it throw an error at runtime. Whatever the compiler doesn’t give you, some decent test coverage will.

But what strikes me as particularly great is that foreach is obviously such a powerful thing to restrict to a single interface, and so they chose “Duck Notation”, because in this case it is worth it.

This reminded me of why I like ecma 4 (and its derivatives like actionscript). You have freedom to use static and dynamic typing at will.

If you check out my take on an AS3 HTTP client library, HttpRequest class and allowing the request body to be of any type:

public class HttpRequest {
 
  // Request method. For example, "GET"
  protected var _method:String;
 
  // Request header
  protected var _header:HttpHeader;
 
  // Request body
  protected var _body:*;
 
  /**
   * Create request.
   *  
   * The request body can be anything but should respond to:
   *  - readBytes(bytes:ByteArray, offset:uint, length:uint)
   *  - length
   *  - bytesAvailable
   *  - close
   *  
   * @param method HTTP Method, for example 'GET'
   * @param header HTTP request header (or null)
   * @param body HTTP request body (or null)
   *  
   */
  public function HttpRequest(method:String, header:HttpHeader = null, body:* = null) {
    _method = method;
    _header = header;      
    _body = body;
 
 ...

I think this is a good choice because:

  1. The IDataInput interface (that ByteArray already implements) doesn’t have a length property and we need to know the request body size (Content-Length) before we send.
  2. The IDataInput interface wants you to implement a ton of read methods, which would make it annoying to force people to implement.
  3. ByteArray has these methods and also implements the length property already. It quacks.
  4. If we created our own interface with these methods, we can’t add this interface retroactively to ByteArray.
  5. I wrote it. Heh.

The other option is to subclass ByteArray and have that implement the new interface, but it just seems awkward (in this case) having any empty subclass solely for the point of enforcing an interface.

Another place where this principle applied for me is in HttpSocket. We need to support both Socket (for http) and TLSSocket (for https). TLSSocket has all the same (mostly) methods as Socket (but does not extend Socket; yay for composition over inheritance). Creating a proxy to delegate to different socket implementations based on the http scheme is an option but to me wasn’t worth it. And using a design pattern to overcome the lack of an appropriate and existing interface just seems to make things worse.

Tags: , ,

One Response to “On duck typing and interfaces”

  1. rel=me » Blog Archive » Moved Says:

    [...] class of type system was a bad idea. I mean, duck (or structural) typing shows up everywhere, C# (foreach), delegates in Cocoa; anywhere you have dynamic typing and loose bindings. But its just a style or [...]

Leave a Reply