Skip Menu |
Report information
Id: 129907
Status: new
Priority: 0/
Queue: perl6

Owner: Nobody
Requestors: david.warring <david.warring [at] gmail.com>
Cc:
AdminCc:

Severity: (no value)
Tag: (no value)
Platform: (no value)
Patch Status: (no value)
VM: (no value)



Subject: [BUG] interaction of class FALLBACK methods and safe method calls (.?)
To: rakudobug [...] perl.org
From: David Warring <david.warring [...] gmail.com>
Date: Tue, 18 Oct 2016 13:34:29 +1300
Download (untitled) / with headers
text/plain 1.6k
I'm adding a FALLBACK method to create method dynamically, the it receives both '.' and '.?' invocations, and I can't distinguish between them.

This then breaks $obj.unknown vs $obj.?unknown handling in class objects.

Consider:

use Test;

class C {
    method foo { 42 }
    method FALLBACK($meth-name, |c) {
        warn "can $meth-name";
        if $meth-name eq 'bar' {
            self.^add_method($meth-name, method { 69 });
            self."$meth-name"(|c);
        }
        else {
            warn "dunno if this is a safe method call or not";
            Nil;
        }
    }
}

for C {
    my $obj = .new;
    is $obj.foo, 42, 'static method - direct call';
    is $obj.?foo, 42, 'static method - safe call';
    is $obj.bar, 69, 'dynamic method - direct call';
    is $obj.?bar, 69, 'dynamic method - safe call';
    todo "can't get both of these to pass!";
    dies-ok {$obj.unknown}, 'direct call - unknown method dies';
    lives-ok {$obj.?unknown}, 'safe call - unknown method lives';
}

I'm receiving both the safe and unsafe 'unknown' invocations, and can't distinguish them.

I also tried overriding the classes 'can' method:

class C {
    method foo { 42 }
    method can($meth-name) {
        my $meths = callsame;
        if !$meths && $meth-name eq 'bar' {
            $meths = [method { 69 }, ];
            self.^add_method($meth-name, $meths[0]);
        }
        $meths;
    }
    method FALLBACK($meth-name, |c) {
        if self.can($meth-name) {
            self."$meth-name"(|c);
        }
        else {
            warn "dunno if this is a safe method call or not";
            Nil;
        }
    }
}

But the FALLBACK is still needed, and still has the same problem.

Any ideas?


From: David Warring <david.warring [...] gmail.com>
CC: bugs-bitbucket [...] rt.perl.org
To: perl6-compiler [...] perl.org
Subject: Re: [perl #129907] [BUG] interaction of class FALLBACK methods and safe method calls (.?)
Date: Thu, 20 Oct 2016 08:17:08 +1300
Download (untitled) / with headers
text/plain 3.2k
I've worked out how to do it, by adding a custom dispatch:<.?> method:

use Test;

class C {
    method foo { 42 }
    method can($meth-name) {
        my $meths = callsame;
        if !$meths && $meth-name eq 'bar' {
            $meths = [method { 69 }, ];
            self.^add_method($meth-name, $meths[0]);
        }
        $meths;
    }
    method dispatch:<.?>(\name, |c) is raw {
        self.can(name)
            ?? self."{name}"(|c)
            !! Nil
    }
    method FALLBACK(\name, |c) {
        if self.can(name) {
            self."{name}"(|c);
        }
        else {
            die X::Method::NotFound.new( :method(name), :typename(self.^name) );
        }
    }
}

for C {
    my $obj = .new;
    is $obj.foo, 42, 'static method - direct call';
    is $obj.?foo, 42, 'static method - safe call';
    is $obj.bar, 69, 'dynamic method - direct call';
    is $obj.?bar, 69, 'dynamic method - safe call';
    dies-ok {$obj.unknown}, 'direct call - unknown method dies';
    lives-ok {$obj.?unknown}, 'safe call - unknown method lives';
}

Based on some code I found in the core Rakudo Mu class.
Slightly awkward, but at least working.

On Tue, Oct 18, 2016 at 1:35 PM, David Warring <perl6-bugs-followup@perl.org> wrote:
Show quoted text
# New Ticket Created by  David Warring
# Please include the string:  [perl #129907]
# in the subject line of all future correspondence about this issue.
# <URL: https://rt.perl.org/Ticket/Display.html?id=129907 >


I'm adding a FALLBACK method to create method dynamically, the it receives
both '.' and '.?' invocations, and I can't distinguish between them.

This then breaks $obj.unknown vs $obj.?unknown handling in class objects.

Consider:

use Test;

class C {
    method foo { 42 }
    method FALLBACK($meth-name, |c) {
        warn "can $meth-name";
        if $meth-name eq 'bar' {
            self.^add_method($meth-name, method { 69 });
            self."$meth-name"(|c);
        }
        else {
            warn "dunno if this is a safe method call or not";
            Nil;
        }
    }
}

for C {
    my $obj = .new;
    is $obj.foo, 42, 'static method - direct call';
    is $obj.?foo, 42, 'static method - safe call';
    is $obj.bar, 69, 'dynamic method - direct call';
    is $obj.?bar, 69, 'dynamic method - safe call';
    todo "can't get both of these to pass!";
    dies-ok {$obj.unknown}, 'direct call - unknown method dies';
    lives-ok {$obj.?unknown}, 'safe call - unknown method lives';
}

I'm receiving both the safe and unsafe 'unknown' invocations, and can't
distinguish them.

I also tried overriding the classes 'can' method:

class C {
    method foo { 42 }
    method can($meth-name) {
        my $meths = callsame;
        if !$meths && $meth-name eq 'bar' {
            $meths = [method { 69 }, ];
            self.^add_method($meth-name, $meths[0]);
        }
        $meths;
    }
    method FALLBACK($meth-name, |c) {
        if self.can($meth-name) {
            self."$meth-name"(|c);
        }
        else {
            warn "dunno if this is a safe method call or not";
            Nil;
        }
    }
}

But the FALLBACK is still needed, and still has the same problem.

Any ideas?

Download (untitled) / with headers
text/plain 3.9k
Unless I'm mistaken, it takes a bit of extra boiler plate code in a class to add a method in such a way that it plays well with other features, such as the .can introspection method and .? safe invocation. It would be more awesome, if I could do a minimal amount of work, and Rakudo would take care of the details and make sure I'm not breaking anything. Maybe overriding the 'can' method should be enough? On Wed Oct 19 12:17:40 2016, david.warring wrote: Show quoted text
> I've worked out how to do it, by adding a custom dispatch:<.?> method: > > use Test; > > class C { > method foo { 42 } > method can($meth-name) { > my $meths = callsame; > if !$meths && $meth-name eq 'bar' { > $meths = [method { 69 }, ]; > self.^add_method($meth-name, $meths[0]); > } > $meths; > } > method dispatch:<.?>(\name, |c) is raw { > self.can(name) > ?? self."{name}"(|c) > !! Nil > } > method FALLBACK(\name, |c) { > if self.can(name) { > self."{name}"(|c); > } > else { > die X::Method::NotFound.new( :method(name), > :typename(self.^name) ); > } > } > } > > for C { > my $obj = .new; > is $obj.foo, 42, 'static method - direct call'; > is $obj.?foo, 42, 'static method - safe call'; > is $obj.bar, 69, 'dynamic method - direct call'; > is $obj.?bar, 69, 'dynamic method - safe call'; > dies-ok {$obj.unknown}, 'direct call - unknown method dies'; > lives-ok {$obj.?unknown}, 'safe call - unknown method lives'; > } > > Based on some code I found in the core Rakudo Mu class. > Slightly awkward, but at least working. > > On Tue, Oct 18, 2016 at 1:35 PM, David Warring <perl6-bugs-followup@perl.org
> > wrote:
>
> > # New Ticket Created by David Warring > > # Please include the string: [perl #129907] > > # in the subject line of all future correspondence about this issue. > > # <URL: https://rt.perl.org/Ticket/Display.html?id=129907 > > > > > > > I'm adding a FALLBACK method to create method dynamically, the it receives > > both '.' and '.?' invocations, and I can't distinguish between them. > > > > This then breaks $obj.unknown vs $obj.?unknown handling in class objects. > > > > Consider: > > > > use Test; > > > > class C { > > method foo { 42 } > > method FALLBACK($meth-name, |c) { > > warn "can $meth-name"; > > if $meth-name eq 'bar' { > > self.^add_method($meth-name, method { 69 }); > > self."$meth-name"(|c); > > } > > else { > > warn "dunno if this is a safe method call or not"; > > Nil; > > } > > } > > } > > > > for C { > > my $obj = .new; > > is $obj.foo, 42, 'static method - direct call'; > > is $obj.?foo, 42, 'static method - safe call'; > > is $obj.bar, 69, 'dynamic method - direct call'; > > is $obj.?bar, 69, 'dynamic method - safe call'; > > todo "can't get both of these to pass!"; > > dies-ok {$obj.unknown}, 'direct call - unknown method dies'; > > lives-ok {$obj.?unknown}, 'safe call - unknown method lives'; > > } > > > > I'm receiving both the safe and unsafe 'unknown' invocations, and can't > > distinguish them. > > > > I also tried overriding the classes 'can' method: > > > > class C { > > method foo { 42 } > > method can($meth-name) { > > my $meths = callsame; > > if !$meths && $meth-name eq 'bar' { > > $meths = [method { 69 }, ]; > > self.^add_method($meth-name, $meths[0]); > > } > > $meths; > > } > > method FALLBACK($meth-name, |c) { > > if self.can($meth-name) { > > self."$meth-name"(|c); > > } > > else { > > warn "dunno if this is a safe method call or not"; > > Nil; > > } > > } > > } > > > > But the FALLBACK is still needed, and still has the same problem. > > > > Any ideas? > >


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org