Front page | perl.perl5.porters |
Postings from December 2021
Re: No implicit coercion?
Thread Previous
|
Thread Next
From:
Nicholas Clark
Date:
December 28, 2021 09:11
Subject:
Re: No implicit coercion?
Message ID:
YcrUtlpVGcIk9pcv@etla.org
On Mon, Dec 27, 2021 at 06:35:05PM +0000, Ovid via perl5-porters wrote:
Re-ordering the sections...
> The core of the idea is simple. it would be lovely to have something to prevent implicit coercion in a given lexical scope:
>
> use explicit;
> my $num = 3; # integer
> $num += .42; # fatal because it creates a float
>
> Instead, we have to do this:
>
> use explicit;
> my $num = 4;
> $num = float($num);
> # or `$num = 4.0;`
> $num += .42; # works just fine
making explicit floating point <=> integer conversion workable is fraught
(with complexity and confusion). If Perl *has* a design architecture at all,
part of it is that scalars are just scalars, and you use operators to
declare whether they are to be treated as strings, numbers
(or something else). There isn't *any* existing distinction between whether
your numbers are integers, floating points, (or bigints or anything else
that can be implemented via overloading)
I'm going to write 4.0 to mean a floating point four, and 4 to mean an integer
four here
What's the result of this:
$result = int 4.2;
Is it 4.0 or 4?
I could make a case for either answer. Type conversion, or truncation towards
0?
Similarly abs. sqrt probably isn't ambiguous (you want integer square roots,
you convert to float and truncate back), but there might be others I didn't
think of.
More generally, under `use explict` the return type of addition:
$c = $a + $b;
$a FLOAT INT
$b
FLOAT float croak
INT croak int*
* but croak on overflow
1) The above table means that we have an op that is still polymorphic.
2) It can return int or float (or croak), depending on inputs.
3) It doesn't handle overloaded objects
4) There's no clean way to say "I'd like floating point maths always, other
than"
$c = float($a) + float($b);
as you need to cast first to avoid that corner case of integer overflow
And under `no explicit`, `$a + $b` does whatever it currently does?
(which isn't that table above, even with the croaks removed)
The "overloading" mentioned above feels like a can of worms. I'm really not
sure if the current overloading interface maps to what is needed. Or what
would work. Conversion is declared as:
conversion => 'bool "" 0+ qr',
There's no integer/floating point distinction. And I suspect that trying to
constrain it to those two hinders bigint/bigfloat/bigrat interaction, and I
don't think that just adding a third numeric type is going to be sufficient.
If one takes out the floating point/integer conversion control:
> my @values = (in => "data.csv");
> $values[2]++;
>
> Except that $values[2] was the string "n/a" and now it's "1".
Fatalising string to numeric seems easy both conceptually and implementation
wise. Arguably it's just a matter of spelling - how to turn it on, and what
the error message should say. I think the mechanisms have been in place since
5.6.0:
$ perl -we 'eval { use warnings FATAL => "numeric"; $values[2] = "n/a"; $values[2]++; }; print "We got: $@"'
We got: Argument "n/a" treated as 0 in increment (++) at -e line 1.
However, there's no way to fatalise conversion in the other direction.
It seems a bit strange to name the pragma as "explicit conversion" when it's
more about explicit lossy conversion.
> This would also be fatal:
>
> use explicit;
> my $value = {};
> say ++$value;
Being able to fatalise this (and independently stringification of references)
has been talked about for a while.
I'm not sure if anyone had a plan that considered references to objects with
overloading
As ever, there seems to be an arms race between folks who create such objects
"it's semantically a scalar. Treat it as such. I put effort into making
it walk and quack like a kosher duck"
and folks who receive such objects
"your Trojan duck is actually made of wood. It's inedible"
Other missed corner cases are whether it matters that this would need to be
turned off in order to compare two references (for equality, and for ordering
such as sorting), and generating hash keys from references.
And how to avoid the actual error message getting lost if a reference is
mistakenly stringified when generating an error message. (Likely to be missed
during testing, and only bite in production.)
> Is this possible? I realize there are many edge cases.
I think that attempting to constrain numbers to just "integers" and
"floating point" has too many edge cases to be realistically implementable.
It's also inflexible, as there are a lot more classes of numbers than
"native sized integers" and "native sized binary floating point".
Faulting lossy string to number conversion, and faulting references used as
strings or numbers seems viable, but I think that they belong as 2 (or
even 3) different names.
Nicholas Clark
Thread Previous
|
Thread Next