views:

726

answers:

11

Can I specify interfaces when I declare a member?

After thinking about this question for a while, it occurred to me that a static-duck-typed language might actually work. Why can't predefined classes be bound to an interface at compile time? Example:

public interface IMyInterface
{
  public void MyMethod();
}

public class MyClass  //Does not explicitly implement IMyInterface
{
  public void MyMethod()  //But contains a compatible method definition
  {
    Console.WriteLine("Hello, world!");
  }
}

...

public void CallMyMethod(IMyInterface m)
{
  m.MyMethod();
}

...

MyClass obj = new MyClass();
CallMyMethod(obj);     // Automatically recognize that MyClass "fits" 
                       // MyInterface, and force a type-cast.

Do you know of any languages that support such a feature? Would it be helpful in Java or C#? Is it fundamentally flawed in some way? I understand you could subclass MyClass and implement the interface or use the Adapter design pattern to accomplish the same thing, but those approaches just seem like unnecessary boilerplate code.

+7  A: 

I don't see the point. Why not be explicit that the class implements the interface and have done with it? Implementing the interface is what tells other programmers that this class is supposed to behave in the way that interface defines. Simply having the same name and signature on a method conveys no guarantees that the intent of the designer was to perform similar actions with the method. That may be, but why leave it up for interpretation (and misuse)?

The reason you can "get away" with this successfully in dynamic languages has more to do with TDD than with the language itself. In my opinion, if the language offers the facility to give these sorts of guidance to others who use/view the code, you should use it. It actually improves clarity and is worth the few extra characters. In the case where you don't have access to do this, then an Adapter serves the same purpose of explicitly declaring how the interface relates to the other class.

tvanfosson
I agree, thats the point of an interface, to describe what something is. Use it whereever you can, its not boilerplate code, its good practice.
Mark
Why is this pattern successful in dynamic languages, but would be considered bad practice in static languages? What does TDD have to do with it that's unique to dynamic typing? As @mipadi mentioned, why can't OO languages support a sort of Haskell-style type-inference system?
Cybis
From my limited understanding of it, Java generics are just a round about way of doing what amounts to duck type.
James McMahon
@James: sorry, but no. Java generics are what amounts to automatic casts to/from the Object type. You can't write code like the one shown above.
Martinho Fernandes
+1  A: 

A pre-release design for Visual Basic 9 had support for static duck typing using dynamic interfaces but they cut the feature* in order to ship on time.

Mark Cidade
+6  A: 

Statically-typed languages, by definition, check types at compile time, not run time. One of the obvious problems with the system described above is that the compiler is going to check types when the program is compiled, not at run time.

Now, you could build more intelligence into the compiler so it could derive types, rather than having the programmer explicitly declare types; the compiler might be able to see that MyClass implements a MyMethod() method, and handle this case accordingly, without the need to explicitly declare interfaces (as you suggest). Such a compiler could utilize type inference, such as Hindley-Milner.

Of course, some statically typed languages like Haskell already do something similar to what you suggest; the Haskell compiler is able to infer types (most of the time) without the need to explicitly declare them. But obviously, Java/C# don't have this ability.

mipadi
Thanks. I've just started learning Haskell about a week ago and so far it seems pretty cool. It's a bit of a learning curve though - never really got into functional languages before. Anyway, its type inference system is a lot like what I'm referring to.
Cybis
C# seems to have Type inference. For example, this article talks about it. http://www.developer.com/net/csharp/article.php/3601646/Go-Inside-C-30s-Type-Inference-Process.htm
John K
+2  A: 

Boo definitely is a static duck-typed language: http://boo.codehaus.org/Duck+Typing

An excerpt:

Boo is a statically typed language, like Java or C#. This means your boo applications will run about as fast as those coded in other statically typed languages for .NET or Mono. But using a statically typed language sometimes constrains you to an inflexible and verbose coding style, with the sometimes necessary type declarations (like "x as int", but this is not often necessary due to boo's Type Inference) and sometimes necessary type casts (see Casting Types). Boo's support for Type Inference and eventually generics help here, but...

Sometimes it is appropriate to give up the safety net provided by static typing. Maybe you just want to explore an API without worrying too much about method signatures or maybe you're creating code that talks to external components such as COM objects. Either way the choice should be yours not mine.

Along with the normal types like object, int, string...boo has a special type called "duck". The term is inspired by the ruby programming language's duck typing feature ("If it walks like a duck and quacks like a duck, it must be a duck").

torial
A static language with duck typing isn't the same as static duck typing. Both existing VB and the upcoming C# 4.0 have static typing and dynamic/late-bound/duck typing
Mark Cidade
I don't mean a mix of static and dynamic typing (which seems to be what you're referring to, torial). I'm referring to type-inference - the compiler being able to see immediately that MyClass and IMyInterface are compatible without the programmer making the relationship explicit.
Cybis
My bad. Boo will not do that for you.
torial
+5  A: 

F# supports static duck typing, though with a catch: you have to use member constraints. Details are available in this blog entry.

Example from the cited blog:

let inline speak (a: ^a) =
    let x = (^a : (member speak: unit -> string) (a))
    printfn "It said: %s" x
    let y = (^a : (member talk: unit -> string) (a))
    printfn "Then it said %s" y

type duck() =
    member x.speak() = "quack"
    member x.talk() = "quackity quack"
type dog() =
    member x.speak() = "woof"
    member x.talk() = "arrrr"

let x = new duck()
let y = new dog()
speak x
speak y
Joh
+6  A: 

How about using templates in C++?

class IMyInterface  // Inheritance from this is optional
{
public:
  virtual void MyMethod() = 0;
}

class MyClass  // Does not explicitly implement IMyInterface
{
public:
  void MyMethod()  // But contains a compatible method definition
  {
    std::cout << "Hello, world!" "\n";
  }
}

template<typename MyInterface>
void CallMyMethod(MyInterface& m)
{
  m.MyMethod();  // instantiation succeeds iff MyInterface has MyMethod
}

MyClass obj;
CallMyMethod(obj);     // Automatically generate code with MyClass as 
                       // MyInterface

I haven't actually compiled this code, but I believe it's workable and a pretty trivial C++-ization of the original proposed (but nonworking) code.

John Zwinck
Someone did mention C++ templates, but I think that answer got deleted. Anyway, templates are basically just advanced macros. A new "CallMyMethod" is created for each different type you pass to it, so it's not really type inference.
Cybis
Furthermore, I don't know of a good C++ IDE with intellisense that doesn't get confused on templates (Visual Studio's doesn't always list all choices, and sometimes it stops entirely).
Cybis
To be fair, the original poster didn't mention type inference *per se* at all. I just tweaked his code slightly and showed that it can work in C++ pretty much as-is.
John Zwinck
I can't understand how people still think that C++ templates are just advanced macros, it's a turing complete programming mechanism, not a text replacement tool.
swegi
+2  A: 

Structural types in Scala does somthing like this.

http://neilbartlett.name/blog/2007/09/13/statically-checked-duck-typing-in-scala/

John Nilsson
+2  A: 

Most of the languages in the ML family support structural types with inference and constrained type schemes, which is the geeky language-designer terminology that seems most likely what you mean by the phrase "static duck-typing" in the original question.

The more popular languages in this family that spring to mind include: Haskell, Objective Caml, F# and Scala. The one that most closely matches your example, of course, would be Objective Caml. Here's a translation of your example:

open Printf

class type iMyInterface = object
  method myMethod: unit
end

class myClass = object
  method myMethod = printf "Hello, world!"
end

let callMyMethod: #iMyInterface -> unit = fun m -> m#myMethod

let myClass = new myClass

callMyMethod myClass

Note: some of the names you used have to be changed to comply with OCaml's notion of identifier case semantics, but otherwise, this is a pretty straightforward translation.

Also, worth noting, neither the type annotation in the callMyMethod function nor the definition of the iMyInterface class type is strictly necessary. Objective Caml can infer everything in your example without any type declarations at all.

james woodyatt
+2  A: 

A brand new answer to this question, Go has exactly this feature. I think it's really cool & clever (though I'll be interested to see how it plays out in real life) and kudos on thinking of it.

Grumdrig
A: 

In the latest version of my programming language Heron it supports something similar through a structural-subtyping coercion operator called as. So instead of:

MyClass obj = new MyClass();
CallMyMethod(obj);

You would write:

MyClass obj = new MyClass();
CallMyMethod(obj as IMyInterface);

Just like in your example, in this case MyClass does not have to explicitly implement IMyInterface, but if it did the cast could happen implicitly and the as operator could be omitted.

I wrote a bit more about the technique which I call explicit structural sub-typing in this article.

cdiggins