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

Add Mu.Callable($method) "coercer" #5513

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Add Mu.Callable($method) "coercer" #5513

wants to merge 6 commits into from

Conversation

lizmat
Copy link
Contributor

@lizmat lizmat commented Jan 14, 2024

The idea being that Raku should provide a HLL interface to obtain a Callable object for the given method name on the invocant.

$ raku -e 'say Int.Callable("Str")(687, :subscript)'
₆₈₇

In place of the .^find_method logic, which is not Raku specific according to the documentation:

https://docs.raku.org/type/Metamodel/DefiniteHOW#method_find_method

EDIT: change Sub to Callable

The idea being that *Raku* should provide a HLL interface to obtain
a Sub object for the given method name on the invocant.

    $ raku -e 'say Int.Sub("Str")(687, :subscript)'
    ₆₈₇

In place of the .^find_method logic, which is *not* Raku specific
according to the documentation:

  https://docs.raku.org/type/Metamodel/DefiniteHOW#method_find_method
@jnthn
Copy link
Member

jnthn commented Jan 14, 2024

I'd count .^find_method as a specified part of the language. Probably much of the MOP can be considered to be by this point; anything that's had a consistent interface for the last 10 years can probably be counted on as a durable design!

- use nqp::tryfindmethod instead of nqp::findmethod
- use nqp::ifnull instead of // to handle VMnull values
@vrurg
Copy link
Member

vrurg commented Jan 15, 2024

I would call it Method because Sub is confusing about what's really happening.

In hindsight, this is probably better, as .Sub may be considered
premature huffmanization.  And what is being returned, is usually
*not* a Sub object anyway.
@lizmat lizmat changed the title Add Mu.Sub($method) "coercer" Add Mu.Callable($method) "coercer" Jan 15, 2024
@lizmat
Copy link
Contributor Author

lizmat commented Jan 15, 2024

I'd count .^find_method as a specified part of the language. Probably much of the MOP can be considered to be by this point

There are indeed quite of a few occurrences of find_method in roast. So I'm starting to wonder whether the documentation is incorrect in stating it is Rakudo specific.

% rak §.^find_method t/spec
t/spec/6.c/APPENDICES/A04-experimental/01-misc.t
314:is-deeply $o.^find_method('v').returns, Str(Any),

t/spec/6.c/APPENDICES/A04-experimental/01-misc.rakudo.moar
323:is-deeply $o.^find_method('v').returns, Str(Any),

t/spec/S06-advanced/dispatching.t
133:my \proto := C2.^find_method('foo', :local, :no_fallback);
221:C2.^find_method('foo', :no_fallback, :local)

t/spec/S06-advanced/wrap.rakudo.moar
253:$pkg.^find_method($accessor).wrap($r);
288:$pkg.^find_method($accessor).wrap($r);
323:$pkg.^find_method($accessor).wrap($r);
358:$pkg.^find_method($accessor).wrap($r);
416:C2.^find_method('foo', :no_fallback).wrap( my method foo { @order.push: 'wrapper'; nextsame } );
417:C2.^find_method('bar', :no_fallback).candidates[0].wrap( my method bar (|) { @order.push: 'wrapper::bar'; callsame } );

t/spec/S06-advanced/dispatching.rakudo.moar
133:#         my \proto := C2.^find_method('foo', :local, :no_fallback);
221:#         C2.^find_method('foo', :no_fallback, :local)

t/spec/S06-advanced/wrap.t
253:$pkg.^find_method($accessor).wrap($r);
288:$pkg.^find_method($accessor).wrap($r);
323:$pkg.^find_method($accessor).wrap($r);
358:$pkg.^find_method($accessor).wrap($r);
416:C2.^find_method('foo', :no_fallback).wrap( my method foo { @order.push: 'wrapper'; nextsame } );
417:C2.^find_method('bar', :no_fallback).candidates[0].wrap( my method bar (|) { @order.push: 'wrapper::bar'; callsame } );

t/spec/S12-meta/primitives.t
54:Any.^find_method($name);
96:method find_method(|) { Mu.^find_method('CREATE') }

t/spec/S06-signature/introspection.t
267:is B.^find_method("foo").signature.params[1].twigil, "!",
269:is B.^find_method("bar").signature.params[1].twigil, ".",

t/spec/S06-signature/introspection.rakudo.moar
268:is B.^find_method("foo").signature.params[1].twigil, "!",
270:is B.^find_method("bar").signature.params[1].twigil, ".",

t/spec/S02-types/capture.t
140:ok \(RT116002, 42) ~~ RT116002.^find_method("foo").signature,
142:nok \(RT116002, @a) ~~ RT116002.^find_method("foo").signature,
144:ok \(RT116002, |@a) ~~ RT116002.^find_method("foo").signature,

t/spec/integration/advent2011-day10.t
27:is Sheep.^find_method('bark').WHY.contents, "produces a funny sound", "method .WHY";

t/spec/S12-introspection/meta-class.t
80:is Any.^find_method('supercalafajalistickexpialadojus').defined,

t/spec/S26-documentation/multiline-trailing.t
16:is ~App.^find_method('do-stuff').WHY, "Does Stuff";

t/spec/S26-documentation/multiline-leading.t
23:my $method = App.^find_method('do-stuff');

t/spec/S26-documentation/block-trailing.t
87:my $roar-method = Sheep.^find_method('roar');
179:my @params = DoesntMatter.^find_method('m').signature.params;
210:my $submethod = C.^find_method("BUILD");
213:my $meth = C.^find_method('meth');
231:my $rule = G.^find_method("R");
232:my $token = G.^find_method("T");
233:my $regex = G.^find_method("X");

t/spec/S26-documentation/block-leading.t
89:my $roar-method = Sheep.^find_method('roar');
184:my @params = DoesntMatter.^find_method('m').signature.params;
215:my $submethod = C.^find_method("BUILD");
218:my $meth = C.^find_method('meth');
236:my $rule = G.^find_method("R");
237:my $token = G.^find_method("T");
238:my $regex = G.^find_method("X");

@lizmat
Copy link
Contributor Author

lizmat commented Jan 15, 2024

On quick glancing, these appear the meta-model methods called in roast:

.^add_attribute
.^add_fallback
.^add_method
.^add_multi_method
.^attributes
.^auth
.^can
.^candidates
.^coerce
.^compose
.^concretization
.^curried_role
.^does
.^enum_value_list
.^find_method
.^isa
.^language
.^lookup
.^methods
.^mro
.^mro_unhidden
.^name
.^num
.^parents
.^pun
.^roles
.^set_name
.^shortname
.^tryit
.^ver

@vrurg
Copy link
Member

vrurg commented Jan 15, 2024

There are indeed quite of a few occurrences of find_method in roast. So I'm starting to wonder whether the documentation is incorrect in stating it is Rakudo specific.

It's not that much the method itself is specific but the interface it provides. For example, :no_fallback is better be renamed to :no-fallback to follow the general naming rules.

@lizmat
Copy link
Contributor Author

lizmat commented Jan 15, 2024

Well, there's that indeed. Also I think we need to get rid of the "Perl6" in the naming of the MOP.

@vrurg
Copy link
Member

vrurg commented Jan 15, 2024

BTW, did you see my other comments about is pure and return value?

@lizmat
Copy link
Contributor Author

lizmat commented Jan 15, 2024

BTW, did you see my other comments about is pure and return value?

I don't see them here. Where should I have seen them? In any case, the method is now "pure" and the return value is Nil if not found.

@vrurg
Copy link
Member

vrurg commented Jan 15, 2024

I don't see them here.

I made them under https://github.com/rakudo/rakudo/pull/5513/files/b23f0e5fe68fbdc5fea8823428445152cc00e6ea and can see both up here. Anyway...

The method cannot be pure because it depends on an independent mutable source of information. In other words, things may change between two consequent .Callable("foo") calls. The first may end up failed (see the next note). The second may succeed because something installed the method.

Returning Nil is a bad idea. Though at first I thought that Nil.() would result in Nil itself and .Callable("no-method")() may remain unnoticed until some long-distance effects, but turns out it would end up with No such method 'CALL-ME' for invocant of type 'Nil'. If there is an argument, it turn into even worse Cannot find method 'is_dispatcher' on object of type BOOTCode. Either outcome, event though it would point at the exact location where the error takes place, is misleading. A Failure(X::MethodNotFound) seems like much better option.

@raiph
Copy link
Contributor

raiph commented Jan 15, 2024

Ah, @vrurg's latest comment only appeared after I posted this comment. (BTW, I'm not seeing any comment by @vrurg on the commit he linked. Maybe GH has caching issues?!? Or my browser (chrome)?)


A cache on Callable is slightly surprising to me. Two things come to mind:

  1. Are all Raku types such that the only changes that can be made to them (changing attributes, routines, ...) are such that all existing (cached) callables are guaranteed to still exist and be callable? For example, are use of MOP calls and features like augment constrained that way?

  2. Aiui nqp and/or MoarVM are currently responsible for most or all of the caching related to things like callables. If I'm right about that, is the idea here to eliminate their caches for Raku, or will there be two levels of caching, or...?

@vrurg
Copy link
Member

vrurg commented Jan 16, 2024

It looks like links to review comments are different from plain commits. I've updated the link above to the working one: https://github.com/rakudo/rakudo/pull/5513/files/b23f0e5fe68fbdc5fea8823428445152cc00e6ea

src/core.c/Mu.rakumod Outdated Show resolved Hide resolved
src/core.c/Mu.rakumod Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants