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

->method treats sub stubs inconsistently #300

Open
cpansprout opened this issue Nov 2, 2017 · 4 comments
Open

->method treats sub stubs inconsistently #300

cpansprout opened this issue Nov 2, 2017 · 4 comments

Comments

@cpansprout
Copy link

This is related to pull request #299.

Since perl 5.6.0 or so, stub created by ‘sub foo;’ declarations have been stored in the stash as simple scalars, as opposed to globs holding CVs lacking bodies.

perl5i’s $class->mc->methods method ignores such subs, but does not ignore those that have been upgraded; e.g., by taking a reference. The upgrading can also happen when calling a stub as a method:

$ perl5.26.0 -Mperl5i -le 'package Foo{sub bar; AUTOLOAD{}} print for Foo->mc->methods'
AUTOLOAD
$ perl5.26.0 -Mperl5i -le 'package Foo{sub bar; AUTOLOAD{}} Foo->bar; print for Foo->mc->methods'
AUTOLOAD
bar

Should perl5i should be including these or not? I believe it should behave consistently at least, but this may not be important enough to worry about.

Incidentally, declaring a stub via ‘sub foo;’ puts -1 in the stash element, and declaring a stub via ‘sub foo ($)’ puts "$" in the stash element.

@schwern
Copy link
Contributor

schwern commented Nov 2, 2017

Yup, that isn't something we considered when writing methods.

The docs for methods say "By default it returns all the methods available". My initial opinion is to say that if it's callable as a method, then yes, it should be included.

@cpansprout
Copy link
Author

Do we want to go so far as to return a stub name only if there is a callable AUTOLOAD present? (Under the assumption that someone may have accidentally vivified a sub by taking a reference to it.) Or should we assume that code is written correctly, and that stubs are methods (which would simpler, and hence less buggy, to implement)?

@schwern
Copy link
Contributor

schwern commented Nov 3, 2017

Hmm. Part of the point of perl5i is to handle the complicated cases that Perl 5 punts on. If we don't handle the complicated cases someone else will have to do it, a lot of someone elses, all differently. That's my thinking until this rabbit hole gets too deep.

Is AUTOLOAD the only way that a stub can be used as a method? I know somewhere there's a clear listing of the complete Perl method lookup scheme, but I can't find it. Also, just because there's a stub doesn't mean AUTOLOAD won't throw its own Can't locate object method "bar" via package "Foo" exception when you try to call it. And that also seems to result in a real sub.

$ perl5i -Ilib -e 'package Foo; sub bar; sub AUTOLOAD {die}; eval { Foo->bar; }; say for Foo->mc->methods'
bar
AUTOLOAD

With that in mind, we might be trying to read too far into the intent of a stub and AUTOLOAD. Could we rely on can instead?

Maybe we need to back up and more tightly define the use cases of methods. I wrote it mostly for manual debugging and introspection purposes, what methods are available on this class or object? Just doing that involves a lot of symbol table code, so it's for convenience.

Here's a thought. I'd always meant to do more with perl5i::2::CODE. With that it's possible to add methods and metadata to a CODE reference. Perhaps the answer is to change methods to return string overloaded CODE references (or if that's not possible, string overloaded objects). Then the user can ask for things like its short name (ie. bar), full name (Foo::bar), prototype, and so on to make their own determination. That would roll together the functionality of several different CPAN modules for introspecting code references.

@cpansprout
Copy link
Author

Is AUTOLOAD the only way that a stub can be used as a method?

It is.

Also, just because there's a stub doesn't mean AUTOLOAD won't throw its own Can't locate object method "bar" via package "Foo" exception when you try to call it.

You could say that about any sub. If package actually contains a stub, then method calls will call AUTOLOAD in that package, instead of continuing the search the @ISA chain.

And that also seems to result in a real sub.

$ perl5i -Ilib -e 'package Foo; sub bar; sub AUTOLOAD {die}; eval { Foo->bar; }; say for >Foo->mc->methods'
bar
AUTOLOAD

When you call a method, perl tries to cache the method, so it will be faster next time. To do that, it needs a real typeglob, so the shorthand method of storing -1 in the stash will not do. Perl code is not supposed to care about the difference between -1 and *typeglob_with_undefined_sub, so perl will automatically switch between them as it sees fit.

With that in mind, we might be trying to read too far into the intent of a stub and AUTOLOAD.

As I mentioned, a stub will prevent further @ISA searching

Could we rely on can instead?

We could. It would be significantly slower. (I have not benchmarked it.)

Maybe we need to back up and more tightly define the use cases of methods. I wrote it mostly for manual debugging and introspection purposes, what methods are available on this class or object? Just doing that involves a lot of symbol table code, so it's for convenience.

If it is just for debugging, does it matter so much what it returns?

Here's a thought. I'd always meant to do more with perl5i::2::CODE. With that it's possible to add methods and metadata to a CODE reference. Perhaps the answer is to change methods to return string overloaded CODE references (or if that's not possible, string overloaded objects). Then the user can ask for things like its short name (ie. bar), full name (Foo::bar), prototype, and so on to make their own determination. That would roll together the functionality of several different CPAN modules for introspecting code references.

In that case, would it return all subs? Does that not defeat the purpose of having perl5i distinguish methods and subs, as you said? (Would you have to increase the version to 3?)

I’m willing to give a stab at implementing it, as long as you guide me around the code a bit. It could not return the meta-object for the sub, or a coderef, as the sub’s own name does not always match the name under which it is installed in the symbol table. It would have to be a separate object. What should the class be called?

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

No branches or pull requests

2 participants