Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

goto &method and skipping call frame

by LanX (Saint)
on Mar 04, 2021 at 20:12 UTC ( [id://11129129]=perlquestion: print w/replies, xml ) Need Help??

LanX has asked for the wisdom of the Perl Monks concerning the following question:

Hi

goto &NAME is a way to call a sub NAME() while autoloading and transparently skipping the actual frame for sub AUTOLOAD() on the call stack.

Hence caller wouldn't show AUTOLOAD but the line which triggered it.

That's also of practical importance when using carp() et al from Carp , because you don't wanna get the error shown inside the AUTOLOAD's code.

But what if I want to delegate to a method from an autoloaded sub?

My best guess is to call it as a normal sub and to prepend the object to @_

sub AUTOLOAD { #warn pp "$AUTOLOAD $OBJ=>",\@_; (my $meth = $AUTOLOAD) =~ s/^.*://; if (my $c_ref = $OBJ->can($meth)) { unshift @_,$OBJ; goto &$c_ref; } }

And - to my big surprise - this is even respecting inheritance, i.e. if the method belongs to a super-class of OBJ, it's properly delegated.

Questions:

  • Any cleaner way to do this?
  • Any side effects I forgot?

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

PS: Hey Mike can't wait to hear about your huge "expertise" from JAVA, bread-trucks and millions of lines of PHP ...

UPDATE

2 monks msged me Where does $OBJ come from?

In this simplified example you can consider it a global, like

our $OBJ = SomeClass->new();

The real use case is a more complicated implementation of a with construct (like in with), where $OBJ is a closure var and AUTOLOAD is localized to a blocks context.

Replies are listed 'Best First'.
Re: goto &method and skipping call frame
by jcb (Parson) on Mar 05, 2021 at 04:02 UTC

    Recalling the other thread that seems to have inspired this, I expect that you will encounter a few problems:

    • Each with body will need its own auto-generated package for each class of object you want as "context": ref $OBJ should be sufficient to choose a context package.
    • The Perl prototype functionality that allows a keyword sub to be omitted only works for the first argument, if I remember correctly, so this may force you to change the syntax a bit or use a source filter.
    • The closure you get for the with body has already been compiled in its surrounding package, so you will need XS magic to crack it open and relocate it into the auto-generated package for the context. It may be easiest to simply move the closure into ref $OBJ and let Perl handle the rest, but watch for with being used in the scope of a use vars — you will need to translate references to globals that came from use vars. Globals declared using our are actually lexical aliases, so they should be carried with the closure when you move it to another package.

    I have only a few readings of perlguts for how any of this is actually implemented, so I could be wrong here, but with appears fairly difficult to "bolt-on" to Perl. I expect a JS-like with to need to be added to the core language to work, or to hook sufficiently far into the interpreter that it may as well have been added to the core language.

      Hi

      thanks for your thoughts.

      Regarding with - I just mentioned it for motivation and am still looking into the options.

      I'll post a RFC soon. :)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

Re: goto &method and skipping call frame
by shmem (Chancellor) on Mar 04, 2021 at 22:15 UTC
    The real use case is a more complicated implementation of a with construct, where $OBJ is a closure var and AUTOLOAD is localized to the block.

    Then show this more complicated implementation. What do you mean by "AUTOLOAD is localized to the block"? Does that mean you have a local *AUTOLOAD; in place? Or is it local $AUTOLOAD?

    This reminds me of one piece of programming lore -

    1. writing code is hard
    2. debugging code is harder
    3. if you write your programs as clever as you are, you are, by definition, too dumb to debug them

    As for your questions: I'd say no, and no (afaik). Prove me wrong with tests.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      > Then show this more complicated implementation.

      what's the problem with the question?

      I linked the relevant docs.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        One place where I've seen this technique is a ORM package on CPAN - Class::Tables - which auto-generates classes from table names and makes colum names into their methods using AUTOLOAD:

        sub AUTOLOAD { my $self = shift; (my $func = $Class::Tables::AUTOLOAD) =~ s/.*:://; croak qq{Can't locate object method "$func" via package "$self"} unless ref $self and UNIVERSAL::isa( $self, "Class::Tables" ); unshift @_, $self, $func; goto &field; }

        The field() sub translates its arguments to the appropriate SQL call against the database. I've used that package very much, and I have seen no adverse side effects. And no, I'm not aware of a cleaner way to do this.

        I'm still puzzled by the meaning of "AUTOLOAD is localized to a blocks context" part of your question. Does that mean having different lookup-results (depending on scope) for the last-resort AUTOLOAD sub?

        Sorry if I'm just being too dumb or having the wrong kind of humour. ;)

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        what's the problem with the question I linked the relevant docs.

        No problem with your question, but probably with my answer. Sorry about that.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: goto &method and skipping call frame (SSCCE)
by LanX (Saint) on Mar 05, 2021 at 14:53 UTC
    Here an SSCCE with tests.

    It's focusing on the matter of goto &METHOD and avoiding the complication of discussing autoload and with

    It's implementing a "proxy" class which allows calling methods on other objects without leaving a trace in caller or error messages.

    see Proxy->call for code in question.

    • Any better way to achieve this?
    • Any known problems?

    C:/Strawberry/perl/bin\perl.exe -w d:/tmp/pm/proxy_goto_SSCCE.pl ok 1 - TargetClass->meth1: Proxy->call skipped in caller ok 2 - TargetClass->meth2: Proxy->call skipped in caller ok 3 - TargetSuper->meth3: Proxy->call skipped in caller 1..3

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    update

    cosmetic change, $level instead of reusing $target

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11129129]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (10)
As of 2024-04-18 09:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found