I've been looking around Objective-C a bit, and I would like to turn over an old rock.
Remember when I suggested that (static) type equivalence should be based on interface equivalence? Objective-C seems to feel the same way. It calls an interface a I<protocol>, and specifying it is optional. This maps nicely into Perl's distinction between typed an untyped variables. In Objective-C: id untyped = somefunction(); id<Foo> typed = otherfunction(); If you send a message to C<typed> which isn't in the C<Foo> protocol definition, you get warnings. Depending on the implementation, that assignment might be dynamically interface-checked. Objective-C had one difference from my proposal, which, upon reading it, I like. There is a distinction between a real object and a protocol. You can supply the name of a class, and the object has to (well, as much as anything I<has to>) be a real object of that class. If you supply the name of a protocol, its interface just has to conform. Objective-C makes a lexical distinction on the user side, which I don't think is so Perlish. So, here's my new proposal. my Type $x = func(); $x.meth; First, C<Type> is allowed to be both an interface (my name for I<protocol>) and a class, even at the same time. When checking, the interface takes precedence, but that can be overridden with some trait. At compile time, if func() has a visibly declared return value, it is checked against C<Type>. If C<Type> is an interface, then func()'s return type is checked to make sure that it supports all methods that C<Type> declares. If C<Type> is a real class and func() is a real class, they are checked for family relationship. Finally, if C<Type> is a real class and func() is an interface, checking is deferred until runtime (with a warning under some pragmatic setting). Then, still at compile time, C<Type> is checked to make sure it provides C<meth>. At runtime on the first statement, no checking needs to be done if C<Type> is an interface (unless func() didn't explicate a return type). If C<Type> is real, a family relationship test is done. And that's all. It's very lenient, but it catches most of the errors any Java-like type system[1] would catch, hopefully without getting in the way. And to make type checking even less explicit, there might be a feature which would scan (as much as possible) the body of a function and generate interfaces for the variables in the signature based on how you use them. That would be neat. Luke [1] It would be totally cool to use a Haskell- or ML-style type inference system, but those things just don't work in procedural languages.