Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coercions don't ensure result type #5567

Open
p6rt opened this issue Aug 14, 2016 · 4 comments
Open

coercions don't ensure result type #5567

p6rt opened this issue Aug 14, 2016 · 4 comments

Comments

@p6rt
Copy link

@p6rt p6rt commented Aug 14, 2016

Migrated from rt.perl.org#128927 (status was 'open')

Searchable as RT128927$

@p6rt
Copy link
Author

@p6rt p6rt commented Aug 14, 2016

From zefram@fysh.org

The description of coercion in S02 says​:

# The type outside the parens indicates the desired end result, and
# subsequent code may depend on it being that type.

Rakudo does not actually ensure that the result of a coercion is of the
requested type. We can readily see this by constructing an object with
an uncooperative coercion method​:

(sub (Int() $a) { $a })("abc" but role { method Int () { :xyz } }).perl
:xyz

Here the sub's $a is supposedly guaranteed to be an Int, but it's actually
a Pair. This doesn't only arise from code deliberately constructed to
do this. It also arises from some reasonable use of the built-in numeric
types, among which there are a couple of uncooperative coercion methods​:

(sub (FatRat() $a) { $a })(Inf).^isa(FatRat)
0

The value received in $a here is apparently a Rational[Num,Int], and it
fails to .perl. It's definitely not the promised FatRat.

Because coercion methods are identified by the name of the target type,
rather than by some first-class reference to the type, and because
scoping allows the same name to refer to different types in different
places, there's an inherent possibility that a coercion method written
with cooperative intent might be invoked for coercion to the wrong type.
Similarly, because coercion methods aren't formally distinguished from
other named methods, it's inherently possible for a method never intended
for coercion to be invoked for a coercion. Both of those situations
look like an uncooperative coercion method. So it is not possible to
resolve this problem by putting the onus entirely on coercion methods
to return the right type. There has to be enforcement.

-zefram

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Sep 11, 2017

From @skids

On Sun, 14 Aug 2016 08​:01​:48 -0700, zefram@​fysh.org wrote​:

The description of coercion in S02 says​:

# The type outside the parens indicates the desired end result, and
# subsequent code may depend on it being that type.

Rakudo does not actually ensure that the result of a coercion is of the
requested type. We can readily see this by constructing an object with
an uncooperative coercion method​:

(sub (Int() $a) { $a })("abc" but role { method Int () { :xyz } }).perl
:xyz

Here the sub's $a is supposedly guaranteed to be an Int, but it's actually
a Pair. This doesn't only arise from code deliberately constructed to
do this. It also arises from some reasonable use of the built-in numeric
types, among which there are a couple of uncooperative coercion methods​:

(sub (FatRat() $a) { $a })(Inf).^isa(FatRat)
0

The value received in $a here is apparently a Rational[Num,Int], and it
fails to .perl. It's definitely not the promised FatRat.

Because coercion methods are identified by the name of the target type,
rather than by some first-class reference to the type, and because
scoping allows the same name to refer to different types in different
places, there's an inherent possibility that a coercion method written
with cooperative intent might be invoked for coercion to the wrong type.
Similarly, because coercion methods aren't formally distinguished from
other named methods, it's inherently possible for a method never intended
for coercion to be invoked for a coercion. Both of those situations
look like an uncooperative coercion method. So it is not possible to
resolve this problem by putting the onus entirely on coercion methods
to return the right type. There has to be enforcement.

-zefram

Just a thought​: we cannot avoid runtime checks when the argument can be
anything, but if we know its type at compile time, and if we found and
introspected the coercion method, and if that method defined a return
type, we might be able to catch errors ahead of time. (We'd still
have to deal with Nil/Failure at runtime, though.)

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Sep 11, 2017

The RT System itself - Status changed from 'new' to 'open'

Loading

@p6rt p6rt added the Bug label Jan 5, 2020
@usev6
Copy link

@usev6 usev6 commented Apr 4, 2021

The examples from the bug report are working now:

$ ./rakudo-m -e 'say (sub (Int() $a) { $a })("abc" but role { method Int () { :xyz } }).raku'
Impossible coercion from 'Str+{<anon|1>}' into 'Int': method Int returned an instance of Pair
  in sub  at -e line 1
  in block <unit> at -e line 1
$ ./rakudo-m -e 'say (sub (FatRat() $a) { $a })(Inf).^isa(FatRat)'
1

If I'm not mistaken coercions do ensure the result type now. This has been fixed by @vrurg in the context of Raku/problem-solving#227.

Again if I'm not mistaken there is already a test in roast for (a variation of) the first example. It has been unfudged with Raku/roast@4718d3e#diff-0068e381348d099424e5f745766eed92d86f3a80fa42025cb5247e052e348238L38-R38 . I'd expect that there is a test for (a variation of) the second example, too -- but I didn't see it at a cursory glance. Would require a closer look with a fresh brain.

Nevertheless I'd think it make sense to add the above examples as regression tests somewhere in S12-coercion.
Tagging testneeded.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants