Front page | perl.perl5.porters |
Postings from August 1999
Re: Purpose of Strong Typing.
Thread Previous
|
Thread Next
From:
Steve Fink
Date:
August 31, 1999 20:29
Subject:
Re: Purpose of Strong Typing.
Message ID:
37CC9D38.DC1EB633@digital-integrity.com
[not sure if Larry should really be cc'd, but...]
Wait, wait. The question posed was a general one. I was answering it
generally, not in the context of what is or is not doable in the current
thinking about perl type checking. Ed seemed to be claiming that strong
typing is only good for compile-time checking. (BTW, strong is a bit of
a misnomer here, since I'd be willing to bet that Perl's never going to
have a safe type system in the computer science sense of the term.) I
was merely saying that it's useful for a number of additional reasons.
I'm really familiar enough with perlguts, or more importantly the
current proposals, to discuss perl-specific justifications for typing.
But I'll still object to some of your claims.
Ilya Zakharevich wrote:
>
> Steve Fink writes:
> > 1. compile-time type checking
>
> Impossible. You need to chase ISA tree *back* to implement this.
Impossible? Under what assumptions? Seems feasible with immutable
compile-time @ISA assignments, together with semi-immutable [see below]
package sub definitions. Why not? (And if anything in the @ISA chain
does not have such an ISA assignment, thereby allowing runtime
modification of @ISA, you disable type checking.)
Straw-man proposal:
package B ();
sub foo : inheritable { ... } # inheritable attr might be default
sub bar { ... }
package A qw(B C); # immutable @ISA = qw(B C)
package main;
my A $a = bless {}, A;
$a->foo(); # OK
$a->bar(); # depends on whether inheritable defaults to on or off
$a->blah(); # error
*B::blah = sub { ... } # no effect on compile-time signature
$a->blah(); # still an error
my $a2 = $a;
$a2->blah(); # OK, I suppose
In other words, every package is given a compile-time signature and the
usual run-time signature. The compile-time signature contains all
subroutine definitions known at compile-time (or only those tagged with
:inheritable?) The run-time signature is a superset of the compile-time
signature (unless you can blow away subroutines at runtime?) Immutable
@ISA assignment modifies both the compile- and run-time signatures;
normal @ISA = assignment affects only run-time signatures. So if you
want typechecking, you don't call any subroutines added at runtime. (Or
you "cast" away the type, as in my A $a; my $a2 = $a;) And if at runtime
you complete reconfigure your inheritance hierarchy, then you deserve
what you get. (Which is to not only lose the usefulness of compile-time
checking, but also to get "incorrect" results if you attempt to use it.)
The problem is that I don't know enough about importing modules to know
whether the above is even feasible. use X implies a BEGIN {}? So if you
ignored wherever I said "compile-time" and instead said "BEGIN-time",
would it be possible?
>
> > 2. run-time type checking
> > - it's still better to give a type error than to silently do something
> > unexpected. At least, if that's what you ask for. For example, it's
> > better than later complaining about an undefined method, since it
> > catches the original source of the problem and narrows down the set of
> > possible screwups.
>
> Like what? I do not see offhand how one would be able to provide a
> more meaningful error message.
my Dog $d = new Dog;
my Cat $c;
$c = $d; # Cannot assign value of type "Dog" to scalar of type "Cat"
$c->purr(); # Can't locate object method "bark" via package "Dog"
Type checking gives you the first error message. Without it, you would
have to trace backwards from the second error message to find the
offending assignment statement, which may have come from a long time
before.
Or:
my TwoDigitYear $x = 99;
sub years_to_go (FourDigitYear $) {
2037 - shift;
}
print "There are ", years_to_go($x), " years until the year 2037!";
> > 3. enabling optimizations
>
> Like *what*?
Allow removing the run-time lookup of the method name in some cases
(maybe). I was actually thinking more of C backend optimizations,
though.
> > 4. more understandable code
>
> Maybe indeed.
Here be dragons. I think that restricting the set of possible operations
that can be performed on a variable is useful as documentation. One,
because it means the reader of the code knows to not consider as many
wacky possibilities ($x++... hmm... could that be a magic increment of a
string variable, I wonder? My head hurts...). Two, because when someone
thinks they (incorrectly) understand the code and attempt to modify it,
they are quickly informed that their assumptions are incorrect.
>
> > 5. user-defined type coercion
> > - the programmer may know a better way of converting a Dog to a Cat
> > than the grooming function mentioned above ;)
>
> Again, can you be more specific?
years_to_go: hmm... I accept things of type FourDigitYear, I was given a
TwoDigitYear. $FourDigitYear::{FROM}{TwoDigitYear} exists. I think I'll
call that on my first parameter before executing.
$FourDigitYear::{FROM}{TwoDigitYear} = sub {
warn("some idiot is using 2-digit years!");
my $y = shift;
return $y + 2000 if ($y < 50);
return $y + 1900;
}
just my 2 cents. Not worth much more than that, either.
Thread Previous
|
Thread Next