The problem with that is it's not giving an explicit return type,
therefore forcing runtime typechecking when you use that returned
value. I'd like an approach that correctly asserted the value of the
return type, such that our signature there doesn't short-circuit
any/all surrounding compile-time typechecking, forcing us to runtime
checks.
So if the above is how you'd do it, wouldn't you always be better off
(for both compile-time typechecking and runtime speed) copying and
pasting your CLONE method into every subclass you create, simply
changing the return type to match the subclass? That seems like a bit
of a let-down, considering that something like CLONE is both very
primitive and very speed-critical.
(This relates back to our mention of C++ templates, which allow you to
do things like that, but essentially through dorky glorified macro
substitutions.)
However...
Note that in practice, 90% of the time you really only are dealing with
the same type as the invocant is. For example:
class Foo { method CLONE(Foo $self) returns Foo {...} }
class Bar is Foo { method CLONE(Bar $self) returns Bar {...} }
class Baz is Bar { method CLONE(Baz $self) returns Baz {...} }
So all you really need, in order to have "generic" or "template-like"
functionality, is to be able to say something like:
class Foo { method CLONE returns __INVOCANT_TYPE__ {...} }
class Bar is Foo {...};
class Baz is Bar {...};
where you have a thing, __INVOCANT_TYPE__, that resolves to whatever
the current class(?) or invocant(?) is. So it's not quite as horrible
as having to allow completely indirect types:
my $type $foo; # Bzzt! Can't do that!
but it gets -- I think -- all of the common cases.
MikeL
>> [1] I am quite fed up with having to code Badly in order to get
>> Speed. Perl5 OO suffers rather significantly from this
>> flummoxacrapicity, as do plenty of other languages.
It also stinks.
Assuming all the parameters are bound (at least statically) before the
return type is checked, this could be done:
class Foo {
method CLONE($self:) returns $self.type {...}
}
Then we could do really neato multimethod stuff:
multi foo ($a, $b) {...} # Generic routine
multi foo ($a, $b of $a.type) {...} # Specialized routine
It doesn't seem to have I<enough> power though (actually it does, I'm
just transitioning into the next section :). For instance, how do you
specify a multimethod that gets called if the two types are unrelated
in the heirarchy? (And why would you want to?)
How about:
multi foo is match( / $a:=(.) $b:=(.)
<( none($a,$b).isa(all($a,$b)) )> / )
{...}
Where the atoms of that regex are Objects. My question is, then, how
do named parameters work with this? Maybe if you're going to use a
regex signature, you don't get automatic named parameters and you have
to process them yourself.
This kind of thing would be really neat, but I imagine it would cause
hell for the parser... maybe. The parser could just gobble up
everything, and then match what it gobbled against the match regexen.
This feature is probably more suited to the Method::PatternSig module.
Luke
P.S. Wheeeeeeeeee!
Is that even true? Or will the compiler assume (by fiat) that the
result of $object.CLONE has identical type with $object?
To me, that's a reasonable constraint on the definition of the CLONE
method. (This is also an argument for interface subclassing, since you
could want to return a lightweight proxy instead of the full object,
but it if looks like a Duck...)
> So if the above is how you'd do it, wouldn't you always be better off
> (for both compile-time typechecking and runtime speed) copying and
> pasting your CLONE method into every subclass you create, simply
> changing the return type to match the subclass? That seems like a
> bit
> of a let-down, considering that something like CLONE is both very
> primitive and very speed-critical.
Problematically, you don't actually KNOW that your subclasses won't
inherit your CLONE. If you want to write a class that CAN have children
that don't override CLONE, you can't specify the return type.
class Pop {
method CLONE returns Pop {...};
}
class Kid is Pop;
my Pop $p = new Pop;
my Kid $k;
$k = $p; # Should invoke Kid::CLONE, which would inherit Pop::CLONE.
In order to use strongly typed cloning, you'd have to make it a
submethod, I guess.
>
> (This relates back to our mention of C++ templates, which allow you
> to do things like that, but essentially through dorky glorified macro
> substitutions.)
>
I think the C++ feature in question here is automatically generated
copy constructors.
For the above example, C++ would generate Kid& Kid(Pop&) {} to do
nothing except automatically invoke the parent ctor in the right
context.
> However...
>
> Note that in practice, 90% of the time you really only are dealing
> with the same type as the invocant is. For example:
>
> class Foo { method CLONE(Foo $self) returns Foo {...} }
> class Bar is Foo { method CLONE(Bar $self) returns Bar {...} }
> class Baz is Bar { method CLONE(Baz $self) returns Baz {...} }
>
> So all you really need, in order to have "generic" or "template-like"
> functionality, is to be able to say something like:
>
> class Foo { method CLONE returns __INVOCANT_TYPE__ {...}
> }
> class Bar is Foo {...};
> class Baz is Bar {...};
>
> where you have a thing, __INVOCANT_TYPE__, that resolves to whatever
> the current class(?) or invocant(?) is. So it's not quite as
> horrible as having to allow completely indirect types:
>
> my $type $foo; # Bzzt! Can't do that!
>
> but it gets -- I think -- all of the common cases.
In this dimension, I'd much rather see full support for generic
programming. I really don't like the idea of having to listen to C++
coders describe how it *should* have been done. :-(
>
> MikeL
>
> >> [1] I am quite fed up with having to code Badly in order to get
> >> Speed. Perl5 OO suffers rather significantly from this
> >> flummoxacrapicity, as do plenty of other languages.
In response to this point, which should be another of the basic user
requirements IMO (Perl6 Objects shall not require writing bad code) I
point out that I'm not personally aware of ANY language which doesn't
require bad code in order to get certain (common) desired results.
=Austin
Yeah, I don't think it can assume that, unless it's special to CLONE.
That's the intriguing part I was musing over... can we have a trait or
something that says 'returns the same type as the actual invocant was',
such that the compiler can retain the appropriate typechecks... and
would that be adequate for most "generic programming" tasks?
>>>> [1] I am quite fed up with having to code Badly in order to get
>>>> Speed. Perl5 OO suffers rather significantly from this
>>>> flummoxacrapicity, as do plenty of other languages.
>
> In response to this point, which should be another of the basic user
> requirements IMO (Perl6 Objects shall not require writing bad code) I
> point out that I'm not personally aware of ANY language which doesn't
> require bad code in order to get certain (common) desired results.
Indeed. Words cannot describe how jaded a programmer I've become over
the last... well, five years, really, since the 'Java is great' spasm
hit IT departments like a bad Outlook virus. At this point in my life,
I have learned -- repeatedly -- that all languages suck.
I maintain it as Fact that if you believe a particular computer
language doesn't suck, it is only because you haven't learned it well
enough.
MikeL
Well, yes. :-) Absolutely, it does!
> Assuming all the parameters are bound (at least statically) before the
> return type is checked, this could be done:
>
> class Foo {
> method CLONE($self:) returns $self.type {...}
> }
That's an interesting idea... but it's basically the exact same thing
as saying:
my $foo returns $type;
in that if we allow one, we should allow the other, and I wonder how
well that really works. I mean, I wonder what kind of overhead that
entails, and if there would be any *prayer* of optimization.
> How about:
>
> multi foo is match( / $a:=(.) $b:=(.)
> <( none($a,$b).isa(all($a,$b)) )> / )
> {...}
Ow. Now my head hurts, like I just banged it on an angle bracket or
something.
Damn circular threads...
MikeL
Now that we have sub signatures and parameter typing is seems to
me that method inheritence has to work differently them in P5.
(note we are getting way ahead of A12 here). If we have
class Foo { method CLONE returns Foo {...} }
# signature actually is
# method CLONE (Foo $_:) returns Foo
class Bar is Foo {...};
It seems that the inherited CLONE method for Bar should have a
virtual signature with the types properly replaced. The compiler
should pretend that Bar::CLONE has the signature:
method CLONE (Bar $self:) returns Bar
--
Mark Biggar
ma...@biggar.org
mark.a...@attbi.com
I'm sorry, why does it stink?
> It seems that the inherited CLONE method for Bar should have a
> virtual signature with the types properly replaced. The compiler
> should pretend that Bar::CLONE has the signature:
>
> method CLONE (Bar $self:) returns Bar
And instead of a "virtual signature" that differs from what the
programmer actually wrote, why not let the programmer write what they
mean?
method CLONE (__CLASS__ $self:) returns __CLASS__
-Scott
--
Jonathan Scott Duff
du...@cbi.tamucc.edu
If you're going to do that, make sure it's __INVOKING_CLASS__ and not
just a tweaked synonym for __PACKAGE__, which would be the wrong value.
Aren't the __WHATEVER__ values zotted in at compile time?
How would the compiler know what class was invoking an inherited
constructor in runtime?
I really have no problem with using a __THING__, but my brain kind of
revolts over that being what we want. Cool idea, wrong phase. Maybe
that's wrong-thinking, but there it is.
$self.class, on the other hand, is obviously a runtime evaluation on
the invocant. I *have* to assume that would be more complex and less
efficient, but at least it's an explicitly inheritable frame....
__________________________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo
http://search.yahoo.com
It is terribly inflexible. When you're talking about generic
programming, parameterized classes, matching types, etc., it just
doesn't do the trick. This is a solution to a very specific problem,
and we want something more general than that.
I think being able to use variables bound earlier in the signature
later in the signature is sufficiently flexible. Since Perl can run
Perl at compile time, it can evaluate any static type checking it
needs to, regardless of how complex the code (but the more code you
write, the more likely you are to write something it doesn't know how
to analyze). It also has the advantage of not adding any special
syntax.
That or allowing regexen to do signatures >:-).
> > It seems that the inherited CLONE method for Bar should have a
> > virtual signature with the types properly replaced. The compiler
> > should pretend that Bar::CLONE has the signature:
> >
> > method CLONE (Bar $self:) returns Bar
>
> And instead of a "virtual signature" that differs from what the
> programmer actually wrote, why not let the programmer write what they
> mean?
>
> method CLONE (__CLASS__ $self:) returns __CLASS__
Yep, I'd call that better than the virtual signature. But it's in the
same class of narrow-minded solutions.
Let's see if I can demonstrate what I mean. First, a type checked
C<max> function:
sub max($a, $b of $a.type) {
$a < $b ?? $b :: $a
}
But that's unsatisfactory, because we really just need two types that
have a < operator defined between them.
sub max($a, $b) will enforce { can($a < $b) }
{
$a < $b ?? $b :: $a
}
I think C<can> should do that. It would make compile time guarantees
a lot easier to enforce. In that, it takes an expression and doesn't
evaluate it, it just makes sure that if it did evaluate it, it
wouldn't throw a "method not found" exception.
So type checking a function might be a lot like matching a regex, on
the implementation side. It would definitely be like matching a regex
with multiple alternatives in multimethods. (Don't worry, I I<do>
think that using the regex syntax is overdoing it in this case)
multi foo($a, $b of $a.type.super) {...}
multi foo($a, $b) will enforce { can(bazbar($b)) } {...}
multi foo(Bar $a, $b) {...}
sub bazbar(Bar $x) {...}
Would be like matching this [object] pattern:
/ $a:=(.) $b:=(<typed $a.type.super>)
| $a:=(.) $b:=(.) <( can(bazbar($b)) )>
| $a:=(<typed Bar>) $b:=(.)
/
Luke
class constrained is Sub {
method postfix:() { die "Constraint failed in call to $.name"
unless !.CONSTRAIN or .CONSTRAIN(); }
}
constrained max($a, $b) will CONSTRAINT { can($a < $b) }
{
$a < $b ?? $b :: $a;
}
==============
# But the more generic one (1) needs to be done at run-time; and
# (2) only has to have an (ill-defined) subset of arguments comparable.
# (E.g., all the interim $max values with all the lesser values after
# each of them.)
sub max($a, $b, *@rest is rw) {
my $max = $a;
@rest.unshift $b;
for (my $next = $b; +@rest; $next = @rest.shift)
{
# Frankly, I expect Perl will do this next bit for me.
die "Cannot compare $max with $next" unless { can ($max < $next) };
$max = $next if $max < $next;
}
$max;
}
> I think C<can> should do that. It would make compile time guarantees
> a lot easier to enforce. In that, it takes an expression and doesn't
> evaluate it, it just makes sure that if it did evaluate it, it
> wouldn't throw a "method not found" exception.
On the one hand, this is a perfect example of the "subtype" philosophy
that I think Larry has been considering. There's no reason not to
extend it to the Code family, too.
On the other hand, how much value is static checking going to really
add?- there's going to wind up being dynamic checking, too, for a huge
collection of things.
>
> So type checking a function might be a lot like matching a regex, on
> the implementation side. It would definitely be like matching a
> regex with multiple alternatives in multimethods. (Don't worry, I
> I<do> think that using the regex syntax is overdoing it in this case)
>
> multi foo($a, $b of $a.type.super) {...}
> multi foo($a, $b) will enforce { can(bazbar($b)) } {...}
> multi foo(Bar $a, $b) {...}
> sub bazbar(Bar $x) {...}
>
> Would be like matching this [object] pattern:
>
> / $a:=(.) $b:=(<typed $a.type.super>)
> | $a:=(.) $b:=(.) <( can(bazbar($b)) )>
> | $a:=(<typed Bar>) $b:=(.)
> /
Perhaps we could get Larry to agree that all perl code with the high
bit set on all characters will be executed immediately in the
compiler...
Yarf.
=Austin
What the heck are you talking about?
> sub max($a, $b, *@rest is rw) {
> my $max = $a;
> @rest.unshift $b;
>
> for (my $next = $b; +@rest; $next = @rest.shift)
> {
> # Frankly, I expect Perl will do this next bit for me.
> die "Cannot compare $max with $next" unless { can ($max < $next) };
> $max = $next if $max < $next;
> }
>
> $max;
> }
>
> > I think C<can> should do that. It would make compile time guarantees
> > a lot easier to enforce. In that, it takes an expression and doesn't
> > evaluate it, it just makes sure that if it did evaluate it, it
> > wouldn't throw a "method not found" exception.
>
> On the one hand, this is a perfect example of the "subtype" philosophy
> that I think Larry has been considering. There's no reason not to
> extend it to the Code family, too.
I really do have to read about how Ada does those.
> On the other hand, how much value is static checking going to really
> add?- there's going to wind up being dynamic checking, too, for a huge
> collection of things.
It adds the fact that we can do it. Perl should support static
checking regardless of whether there's dynamic checking. Getting
complained to about errors at compile time is much nicer than being
perplexed at run time.
And Perl, being the multiparadigm language it is, should support this.
Some paradigms rely on static checking. Some of them rely on methods
of static checking which we'll never think of. So, give people all
the information we have at compile time and let them do what they want
with it.
(And, of course, build in tools to make the common cases easy)
> >
> > So type checking a function might be a lot like matching a regex, on
> > the implementation side. It would definitely be like matching a
> > regex with multiple alternatives in multimethods. (Don't worry, I
> > I<do> think that using the regex syntax is overdoing it in this case)
> >
> > multi foo($a, $b of $a.type.super) {...}
> > multi foo($a, $b) will enforce { can(bazbar($b)) } {...}
> > multi foo(Bar $a, $b) {...}
> > sub bazbar(Bar $x) {...}
> >
> > Would be like matching this [object] pattern:
> >
> > / $a:=(.) $b:=(<typed $a.type.super>)
> > | $a:=(.) $b:=(.) <( can(bazbar($b)) )>
> > | $a:=(<typed Bar>) $b:=(.)
> > /
>
> Perhaps we could get Larry to agree that all perl code with the high
> bit set on all characters will be executed immediately in the
> compiler...
I know this is a joke... but... I don't get it. :-/
Luke
This started me thinking....
You could always do it in an eval(), I suppose, but ewww....
But then, how about C<toType($name)> or some such, which dynamically
converts the *content* of a variable to a type it represents?
my $class = someCode(); # let's say it returns "Foo"
my toType($class) $x; # $n now a Foo
That would definitely be a runtime thing, though, unless you said
my toType("Foo") $x;
which would seem pretty stupid. Still, I wouldn't really expect be able
to do that at compile time either.
===
Maybe $x.isNow(Foo) to dynamically type an existing variable after the
fact? Can of worms, I know....but might it be useful?
Hmm...probably less offensive as a Junction?
sub makemea ($var,$name) { $var.isNow($var.type|$name.toType) }
sub makemelike ($var,$other) { $var.isNow($var.type|$class.type) }
$x.makemea("Foo"); # btw....dot syntax on sub() ok?
$x.makemelike(Bar.new);
Looks horrible, but we've all seen CPAN modules that take an object and
rebless it into a new package.... Not something I'd recommend, but hey,
it made it to CPAN (or am I hallucifying again?). Is there already a
way to do that in P6?
LOL!!! Hell, man, I only *think* I get it, but THAT was funny. :)
Personally, I assumed it's an oblique shot at the high density of
non-alpha particles in that dustcloud. :)
But then, I'm just an ol'e country boy....
So C<enforce> is a precondition on compiling the associated
Routine object? Sounds like a BEGIN or CHECK block that can
abort compilation. So maybe C<will check>? Otoh, you have
previously noted that for dynamic variables the checks have
to be run-time, so presumably not. Otgh, in the post to which
this is a reply, you talk exclusively about compile-time
guarantees...
The above C<can> syntax means copy/paste of fragments of code.
That's likely to get verbose and awkard to maintain real fast.
Alternatives are presumably to use a pragma or property that
adds a lexically scoped limit on either code, one or more
variables, or one or more operators/functions.
The first suggests something like:
use can <<Code>>; # please try to ensure that the code
# will not run afoul of type mismatches,
# and at the very least, generate a
# run-time error if there's a mis-match.
sub max($a, $b)
{
$a < $b ?? $b :: $a
}
or:
sub max($a, $b) will enforce { can &_; }
{
$a < $b ?? $b :: $a
}
Tagging variables indicates something like:
use can <<$a, $b>>;
sub max($a, $b)
{
$a < $b ?? $b :: $a
}
or:
sub max($a, $b) will enforce { can $a, $b; }
{
$a < $b ?? $b :: $a
}
or a pseudo-type:
sub max(Can $a, Can $b)
{
$a < $b ?? $b :: $a
}
Am I making sense?
--
ralph
Here I was talking about static guarantees, sorry If I wasn't clear.
Basically, can would try to resolve the routines called in itself at
compile time (much the way an optimizer would), and throw if it
couldn't. The reason I named it C<enforce> as opposed to C<check> is
that it happens more than once. It happens at each call resolution to
the function (a call appears 4 times in your program, C<enforce> would
be called 4 times).
I may be missing some obvious impossibilities.
You most certainly are. I was wondering about this: that it would
check all the code in a function to make sure it was sound. But
because Perl is so dynamic, there will be things that you won't want
it to check, that you just want to say "trust me on this one." Rather
than do that, I was creating a "don't trust me on this one"
declarator.
You've convinced me to think that was a bad idea. After all, if I'm
aware of it, why would it be a problem (other than the tpyo argument).
It'd be really nice to be able to generic program in the fashion of
"if they're the same type, call this one, otherwise call this other
one" without specifying which types those are. Only more powerful
than mere type equality.
Hmmm...
Luke
Perhaps C<can> should compute one of three possibilities,
definitely fails / definitely ok / needs a run-time check,
but C<enforce> views the latter possibility as a fail so
it's C<enforce> that throws. Or perhaps C<enforce> should
have options that enable both types of check stringency
(definitely ok or needs run-time check).
> The reason I named it C<enforce> as opposed to C<check> is
> that it happens more than once. It happens at each call
> resolution to the function (a call appears 4 times in your
> program, C<enforce> would be called 4 times).
Gotcha. 'Enforce' reads well, but isn't as obvious as it
could be, imo. Perhaps C<checkcalls> or C<checkuses>? The
latter could then be attached to either whole routines or
an individual variable?
> You've convinced me to think that ["don't trust me on this one"]
> was a bad idea.
Oh. And it sounds like you think "check the whole routine"
is also a less than stellar idea.
Did you think the notion of asking the compiler to check
uses of a particular variables was dumb? It has a good
analogy with explicit types, even if it is a very different
underlying mechanism.
> It'd be really nice to be able to generic program in the fashion of
> "if they're the same type, call this one, otherwise call this other
> one" without specifying which types those are. Only more powerful
> than mere type equality.
"They" being a couple or more parameters? Are you saying
this because many operators are binary, and many of those
are defined/optimized for particular related operand types,
and not when they are not? (Hope that made sense!)
--
ralph
> At this point in my life,
> I have learned -- repeatedly -- that all languages suck.
> [...]
> MikeL
Out of curiousity (and a desire to improve the "sux" parts), what
sucks about Perl 5? And what sucks about Perl 6?
--Dks
You know, that's an astute and intelligent question.
Lemme see.... This is a hard one for me, because I *LOVE* Perl.
Still, I have to admit that there have been times that I've had to
indulge in deep sighs....
One thing that comes to mind with no particular force is the junction
of the facts that Perl almost *never* lets go of memory once allocated
(even if it isn't using it) and that the C<less> pragma does
practically nil. I'd love to see C<use less -memory;> make Perl free up
space a little more agressively, though I'd still prefer the current
optimization as the default.
For all it's wondrosity, Perl *IS* very line-noisy. Part of that is
just my coding style, and I have little idea of how to make it better
(though Lingua::Romana::Perligata does a pretty good job of it. :)
I have on rare occasion lamented the lack of types, which is currently
under treatment in P6.
I have most certainly bemoaned the slowness of some of my object
classes, but between learning to write better code, converting some to
inline C (thanks again, Ingy!), and getting P6's types to zoom through
the parrot engine, I'm expecting a quantum leap improvement....
umm....sux, huh? Hmm...
The -w flag isn't mandatory? :)
A caveat: Perl5 sucks less than any other lang I've worked in, or I
wouldn't be working in it and recommending to companies that they use
it. :-)
I think Larry and others have stated very well what their issues with
Perl5 are -- and I agree wholeheartedly with those reasonings. My own
opines are in the POOC preface, at
http://cog/cognitivity.com/perl6/me.html
I think a language "sucks" solely in comparison to the mythical
"perfect" programming language -- a language with no flaws whatsoever.
A language's "suckiness" is measured by the distance between it and
that mythical language.
So far, in running down my own personal checklist of what the perfect
language would have, the Perl6 goals are very, very close to my own. I
still have speed worries, and I still worry about how to make things
like continuations, hypotheticals, etc., even _remotely_ understandable
to the average people who will determine the overall adoption of the
language, so those are the things I tend to focus on.
(Oddly enough, I think a very productive language to analyze is Java.
Java was touted as a be-all-end-all language, with an impressive
feature set and an astronomical adoption rate. I would argue, however,
that it very quickly showed limitations.)
More later, if I get re-inspired, but right now my two-year-old
daughter is demanding -- rather vocally -- that I re-prioritize my
attentions.
MikeL
So, RFC#231 -- Add babysitter to P6...
=Austin
> And what sucks about Perl 6?
That I can't replace all my production Perl 5 code with it yet.
David
--
David Wheeler AIM: dwTheory
da...@kineticode.com ICQ: 15726394
Yahoo!: dew7e
Jabber: The...@jabber.org
Kineticode. Setting knowledge in motion.[sm]
> On Tuesday, April 22, 2003, at 01:42 PM, Austin Hastings wrote:
>> --- Michael Lazzaro <mlaz...@cognitivity.com> wrote:
>>> Or, for the simplest possible demonstration of the issue:
>>>
>>> class Foo {
>>> method CLONE returns Foo {...}
>>> }
>>>
>>> How do you declare CLONE such that it works for all eventual
>>> subclasses of Foo -- returning the correct subclass -- while
>>> still retaining the strict compile-time typing? Such that it
>>> wouldn't turn out to be _more runtime efficient_ to define a
>>> CLONE for every class separately, even if their implementations
>>> were identical? [1]
>>
>> class Foo {
>> method CLONE {
>> my $dolly = new typeof($_);
>> $dolly.%attributes = %.attributes; # Syntax on .%attr?
>> return $dolly;
>> }
>> }
>
> The problem with that is it's not giving an explicit return type,
> therefore forcing runtime typechecking when you use that returned
> value. I'd like an approach that correctly asserted the value of the
> return type, such that our signature there doesn't short-circuit
> any/all surrounding compile-time typechecking, forcing us to runtime
> checks.
[ #include various other suggestions that seem to agree that something
like this is a good idea ]
Have you all gone completely and utterly mad? If you want this kind of
anal compile time checking then you should damn well have to jump
through hoops. Why in ghod's name do you want to nail down generic
interfaces like this? So what if you have the occasional requirement
to do a runtime check of an object type? It's not the end of the
world. The suggestion later in the thread that we treat
method Widget::factory_widget returns Widget {...}
as an assumption that all subclass 'factory_method' definitions return
an object of the invocant's class is not what I would call a sound
one. Factory methods are defined in this fashion precisely because the
return type is unknowable at compile time, and specifying any more
tightly than at superclass level can be a recipe for programmer pain
when he needs to come up with a more flexible factory method for some
class or another, or when he wants to quickly throw together a mock
object.
And it's not as if you're going to take a massive performance hit if
you just have 'returns Object' for all your methods. Consider:
method Object::CLONE returns Object {...}
...
my SpecializedWidget $widget = $specialized_widget.CLONE # Runtime
given $widget {
.do_this; # Compile time
.do_that; # Compile time
.do_the_other; # Compile time
}
So what if you have to pay a runtime cost when you do the initial
assignment, you still get those shiny compile time benefits when you
come to use that new variable. Actually, that snippet seems to imply
type inference, at least as far as $_ is concerned. (I for one will be
even less inclined to use typed variables if we don't support at least
this level of type inference. Then again, I can't see me using type
declarations for much beyond (multi)method declarations anyway and
occasionally in places where profiling shows I can make substantial
performance gains by doing so)
--
Piers
Sure. :)
> If you want this kind of anal compile time checking then you should
> damn well have to jump through hoops. Why in ghod's name do you want
> to nail down generic interfaces like this? So what if you have the
> occasional requirement to do a runtime check of an object type? It's
> not the end of the world. The suggestion later in the thread that we
> treat
>
> method Widget::factory_widget returns Widget {...}
>
> as an assumption that all subclass 'factory_method' definitions return
> an object of the invocant's class is not what I would call a sound
> one. Factory methods are defined in this fashion precisely because the
> return type is unknowable at compile time, and specifying any more
> tightly than at superclass level can be a recipe for programmer pain
> when he needs to come up with a more flexible factory method for some
> class or another, or when he wants to quickly throw together a mock
> object.
Perhaps you're missing something about our, or at least my, posting
style. I come up with something I want to do, or something I feel is
missing, and post it. Then I advocate it until either something
better comes out of it (quite often), or until it just, sortof, dies.
And I know most of it is not going to make it into the core, and I
probably wouldn't want it to. It's just about ideas. The more
controversy kicked up, the more chance something really cool will
emerge.
And about factories, I agree with you. Returning the base type, IMO,
is not only an acceptable way to do it, but a preferable way. I'm
defending this feature in the name of generic programming, which
usually has little to do with inheritance.
> And it's not as if you're going to take a massive performance hit if
> you just have 'returns Object' for all your methods. Consider:
>
> method Object::CLONE returns Object {...}
> ...
> my SpecializedWidget $widget = $specialized_widget.CLONE # Runtime
> given $widget {
> .do_this; # Compile time
> .do_that; # Compile time
> .do_the_other; # Compile time
> }
>
> So what if you have to pay a runtime cost when you do the initial
> assignment, you still get those shiny compile time benefits when you
> come to use that new variable. Actually, that snippet seems to imply
> type inference, at least as far as $_ is concerned. (I for one will
> be even less inclined to use typed variables if we don't support at
> least this level of type inference. Then again, I can't see me using
> type declarations for much beyond (multi)method declarations anyway
> and occasionally in places where profiling shows I can make
> substantial performance gains by doing so)
We'll see how much typing is going to be used in Perl 6 when people
start writing real programs in it. :)
Luke
Chaos is the engine of evolution. Hail Eris! :)
I like to throw out ideas, and usually expect them to be bashed....but
hopefully with a mallet and chisel and not a sledge. Even so, the
sledge is welcome if the scattered bits can at least be cannibalized
for spare parts.
In a separate thread I suggested something like
use strict types => { Int => Str };
That's a really horrible syntax, and gets worse the more I look at it.
I assumed someone would suggest a better way, and Piers did, and with
more thought I did, too.
So please, for the Peanut Gallery, don't be shy -- tell me when I do
something stupid, but offer a better suggestion in the process! :)
__________________________________
Do you Yahoo!?
The New Yahoo! Search - Faster. Easier. Bingo.
http://search.yahoo.com