Re: Protocols
On Wednesday, July 23, 2003, at 05:57 PM, chromatic wrote: The first is a deeper question -- besides inheritance, there's delegation, aggregation, and reimplementation (think mock objects) that can make two classes have equivalent interfaces. I'd like some way to mark this equivalence *without* having to inherit from an abstract base class and I wish that interface equivalence were checked before inheritance, as per Luke's idea. Sounds like you want Java-style interfaces to me. Regards, David -- David Wheeler AIM: dwTheory [EMAIL PROTECTED] ICQ: 15726394 http://kineticode.com/ Yahoo!: dew7e Jabber: [EMAIL PROTECTED] Kineticode. Setting knowledge in motion.[sm]
Re: Protocols
On Thursday, July 24, 2003, at 09:25 AM, Kurt Starsinic wrote: Sounds like you want Java-style interfaces to me. Follow the thread back. Objective-C had them way first, and their ur-name is protocols. D'oh! Sorry, I had read that, but then forgot. David -- David Wheeler AIM: dwTheory [EMAIL PROTECTED] ICQ: 15726394 http://kineticode.com/ Yahoo!: dew7e Jabber: [EMAIL PROTECTED] Kineticode. Setting knowledge in motion.[sm]
Re: Protocols
On Thursday, July 24, 2003, at 08:49 AM, David Wheeler wrote: On Wednesday, July 23, 2003, at 05:57 PM, chromatic wrote: The first is a deeper question -- besides inheritance, there's delegation, aggregation, and reimplementation (think mock objects) that can make two classes have equivalent interfaces. I'd like some way to mark this equivalence *without* having to inherit from an abstract base class and I wish that interface equivalence were checked before inheritance, as per Luke's idea. Sounds like you want Java-style interfaces to me. No, I think Java interfaces are a kluge to get around copying a broken type system and the lack of multiple inheritance. I don't want to litter both the caller and the callee with interface declarations that do nothing but say this thing here understands the same methods as that thing there. The caller, fine -- that's the place it belongs. If I have to modify the callee to do this, I've insufficient polymorphism. Think of it this way. If you write Perl 5 code like this: sub some_method { my $self = shift; die Bad object unless ref $self = 'Some::Class'; # do something useful... } someone will have to change or override some_method() if he wants to subclass it. You could make his life a little easier by writing: sub some_method { my $self = shift; die Bad object unless $self-isa( 'Some::Class' ); # do something useful... } I'm suggesting to go the next step and let the code say, Hey, if it acts like an instance of Some::Class, I don't care where it gets its behavior. I'll treat it like an instance of Some::Class. That's what I do with Class::ActsLike, and that's what I'd like to see here: sub some_method { my $self = shift; die Bad object unless $self-acts_like( 'Some::Class' ); # do something useful... } Now it doesn't care whether I've inherited, aggregated, delegated, or reimplemented. My argument is that it shouldn't have to care. It should only care that I've somehow promised that what I'm passing in behaves like it expects it to behave. How it does that is uninteresting. -- c
Re: Protocols
--- chromatic [EMAIL PROTECTED] wrote: On Thursday, July 24, 2003, at 08:49 AM, David Wheeler wrote: On Wednesday, July 23, 2003, at 05:57 PM, chromatic wrote: The first is a deeper question -- besides inheritance, there's delegation, aggregation, and reimplementation (think mock objects) that can make two classes have equivalent interfaces. I'd like some way to mark this equivalence *without* having to inherit from an abstract base class and I wish that interface equivalence were checked before inheritance, as per Luke's idea. Sounds like you want Java-style interfaces to me. No, I think Java interfaces are a kluge to get around copying a broken type system and the lack of multiple inheritance. Multiple Inheritance != Protocols | Interfaces How much C++ code have you seen with unused stuff in the objects because I had to inherit from that class to get the MI behavior I wanted, but I no longer use those attributes. Protocols/Interfaces is a way of saying My structure is none of your damn business, but I comply with the rules you've set. MI, on the other hand, can be implemented with a protocol and a has-a relationship, albeit at a significant cost in coding dispatch methods. There's an argument for supporting both. class Foo is all(DessertTopping, FloorWax) { } I don't want to litter both the caller and the callee with interface declarations that do nothing but say this thing here understands the same methods as that thing there. The caller, fine -- that's the place it belongs. I disagree, and I hope you've simply swapped terms around. I think you want to declare I comply with ruleset X at the callee object level. That enables the compiler to (1) check that you're not lying; and (2) optimize based on (1). If I have to modify the callee to do this, I've insufficient polymorphism. At the caller side, you want to say I require something which complies with ruleset X and have it be enforced to a user-configurable extent. Obviously calling a method which doesn't exist should be an error. But (especially in large systems) it should be possible to slack off on the call-side checking, because you know you're doing the checking on the callee side at compile time. Think of it this way. If you write Perl 5 code like this: sub some_method { my $self = shift; die Bad object unless ref $self = 'Some::Class'; # do something useful... } someone will have to change or override some_method() if he wants to subclass it. You could make his life a little easier by writing: sub some_method { my $self = shift; die Bad object unless $self-isa( 'Some::Class' ); # do something useful... } I'm suggesting to go the next step and let the code say, Hey, if it acts like an instance of Some::Class, I don't care where it gets its behavior. I'll treat it like an instance of Some::Class. That's what I do with Class::ActsLike, and that's what I'd like to see here: sub some_method { my $self = shift; die Bad object unless $self-acts_like( 'Some::Class' ); # do something useful... } I notice all this is on the callee side. I'm hoping you swapped er/ee above. Now it doesn't care whether I've inherited, aggregated, delegated, or reimplemented. My argument is that it shouldn't have to care. It should only care that I've somehow promised that what I'm passing in behaves like it expects it to behave. How it does that is uninteresting. I agree. Luke agrees. The extent to which this is formalized is open for discussion, but I think Damian doesn't agree (see his example some time back about class Dog vs. class Tree). =Austin
Re: Protocols
On Thursday, July 24, 2003, at 11:17 AM, Austin Hastings wrote: No, I think Java interfaces are a kluge to get around copying a broken type system and the lack of multiple inheritance. Multiple Inheritance != Protocols | Interfaces I quite agree, but I've done enough Java to know that if they could have solved it with MI, they would have. Protocols/Interfaces is a way of saying My structure is none of your damn business, but I comply with the rules you've set. Yes, exactly. I disagree, and I hope you've simply swapped terms around. I think you want to declare I comply with ruleset X at the callee object level. That enables the compiler to (1) check that you're not lying; and (2) optimize based on (1). At least one of us is using caller/callee in the X11 sense. What I mean and what I think you mean is: method foo ( Thingie $t ) { ... } $object-foo( $behaves_like_thingie ); foo() says, Give me something that I can treat like a Thingie. I don't care HOW it does it, I just want it to do something sane. $behaves_like_thingie is an instance of a class that somehow says, Hey, I act like Thingie. I'm substitutable for Thingie if you don't break my encapsulation. If we're just confused over a bit of terminology, we're in violent agreement on the idea, which is much more important. -- c
Re: Protocols
--- chromatic [EMAIL PROTECTED] wrote: On Thursday, July 24, 2003, at 11:17 AM, Austin Hastings wrote: No, I think Java interfaces are a kluge to get around copying a broken type system and the lack of multiple inheritance. Multiple Inheritance != Protocols | Interfaces I quite agree, but I've done enough Java to know that if they could have solved it with MI, they would have. Protocols/Interfaces is a way of saying My structure is none of your damn business, but I comply with the rules you've set. Yes, exactly. I disagree, and I hope you've simply swapped terms around. I think you want to declare I comply with ruleset X at the callee object level. That enables the compiler to (1) check that you're not lying; and (2) optimize based on (1). At least one of us is using caller/callee in the X11 sense. What I mean and what I think you mean is: method foo ( Thingie $t ) { ... } $object-foo( $behaves_like_thingie ); foo() says, Give me something that I can treat like a Thingie. I don't care HOW it does it, I just want it to do something sane. To me, $object.Class is the callee (includes method foo). The code that contains C$object-foo($behaves_like_thingie); is the caller. If we're just confused over a bit of terminology, we're in violent agreement on the idea, which is much more important. Yeah. So what do we get? # Multiple Inheritance: class Combo is all(SuperClass1, SuperClass2, ...) {...} class Comb2 is Super1 is Super2 {...} # Protocol: # More than just an interface, because Perl6 is okay with # loose encapsulation protocol TCPIP { has $.variable; # Protocol requires this variable has $.var2 is Array of Int; # Ditto method Int m1(Int, Str) {...} # Method required } Going one step farther, there's a function called protocol and maybe one called class that handle this sort of thing. Also, Cis means Cimplements when given a protocol, and Cimplements extracts a default protocol when given a class. class Scalar implements Str implements Int implements Ref {...} # All you need to know. class MyArray is class(Array) # Convert PCL to Class Perverse behavior: # Converts protocol TCPIP, above, to anon class, inherits. class Perv is class(TCPIP) {...} # Converts Super2 to Protocol, implements it. class Perv2 is Super1 implements Super2 {...} class Perv2 is Super1 is protocol(Super2) {...} # Alternatively, select any of: # {private, protected, public}_methods (or methods = public) # {private, protected, public}_data (data = public) # inheritance class Perv2 is Super1 implements Super2, qw(methods inheritance) {...} class Perv2 is Super1 is protocol(Super2, qw(methods inheritance)) {...} =Austin
Re: Protocols
On Jul 24, David Wheeler wrote: On Wednesday, July 23, 2003, at 05:57 PM, chromatic wrote: The first is a deeper question -- besides inheritance, there's delegation, aggregation, and reimplementation (think mock objects) that can make two classes have equivalent interfaces. I'd like some way to mark this equivalence *without* having to inherit from an abstract base class and I wish that interface equivalence were checked before inheritance, as per Luke's idea. Sounds like you want Java-style interfaces to me. Follow the thread back. Objective-C had them way first, and their ur-name is protocols. - Kurt
Re: Protocols
Chromatic wrote: [snip] I think you want to declare I comply with ruleset X at the callee object level. That enables the compiler to (1) check that you're not lying; and (2) optimize based on (1). At least one of us is using caller/callee in the X11 sense. What I mean and what I think you mean is: method foo ( Thingie $t ) { ... } $object-foo( $behaves_like_thingie ); foo() says, Give me something that I can treat like a Thingie. I don't care HOW it does it, I just want it to do something sane. $behaves_like_thingie is an instance of a class that somehow says, Hey, I act like Thingie. I'm substitutable for Thingie if you don't break my encapsulation. If this were Java, the way to do this would be to define a Thingie interface, and then an (archetypical) ThingieObject class... any time that we want to actually *create* Thingies, we would use new ThingieObject, but everywhere else, we would use the typename Thingie. This way, when we want a class which acts like a Thingie, but without inheriting any of it's innards, simply implement the Thingie interface, instead of inheriting the ThingyObject class. idea type=wierd Here's a possible idea -- have a method of the Class class, which returns (creates) an anonymous Interface object, which provides all of the public methods of that class, and which is magically one of the parents of that class. This way, when one wants to define a new class X which acts like some other class Y, but which doesn't *really* inherit from Y (none of the internal data, etc.), we can define X as implementing the Y.interface() Interface. For our isa operator, and (perhaps more importantly) for multimethod dispatch and/or sub prototype checking, we only check if an object inherits from a class's magic parent interface, and *don't* check if it *really* inherits from that class itself. /idea Of course, this by itself wouldn't let us delegate to the ThingyObject's versions of the methods... that would require another extra layer of nonsense^Windirection. If we're just confused over a bit of terminology, we're in violent agreement on the idea, which is much more important. -- $a=24;split//,240513;s/\B/ = /for@@=qw(ac ab bc ba cb ca );{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print [EMAIL PROTECTED] ]\n;((6=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))redo;}
Re: Protocols
On Thursday, July 24, 2003, at 05:28 PM, Benjamin Goldberg wrote: If this were Java, the way to do this would be to define a Thingie interface, and then an (archetypical) ThingieObject class... any time that we want to actually *create* Thingies, we would use new ThingieObject, but everywhere else, we would use the typename Thingie. This way, when we want a class which acts like a Thingie, but without inheriting any of it's innards, simply implement the Thingie interface, instead of inheriting the ThingyObject class. Yes, that's the Java way to do it. Surely we can do it better in Perl 6. The problem with Java interfaces is that you have to rely on the library writer to have expected you to use an interface. Given the amount of CPAN modules that, for example, expect a glob and preclude me from passing in an IO::Handle with code like this: croak Need a glob unless ref $thingie eq 'GLOB'; I'm not sure that the Java style is helpful. I'd rather not multiply entities needlessly. For our isa operator, and (perhaps more importantly) for multimethod dispatch and/or sub prototype checking, we only check if an object inherits from a class's magic parent interface, and *don't* check if it *really* inherits from that class itself. heretic Why should an implementor inherit from the interface? If inheritance and polymorphic equivalence are two different things, they ought to be handled two different ways. If anything, inheritance is a specific case of the general mechanism of marking polymorphic equivalence. Again, the interesting question isn't Does this thing derive from something I know about? It's Does this thing support the operations I expect it to support? I don't care how, just that it does. I don't want to call $mock_foo-isa( 'foo' ) because $mock_foo *isn't* a foo. I don't want to call $delegates_to_foo-isa( 'foo' ) because $delegates_to_foo *isn't* a foo. They can both handle foo-methods, but neither is a foo. /heretic -- c