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

Detect method call type within FALLBACK method #5755

Open
p6rt opened this issue Oct 18, 2016 · 3 comments
Open

Detect method call type within FALLBACK method #5755

p6rt opened this issue Oct 18, 2016 · 3 comments
Labels
RFC Request For Comments

Comments

@p6rt
Copy link

p6rt commented Oct 18, 2016

Migrated from rt.perl.org#129907 (status was 'new')

Searchable as RT129907$

@p6rt
Copy link
Author

p6rt commented Oct 18, 2016

From @dwarring

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?

@p6rt
Copy link
Author

p6rt commented Oct 19, 2016

From @dwarring

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-archive.perl.org/perl6/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?

@p6rt
Copy link
Author

p6rt commented Oct 19, 2016

From @dwarring

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​:

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-archive.perl.org/perl6/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?

@p6rt p6rt added the RFC Request For Comments label Jan 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC Request For Comments
Projects
None yet
Development

No branches or pull requests

1 participant