I am not very good at OO but I tried at least 2 times to develop with it though :-)
Last time it was Java. The problem is that when i going to use some 'standard' class
or 3d party class i'd rather to cut off all unnecessary methods (and may be even properies!),
then adding my own. I know it kills inheritance but it is much more to my Perl habit of hacking code.
example:
Class a {
method getX;
method getY;
method size;
method area;
method move;
}
I'd like to write
Class myclass : a {
forget method area;
forget method move;
method put;
}
so methods getX, getY, size will be 'inherited'.
Methods 'area' and 'move' will be not present in myclass at all!
so
$a = new myclass;
$a.area()
will return an error.
At some level of inheritance methods area() and move() may be reimplemented again if required.
I see few benefits
1. Much more flexible to build what programmers need. Becouse we have both 'joining' and 'breaking' around us in real life.
2. Inheritance diagrams may become less in size, showing only what programmer use or need in classes.
3. probably there are some optimization possibilities (especially for properties)
i see some drawbacks
1. kills traditional OO mainstream, theory and books
2. hard to keep track both for 'added' methods and for 'killed' methods in mind.
3. hard to know if 'killed' method called from the other methods in the class. But that may be
not a problem if we just declare forget blah, without affecting run-time.
I am very interested what Perl gurus think about it. Even if you consider this as stupidiest idea ever.
Which is probably true :-)
-Dmitry Dorofeev.
Why do you want to cut off theirs?
> I know it kills inheritance but it is much more to my Perl habit of
> hacking code.
Yes, it quite kills inheritance. Say in your example (whose syntax I
will show in this footnote[1]) that you have:
sub foo(a $x) {
print $x.area;
}
Now if you give it a myclass, it's not really an a anymore, because it
doesn't behave like one. Which leads me to believe that you should be
using something besides inheritance.
So you're saying that if size called area, that area would be called as
though you hadn't forgotten it? Okay, you definitely don't want
inheritance.
It sounds like you're wanting inheritance for code reuse. The Perl 6
way to reuse code is with roles, but assuming that you either don't know
how to use roles, the 3rd party writer didn't use them, or you're in a
language without them (like Java), I would suggest aggregation:
class MyClass {
has A $.a; # turns out that "a" is a keyword in Perl 6
method getX() { $.a.getX }
method getY() { $.a.getY }
method size() { $.a.size }
method put() { ... }
}
The thing is, that when you inherit from a class, you expect the
subclass to behave like the superclass in some extended way (thus the
Java keyword C<extends>). Removing methods makes it so the subclass no
longer behaves like the superclass, because methods you'd expect to call
don't exist anymore.
That is not to say, of course, that Perl won't let you do it. It's
Perl, after all :-) [2]
> I am very interested what Perl gurus think about it. Even if you consider
> this as stupidiest idea ever.
> Which is probably true :-)
>
> -Dmitry Dorofeev.
[1] Your code, Perl6-ized:
> Class a {
> method getX;
> method getY;
> method size;
> method area;
> method move;
> }
class A {
method getX() {...}
method getY() {...}
method size() {...}
method area() {...}
method move() {...}
}
> I'd like to write
>
> Class myclass : a {
> forget method area;
> forget method move;
> method put;
> }
[2] Never, ever do this, but just in case:
class MyClass is A {
method put() {...}
method DISPATCH(*@args) {
die "No such method: $DISPATCH" if $DISPATCH eq 'area'|'move';
.$DISPATCH(*@args);
}
}
Luke
There's little benefit to explicitly stubbing out inherited methods you
don't plan to use, just don't use them. Its not worth screwing up
the language's inheritence model with an explicit way to have a subclass
not implement its parent's interface.
I suspect that if you find yourself only needing a small fraction of your
parent's interface often, inheritence might not be the right thing. Consider
delegation instead.
--
Michael G Schwern sch...@pobox.com http://www.pobox.com/~schwern/
You're more radiant than a memory of breathtaking ecstasy.
> Hi all.
> Sorry if this idea|question has been discussed or has name which i
> don't know about.
<snip>
> I'd like to write
>
> Class myclass : a {
> forget method area;
> forget method move;
> method put;
> }
>
> so methods getX, getY, size will be 'inherited'.
> Methods 'area' and 'move' will be not present in myclass at all!
> so $a = new myclass;
> $a.area()
>
> will return an error. At some level of inheritance methods area() and
> move() may be reimplemented again if required.
At first, I thought "Hmmm, I'm not sure if this will be useful.
Besides, what would happen in the case of multipile inheri..."
Then, it hit me. A "forget" (or "block", or something similar)
keyword would be great in clearing up confusion with multiple
inheritance.
For instance, in an example like:
class A {
method a_method {}
method common_method {}
}
class B {
method b_method {}
method common_method {}
}
class C is A,B { # Is that right, or am I too java-ed out?
method c_method {}
forget A::common_method;
# or maybe something like: "block A::common_method"
}
Class C would now have access to:
A::a_method, B::b_method, C::c_method, and B::common_method
Of course, roles are another great way to prevent confusion with
multiple inheritance. A good question would be whether something
like "forget" is useful in addition, or whether everyone should
just use roles. :)
- Joe
> Of course, roles are another great way to prevent confusion with
> multiple inheritance. A good question would be whether something
> like "forget" is useful in addition, or whether everyone should
> just use roles. :)
For the record, roles are not a form of multiple inheritence. They're
similar in that both are techniques for code re-use; but there are crucial
differences - for instance, classes call methods; roles merely provide
methods for classes to call.
How about this: allow for two approaches for calling a given method:
implicit (state the object and the method, and leave it up to the class
dispatcher to figure out where the method is to be found - in the class,
one of its roles, or one of its parents) or explicit (state the object,
the method, and the class or role where it will be found). Allow
exclusion of inherited and role methods, but define exclusion strictly in
terms of implicit calls: you're telling the class dispatcher to ignore
that role or parent when searching for candidate methods to call.
Explicit calls would suffer from "brittleness" - that is, if you rename a
role or a class, you'd need to hunt down every instance where one of its
methods is explicitly called and rename it there as well. Implicit calls,
OTOH, would risk incompleteness - exclude an inherited or role method from
a class without providing a valid substitute, and other code may end up
assuming that the class has capabilities that it doesn't.
The danger isn't really in the ability to suppress a method from a given
role or parent; the danger comes from the ability to suppress a method
from _every_ role or parent. A safe alternative to this would be to
define a class method which then turns around and explicitly calls the
inherited or role method that you really wanted; the drawback here is the
poor Huffman encoding involved: writing a method is considerably more
bulky than saying "exclude ..." or "rename ...". You can resolve this
dilemma in two ways (not mutually exclusive): forbid the latter options,
or come up with a more succinct way of handling the former option.
OK; add a trait for methods: call it "from", and require it to take one
parameter: the name of a role or parent. What it does is to automatically
redirect any calls to that method, while removing the need for a code
block. So:
class Parent {
method foo () {...}
}
class Role {
method foo () {...}
}
class Bar is Parent does Role {
method foo () is from Parent;
}
C<is from Parent> would be equivelent to C<{return Parent::foo();}>.
=====
Jonathan "Dataweaver" Lang
__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free web site building tool. Try it!
http://webhosting.yahoo.com/ps/sb/
I think that both of these capabilities are already present in P5, and have
been agreed upon for P6:
$obj->foo(); # dispatches, and
Class::Subclass $obj; # explicitly invokes.
> The danger isn't really in the ability to suppress a method from a given
> role or parent; the danger comes from the ability to suppress a method
> from _every_ role or parent. A safe alternative to this would be to
> define a class method which then turns around and explicitly calls the
> inherited or role method that you really wanted; the drawback here is the
> poor Huffman encoding involved: writing a method is considerably more
> bulky than saying "exclude ..." or "rename ...". You can resolve this
> dilemma in two ways (not mutually exclusive): forbid the latter options,
> or come up with a more succinct way of handling the former option.
I don't think this is a disadvantage.
Consider that ROLES already require some similar feature: When two roles
have methods that conflict, there is a requirement to suppress or rename one
or both methods.
Consider also that suppression across the board would be a valid
Aspect-Oriented operation. For example, adding or replacing a C<debug>
method is a fairly common example. But suppressing the same debug method for
use in finished products might be advantageous, especially if it resulted in
a smaller compiled executable.
To me, the "forget" or "discard" or "dispose" or "delete" (gasp) keyword or
operation has a valid place, even if it's not a frequently used place. I
guess the question is: Could we successfully implement this in 6.1 as a
module?
=Austin
Actually, no; roles don't _need_ "suppress" or "rename" options to
disambiguate a conflict: the priority chain of "class methods, then role
methods, then inherited methods" provides all the tools that are
_required_ to remove ambiguities: you merely override the conflicting role
methods with a class method - which may explicitly call the preferred
inherited or role method, do its own thing, or both. This technique
covers every benefit that exclusions and aliases provide with the sole
exception of the ability to make a given method name unavailable. Its
only other potential fault vs. suppress and rename is poor Huffman
encoding.
> Consider also that suppression across the board would be a valid
> Aspect-Oriented operation. For example, adding or replacing a C<debug>
> method. But suppressing the same debug method for use in finished
> products might be advantageous, especially if it resulted in a smaller
> compiled executable.
>
> To me, the "forget" or "discard" or "dispose" or "delete" (gasp) keyword
> or operation has a valid place, even if it's not a frequently used
> place. I guess the question is: Could we successfully implement this in
> 6.1 as a module?
It's been suggested that something like this could be handled by hacking
the DISPATCH method of a class so that it throws an exception whenever
that method gets called. This doesn't really _remove_ the method in
question, but it does render it unavailable (implicitly, at least).
> -----Original Message-----
> From: Jonathan Lang [mailto:datawe...@yahoo.com]
This is not my understanding. If I say
role tree {
method bark {...}
}
role dog {
method bark {...}
}
class Trog
does tree
does dog
{
...
}
then there is a conflict unless an alias is declared, or unless the class
explicitly specified which method to call, or provides a combining method.
But saying
class Trog
does tree { forget bark() }
does dog
{
...
}
makes it pretty clear what's happening.
Going further, this makes for interesting namespace manipulations:
class Canis {
method bark {
print STDERR, "Error: Can't bark!";
}
}
class Canis::Familiaris {
method bark { $System::Audio->Play $.bark_noise; }
}
# small smooth-haired breed of African origin
# having a tightly curled tail and the inability to bark
class Basenji {
forget &Canis::Familiaris.bark;
}
my $dog = new Basenji;
$dog->bark; # Error, can't bark!
>
> > Consider also that suppression across the board would be a valid
> > Aspect-Oriented operation. For example, adding or replacing a C<debug>
> > method. But suppressing the same debug method for use in finished
> > products might be advantageous, especially if it resulted in a smaller
> > compiled executable.
> >
> > To me, the "forget" or "discard" or "dispose" or "delete" (gasp) keyword
> > or operation has a valid place, even if it's not a frequently used
> > place. I guess the question is: Could we successfully implement this in
> > 6.1 as a module?
>
> It's been suggested that something like this could be handled by hacking
> the DISPATCH method of a class so that it throws an exception whenever
> that method gets called. This doesn't really _remove_ the method in
> question, but it does render it unavailable (implicitly, at least).
Yes, but I don't want an exception. I want an "ignoration" -- possibly
causing the dispatcher to locate some other, less proximate, candidate
method.
=Austin
Doesn't
class Trog
does tree
does dog
{
method bark { ... }
}
Also make clear what's happening? Especially when the ... isn't
literal, but really a call to tree.bark or dog.bark.
> > It's been suggested that something like this could be handled by hacking
> > the DISPATCH method of a class so that it throws an exception whenever
> > that method gets called. This doesn't really _remove_ the method in
> > question, but it does render it unavailable (implicitly, at least).
>
> Yes, but I don't want an exception. I want an "ignoration" -- possibly
> causing the dispatcher to locate some other, less proximate, candidate
> method.
Hmm. The text and examples so far have been about methods and this
seems to be about multi-methods. Correct me if I'm wrong ...
That's not how I interpretted "forget" It looked more like "this method
doesn't exist, please error now". Which you can achieve by providing a
an ordinary method that just errors. However, if you wanted to control
how the method is dispatched, that's exactly what .DISPATCH() is for.
(assuming .DISPATCH is writ in something resembling stone as I only
recall seeing it mentioned once or twice) Just write it so that it
doesn't consider the multi-method you want to forget.
You can also control how closely a multi-method matches by choosing an
appropriate method signature. For instance, an unprototyped
multi-method would sit at the bottom of the list with prototyped
multi-methods before it.
-Scott
--
Jonathan Scott Duff
du...@lighthouse.tamucc.edu
Not as I recall from the paper. Especially not if the methods have different
signatures. The point here being that either tree or dog may have other
methods that call C<bark> internally, so the defined interface is a required
list -- the only thing you can do is explicitly provide some sort of
behavior modification.
> > > It's been suggested that something like this could be handled
> by hacking
> > > the DISPATCH method of a class so that it throws an exception whenever
> > > that method gets called. This doesn't really _remove_ the method in
> > > question, but it does render it unavailable (implicitly, at least).
> >
> > Yes, but I don't want an exception. I want an "ignoration" -- possibly
> > causing the dispatcher to locate some other, less proximate, candidate
> > method.
>
> Hmm. The text and examples so far have been about methods and this
> seems to be about multi-methods. Correct me if I'm wrong ...
You're wrong. Consider my example, where via single inheritance we reach a
"layered" list of methods, each of which replaces the previous one in the
namespace (parent.method superseded by child.method). This is not
multi-dispatch -- the class of the object being dispatched determines the
method -- but I want to modify the dispatch chain so that some upstream
class' method is "ignored".
> That's not how I interpretted "forget" It looked more like "this method
> doesn't exist, please error now". Which you can achieve by providing a
> an ordinary method that just errors. However, if you wanted to control
> how the method is dispatched, that's exactly what .DISPATCH() is for.
> (assuming .DISPATCH is writ in something resembling stone as I only
> recall seeing it mentioned once or twice) Just write it so that it
> doesn't consider the multi-method you want to forget.
See above. I'm willing to believe that a module could be done that provides
this service in the way you describe, if it can be temporized.
=Austin
It's surely possible by modifying that class's DISPATCH.
Whether it should actually be in the language is up for debate. I'd say
that if you need to do this with any frequency whatsoever, you're not
thinking about roles right. A good example might be in order... :-)
And by "good", I mean that the following pattern should not match
against it:
/:i foo | bar | baz | quux | animal | mammal | vehicle | car | yacht /
> > That's not how I interpretted "forget" It looked more like "this method
> > doesn't exist, please error now". Which you can achieve by providing a
> > an ordinary method that just errors. However, if you wanted to control
> > how the method is dispatched, that's exactly what .DISPATCH() is for.
> > (assuming .DISPATCH is writ in something resembling stone as I only
> > recall seeing it mentioned once or twice) Just write it so that it
> > doesn't consider the multi-method you want to forget.
>
> See above. I'm willing to believe that a module could be done that provides
> this service in the way you describe, if it can be temporized.
Yep. For a weekend or a week, there's nothing like DISPATCH. Food, fun
and fashion, DISPATCH is your match. :-p
Luke
> =Austin
>
Which doesn't contradict what I said in the slightest. We agree that the
class needs to include _something_ to disambiguate the two versions of
"bark"; we're only differing in terms of what it is that needs to be
included. What I'm saying is that
class Trog
does tree
does dog
{
method bark {tree.bark;}
}
would suffice, due to the fact that class methods take precedence over
role methods. It's a bit wordy (and gets moreso as you add a signature
and use longer method names), but it does the trick. Give this technique
an abbreviated form that removes as much of the redundancy as possible,
and you've got something that rivals the "exclusion" and "alias"
alternatives in brevity:
class Trog
does tree
does dog
{
method bark is from tree;
}
> But saying
>
> class Trog
> does tree { forget bark() }
> does dog
> {
> ...
> }
>
> makes it pretty clear what's happening.
True. It just isn't _needed_.
Don't get me wrong: I don't neccessarily have anything against the
inclusion of a "forget"/"exclude"/whatever technique; I'm merely arguing
that such a technique isn't something that we can as yet assume that perl
6 will have - and the only functionality that we lose by not having it is
the ability to render a method completely inaccessible via implicit calls.
Is this functionality _really_ that important to have?
- Joe
Joseph Ryan wrote:
> Luke Palmer wrote:
>
>> Austin Hastings writes:
>>
>>
>>>> Hmm. The text and examples so far have been about methods and this
>>>> seems to be about multi-methods. Correct me if I'm wrong ...
>>>>
>>>
>>> You're wrong. Consider my example, where via single inheritance we
>>> reach a
>>> "layered" list of methods, each of which replaces the previous one
>>> in the
>>> namespace (parent.method superseded by child.method). This is not
>>> multi-dispatch -- the class of the object being dispatched
>>> determines the
>>> method -- but I want to modify the dispatch chain so that some upstream
>>> class' method is "ignored".
>>>
>>
>>
>> It's surely possible by modifying that class's DISPATCH.
>> Whether it should actually be in the language is up for debate. I'd say
>> that if you need to do this with any frequency whatsoever, you're not
>> thinking about roles right. A good example might be in order... :-)
>>
>>
>
> Well, what if the two classes you want to inherit from weren't
> designed with roles in mind? For instance, there might be two
> CPAN modules that each have a dozen methods that you want to
> inherit, but they each have 1 that overlap whose conflict you
> want to easily resolve.
>
> Besides, "the user is not thinking about XXX right" sounds like we
> need to give a ++ to the pythonometer ;)
>
> - Joe
>
The conflict can still be resolved via a class method that routes to the
appropriate inherited method.
That said, if some sort of "exclusion" technique gets implemented for
roles, I don't see why it shouldn't also be implemented for classes - with
the caveat that actually removing a method (as opposed to merely
suppressing a conflict) would generally be considered bad OO practice.
=====
Jonathan "Dataweaver" Lang
__________________________________
Do you Yahoo!?
Yahoo! Finance: Get your refund fast by filing online.
http://taxes.yahoo.com/filing.html