duck operator

Crazy idea for today – operator to check conformance to specific interface without actually implementing it. Why one would want that?
Well, if you are into duck typing style of programming, it may be interesting for you to have an object that implements certain set of functions, but not necessary declares it at class definition. Languages like Smalltalk do it all day along, so why PHP couldn’t? The idea is it looks like this:

interface Cow {
  function moo();
  function eatGrass();
}
/* somewhere else */
class MooingGrassEater {
  function moo() {/*stuff */}
  function eatGrass() {/*stuff */}
  /*stuff */
}
/* somewhere else */
function CowConsumer($classname) {
$foo = new $classname();
if($foo implements Cow) {
  echo "Behold the cow:";
  $foo->eatGrass();
  $foo->moo();
} else {
  echo "$classname is not a cow!";
}

implements here is our duck operator. Note that unlike instanceof, no formal relationship is required, but only practical implementation. So another name would be “common law marriage operator” ;)

Of course, this one would be anathema to “strict OO” camp, so if you subscribe to that, just ignore this post :)

Two challenges to this idea are:

  1. __call() – we have no way to know what __call does. So either we ignore it or say “ok, __call does everything”. I’d go for the latter.
  2. Performance. To check duck implementation one basically would have to match method lists, which amounts to number of is_callable calls equal to the number of methods in interface being checked.

Actually, PHP uses this style sometimes – see, for example, user defined streams. But there’s no nice way to work with it from the consumer side.

About these ads

15 thoughts on “duck operator

  1. Hmm. I think that duck typing will result in code reminiscent of a huge heap of stinking guano.

    I can’t see one good reason in your example for actually coding things that way. What’s wrong with an interface – a known contract for operating on an object?

    Exceptions are a very inefficient way of handling logic. They should only be used to catch errors that you can’t possibly predict or account for. If you *know* that a function might not be there, you should check its existence first, avoiding an exception altogether.

    Don’t encourage sloppy practices! PHP is full enough of them already. This is not from a strict OO camp. This is from the general sanity camp.

  2. Pingback: Jon Lebensold » Blog Archive » PHP: What is Duck Typing?

  3. One interesting difference compared to formal declaration (explicit interface implementation) is that the duck operator would presumably take visibility into account. I assume this, since you talk about implementing it with is_callable(), which iirc does visibility checks.

    So, for example, in a context where MooingGrassEater’s moo() method is visible, it would be considered to “implement” Cow. But from a different context where moo() is not visible, it wouldn’t be considered to “implement” Cow.

    Would only the method name be used for comparison? What about differing parameter pass semantics (value vs ref), type hints, default values etc…?

  4. Thierry Stiegler, NiKo – that’s for formal declarations. I was talking about informal contract implementation.

    Alan – optional interfaces would be a nice idea too, but different one :)

  5. Gosha, I think you need to chill a bit. And if for some reason, incomprehensible to me, you are interested in my national roots – I’m Jewish. The comments here are moderated, thanks to our friends the spammers. Unfortunately, I have some things of little importance to do besides the blog – like work, personal life, etc. – so approving comments sometimes could take forever, like a day. Sorry about that.

    Now with that out of the way, to the exception thing. You can do that easily with __call, but I see no reason why – throwing exceptions left in right is not really the style I’d like.

  6. You can do this to

    <?php
    interface Mooer {
    function moo();
    }

    class Cow implements Mooer {
    function moo() {
    echo ‘moo!';
    }
    }

    var_dump(new Cow() instanceof Mooer); // bool(true)

  7. At first glance, this seems like a bad idea. It seems to me to be horribly dangerous to assume that functions eatGrass() and moo() do “what you’d expect” from such named functions based solely on their existence.

    I just can’t imagine how this is a good practice. If you expect a class to implement a function with a given name, then check for it directly with is_callable. I don’t see much of a need to automate this over a set of functions.

    What you are discussing is essentially what Objective-C calls informal protocols.

    An informal protocol is a *definition* of a set of related methods, not all of which have to be implemented. Callers can then just check the existence of the desired function(s) and call them as needed. Informal protocols are just interfaces where the methods are OPTIONAL.

    I use this concept a lot in my PHOCOA framework. You can read more at http://phocoa.com.

  8. Pingback: PHP 10.0 Blog: duck operator | Development Blog With Code Updates : Developercast.com

  9. Pingback: PHP 10.0 Blog: duck operator | Michael Kimsal’s weblog

  10. good job deleting comments, my friend.
    actually, my failure: haven’t noticed from the start you’re russian – that explains a lot.
    gday

  11. Pingback: Implementing a Duck Operator with Reflection | Mats Lindh

  12. Well, i like the idea. Actually i’ve started a RFC yesterday. It’s in german currently but i’ll publish it in english if i’ve reviewed it with a friend.

    But in short:
    I’m differing three concepts. First are concrete interfaces, the current implementation. Second are implicit interfaces. In that case every class (or trait) is an interface and is comparable to each other without implementing and concrete interface (‘interface’ is not needed anymore). Third are duck interfaces. Which work like implicit interfaces but additionally every subset of an class can also be an interface.

    Example with implicit interfaces:
    class SplCountable {
    function count(){}
    }
    class FooCountable {
    function count(){}
    }
    class List implements SplCountable {
    function add($value){}
    function count(){}
    }
    new List instanceof FooCountable; // true
    new List instanceof SplCountable; // true

    Mention that you need to implement (or extend) one of the classes with the same signature!

    Example with duck interfaces:
    class Countable {
    function count(){}
    }
    class List {
    function add($value){}
    function count(){}
    }
    new List instanceof Countable; // true

    The good thing is that there are no more hardwired interfaces needed, so you have less dependencies and more flexibility. The downside is, like you noticed, the performance. Implicit interfaces will do the interface stuff for every class, so it’s an overall performance payoff. Duck interfaces require more performance for each comparison at runtime. For duck interfaces it’s an good idea to use another operator, like in your example.

    Good to see that i’m not alone with my ideas :)

  13. From my understanding, “if($foo implements Cow)..” is not what they call “duck typing” or is not “ducky” enough. Ideally we should be able to do it in a “dont ask, do” way


    try {
    $foo->eatGrass();
    } catch(UnknownMethodException $e) {
    ...
    }

    What? Zend Engine still doesn’t support this? Shame on them. ;)

  14. which amounts to number of is_callable calls equal to the number of methods in interface being checked

    not exactly.
    Actually, it would be: number of methods you are going to use on that class (interface might be wider, and there are good chances, that you don’t need all of its methods)

Comments are closed.