On Wed, 16 Apr 2003, Austin Hastings wrote:
> > We need to distinguish between "conversion" and "typecasting". Often we
> > are not converting anything, but merely remembering what the type
> > originally was.
>
> So perhaps we shouldn't worry about that case directly, and instead just
> require some DWIMery: narrowing conversions are not compile errors, but will
> have to be checked at run-time.
Heck, now that someone actually says it, that really seems quite logical.
The compile time logic could be something like this:
For the expression $a = $b,
if $b.type ISA $a.type : OK ( $b is same or subclass of $a )
elsif $a.type ISA $b.type : defer until runtime ($a is subclass of $b)
else : compile time ERROR
If we assume[1] that Scalar is the base of all classes, then we get the
desired typed <-> untyped behavior for free. I like it! (Unknown type
situations are always deferred of course.)
We still need an occasional typecast for the really bizarre situations
like my multiply-inherited-siblings example. I like the suggested "as"
keyword for that, especially since I'm already used to it in Delphi.
OTOH, one could always force runtime checking with an intermediate untyped
variable. $a = my $xxx = $b. Naah, I still like "as" better.
[1] Scalar might be a container class. Maybe Object is the base class for
values.
On second thought, one could consider $a = $b as a sort of typecast
already, since both sides have type information already. (Not that I'm
saying it really is, just that we have enough information.) The real
problem is with this:
class Foo is Bar { method foo; }
my Bar $b = Foo.new;
...
$b.foo;
Since foo is not a method of Bar, and the compiler doesn't really know
which subclass of Bar it might be from, this would be a compile time error
unless:
(A) I write ($b as Foo).foo;
(B) The compiler always punts until runtime.
(C) The compiler searches all known subclasses of Bar for foo.
(A) is ugly, and results in a lot of useless code which makes the useful
code hard to read. It is also what most languages do. I hope we can find
a way to avoid it.
(B) is not very efficient.
(C) sucks. I'm embarrassed to even suggest it.
Are there any other alternatives?
Actually, I think I favor (B). At runtime it asks "Can $b foo?".
In (A) we already know that a Foo can foo, but we still have to ask at
runtime "Is $b a Foo?" to validate the typecast, so it doesn't eliminate
all runtime cost. We may not even be able to precompute which foo to
call, because $b could also be a subclass of Foo which overrides foo.
fooey!
> Alternatively, we could go with the "typed" idea I mentioned earlier, and
> say
>
> my Foo $x = (my Object $z = Foo.new).typed(Foo);
>
> I like this better than the "obvious" .Foo trait, because when dealing with
> multiply typed vars, it's easier:
>
> my $x is Slicer is Dicer is Grinder;
> my $j = $x;
> $x = $j.Slicer.Dicer.Grinder; # Doubtful
> $x = $j.typed(Slicer, Dicer, Grinder);
That (or using properties: $j but typed(Slicer,Dicer,Mixer)) looks more
like Mixin classes to me.
~ John Williams
Thread Previous
|
Thread Next