FAQ

[P5P] Proposal: "$->" for implicit invocant

Chia-liang Kao
Jan 16, 2011 at 7:06 am
Hi,

I just released the invoker module on cpan, and i'd like to
propose the syntax to be included in future perls.

why: with the blooming modules providing the "method" keyword, we
no longer need to have "my $self = shift" everywhere. however
this makes "$self" now the most repeated code.

Here's the idea:

"use feature 'invocant'" enables the $-> operator. There are two
variants:

- "use invocant '$self" looks for the specific lexical variable
named $self in the current context, and bails out in compile
time if not found.

- "use invocant 'auto'" looks for the first real pad entry in the
nearest scope as the default invocant.

I am not sure which one suites as better default behaviour. the
latter seems less intrusive on insisiting variable names by can
be a bit confusing.

Conflicts:

$-> can be parsed as $- > ($- greater than .. ), so we need to
deprecate the use of $- (and hopefully the whole format system by
requiring use of formats to add additional "use format" line.)
the feature can install a warning when accessing $- before such
deprecation.

What do people think?

Cheers,
CLK
reply

Search Discussions

28 responses

  • H.Merijn Brand at Jan 16, 2011 at 8:12 am

    On Sun, 16 Jan 2011 15:06:03 +0800, Chia-liang Kao wrote:

    Hi,

    I just released the invoker module on cpan, and i'd like to
    propose the syntax to be included in future perls.

    why: with the blooming modules providing the "method" keyword, we
    no longer need to have "my $self = shift" everywhere. however
    this makes "$self" now the most repeated code.

    Here's the idea:

    "use feature 'invocant'" enables the $-> operator. There are two
    variants:

    - "use invocant '$self" looks for the specific lexical variable
    named $self in the current context, and bails out in compile
    time if not found.

    - "use invocant 'auto'" looks for the first real pad entry in the
    nearest scope as the default invocant.

    I am not sure which one suites as better default behaviour. the
    latter seems less intrusive on insisiting variable names by can
    be a bit confusing.

    Conflicts:

    $-> can be parsed as $- > ($- greater than .. ), so we need to
    deprecate the use of $- (and hopefully the whole format system by
    requiring use of formats to add additional "use format" line.)
    This alone would cause me to try to issue a veto. Perl5 has format.
    Period. And I use it. A lot.
    the feature can install a warning when accessing $- before such
    deprecation.

    What do people think?

    Cheers,
    CLK

    --
    H.Merijn Brand http://tux.nl Perl Monger http://amsterdam.pm.org/
    using 5.00307 through 5.12 and porting perl5.13.x on HP-UX 10.20, 11.00,
    11.11, 11.23 and 11.31, OpenSuSE 10.1, 11.0 .. 11.3 and AIX 5.2 and 5.3.
    http://mirrors.develooper.com/hpux/ http://www.test-smoke.org/
    http://qa.perl.org http://www.goldmark.org/jeff/stupid-disclaimers/
  • Zefram at Jan 16, 2011 at 11:52 pm

    Chia-liang Kao wrote:
    "use feature 'invocant'" enables the $-> operator.
    Already effectively available. It's spelled "$_->", as in

    given(shift) {
    $_->foo;
    $_->bar;
    }

    -zefram
  • David Golden at Jan 17, 2011 at 12:12 am

    On Sun, Jan 16, 2011 at 2:06 AM, Chia-liang Kao wrote:
    "use feature 'invocant'" enables the $-> operator.  There are two
    variants:
    If we're really pondering this sort of thing, why not think more
    broadly and finally get around to dealing with method/object syntax?
    (Like some of the syntax manglers on CPAN do.)

    Hypothetically:

    use feature 'method';

    method foo {
    self->wibble($_) for @_;
    }

    I.e. Given a "method" keyword, set up the invocant in some way and
    leave it out of @_. People can bikeshed the most efficient way to set
    up the invocant -- in my example I have a bareword, but it could be
    "$self" or "$*" (available now without a deprecation cycle) or
    whatever else people dream up.

    -- David
  • Johan Vromans at Jan 17, 2011 at 8:04 am

    David Golden writes:

    If we're really pondering this sort of thing, why not think more
    broadly and finally get around to dealing with method/object syntax?
    +1

    -- Johan
  • Chromatic at Jan 20, 2011 at 6:27 pm

    On Sunday 16 January 2011 at 16:11, David Golden wrote:

    If we're really pondering this sort of thing, why not think more
    broadly and finally get around to dealing with method/object syntax?
    (Like some of the syntax manglers on CPAN do.)

    Hypothetically:

    use feature 'method';

    method foo {
    self->wibble($_) for @_;
    }
    This proof of concept patch enables that, with $self as the invocant. It
    could use more robust testing, but all existing tests pass.

    The trick of using lex_stuff_pvs() seems grotty, but it's far, far easier than
    building a new optree with the appropriate lexical bindings within the method
    production in perly.y.

    The patch needs make regen_perly after applying.

    -- c
  • Zefram at Jan 20, 2011 at 6:32 pm

    chromatic wrote:
    This proof of concept patch enables that, with $self as the invocant. It
    could use more robust testing, but all existing tests pass.
    You should prototype this as a CPAN module, using the keyword hook.
    The trick of using lex_stuff_pvs() seems grotty, but it's far, far easier than
    building a new optree with the appropriate lexical bindings within the method
    production in perly.y.
    As something to go in the core, I do not approve of this shortcut.
    You should definitely build the optree rather than stuff source.

    It also seems very unwise for the core to take the keyword "method" at
    this stage. We have several CPAN modules supplying "method" keywords
    with various semantics, it's an unresolved area.

    -zefram
  • David E. Wheeler at Jan 20, 2011 at 6:50 pm

    On Jan 20, 2011, at 10:32 AM, Zefram wrote:

    It also seems very unwise for the core to take the keyword "method" at
    this stage. We have several CPAN modules supplying "method" keywords
    with various semantics, it's an unresolved area.
    Tie it to `use 5.14.0;` or, more likely, `use 5.16.0;`?

    Oh, and the class keyword would be handy to have too, if we're gonna have `method`.

    Best,

    David
  • David Golden at Jan 20, 2011 at 7:00 pm

    On Thu, Jan 20, 2011 at 1:49 PM, David E. Wheeler wrote:
    Oh, and the class keyword would be handy to have too, if we're gonna have `method`.
    It's called "package".

    package Foo 1.23 {
    ...
    }

    -- David
  • Chromatic at Jan 20, 2011 at 7:29 pm

    On Thursday 20 January 2011 at 10:32, Zefram wrote:

    You should prototype this as a CPAN module, using the keyword hook.
    How do you use keyword hooks to add 'method' to the imports of feature.pm?
    It also seems very unwise for the core to take the keyword "method" at
    this stage. We have several CPAN modules supplying "method" keywords
    with various semantics, it's an unresolved area.
    To my knowledge, none of them import 'method' from feature.pm.
    As something to go in the core, I do not approve of this shortcut.
    You should definitely build the optree rather than stuff source.
    That means:

    * grabbing the optree *already generated* for the body of the sub
    * creating a new lexical $self binding in that optree
    * rummaging through every variable access in that entire optree to find $self,
    if it exists
    * rebinding those package globals to the lexical
    * building up the appropriate optree for 'my $self = shift';
    * splicing the new optree to the existing optree

    I've done all of this before with B::Generate activated by a new :method
    attribute on existing subs. It's fragile and unpleasant enough in Perl, and
    it's a lot of special-purpose code to stuff into perly.y.

    The worst part is doing this all in a way that doesn't trip the strict pragma.
    I don't know how to do that.

    Alternately, you could take the approach that doesn't add at least a few
    hundred lines of new code to the parser for a special case. You could use as
    much existing code as possible (code that knows how to build an optree, code
    that knows how to create lexicals, code that knows how to decide $self is
    lexical, et cetera).

    -- c
  • David Golden at Jan 20, 2011 at 8:15 pm

    On Thu, Jan 20, 2011 at 2:28 PM, chromatic wrote:
    * grabbing the optree *already generated* for the body of the sub
    * creating a new lexical $self binding in that optree
    * rummaging through every variable access in that entire optree to find $self,
    if it exists
    This is why I was pondering a "self" keyword. If it could access the
    right reference at runtime you wouldn't need to worry about the
    existing bindings.

    Imagine:

    * method { ... } somehow marks the subroutine body as a method
    * dispatch to such a marked method doesn't put the invocant in @_
    but puts it "somewhere else" (big hand-waving here)
    * keyword self retrieves invocant from wherever it got put

    I leave it to people who know the guts in detail to explain why that
    is doomed to fail. :-)

    -- David
  • Steffen Mueller at Jan 20, 2011 at 9:43 pm

    On 01/20/2011 09:14 PM, David Golden wrote:
    On Thu, Jan 20, 2011 at 2:28 PM, chromaticwrote:
    * grabbing the optree *already generated* for the body of the sub
    * creating a new lexical $self binding in that optree
    * rummaging through every variable access in that entire optree to find $self,
    if it exists
    This is why I was pondering a "self" keyword. If it could access the
    right reference at runtime you wouldn't need to worry about the
    existing bindings.

    Imagine:

    * method { ... } somehow marks the subroutine body as a method
    * dispatch to such a marked method doesn't put the invocant in @_
    but puts it "somewhere else" (big hand-waving here)
    * keyword self retrieves invocant from wherever it got put
    "wherever" would likely still be the stack, except @_ is populated only
    with the elements after the invocant.

    The little understanding I have of these matters suggests that arguments
    will be passed via the stack no matter what and @_ is then "aliased"
    (SV* copy? Too lazy to check.) to the elements since the last pushmark.
    If there was a flag to start only after the first element and make the
    sp accessible via "self" by some mechanism, that might just do it.
    I leave it to people who know the guts in detail to explain why that
    is doomed to fail. :-)
    Yes, it is now up to them :)

    Cheers,
    Steffen
  • Reini Urban at Jan 20, 2011 at 9:07 pm

    2011/1/20 chromatic <chromatic@wgz.org>:
    On Thursday 20 January 2011 at 10:32, Zefram  wrote:

    You should prototype this as a CPAN module, using the keyword hook.
    How do you use keyword hooks to add 'method' to the imports of feature.pm?
    It also seems very unwise for the core to take the keyword "method" at
    this stage.  We have several CPAN modules supplying "method" keywords
    with various semantics, it's an unresolved area.
    To my knowledge, none of them import 'method' from feature.pm.
    As something to go in the core, I do not approve of this shortcut.
    You should definitely build the optree rather than stuff source.
    That means:

    * grabbing the optree *already generated* for the body of the sub
    * creating a new lexical $self binding in that optree
    * rummaging through every variable access in that entire optree to find $self,
    if it exists
    * rebinding those package globals to the lexical
    * building up the appropriate optree for 'my $self = shift';
    * splicing the new optree to the existing optree

    I've done all of this before with B::Generate activated by a new :method
    attribute on existing subs.  It's fragile and unpleasant enough in Perl, and
    it's a lot of special-purpose code to stuff into perly.y.

    The worst part is doing this all in a way that doesn't trip the strict pragma.
    I don't know how to do that.

    Alternately, you could take the approach that doesn't add at least a few
    hundred lines of new code to the parser for a special case.  You could use as
    much existing code as possible (code that knows how to build an optree, code
    that knows how to create lexicals, code that knows how to decide $self is
    lexical, et cetera).
    I'm completely with chromatic here.

    Maybe Zefram could help hooking into the lexer to make that patch work
    as module,
    but currently it's not possible.
    And suggesting the optree manipulation is not stable and also not clever.
    It would be good to have better optree manipulation methods, but they
    do not exist yet.

    Stuffing the core source is definitely easier, and for this case
    a new self or this keyword is definitely something we need in core
    sooner or later. We already have the modules. They have no impact.
    core must lead.
    --
    Reini
  • Eric Brine at Jan 20, 2011 at 11:43 pm

    On Thu, Jan 20, 2011 at 2:28 PM, chromatic wrote:

    On Thursday 20 January 2011 at 10:32, Zefram wrote:

    It also seems very unwise for the core to take the keyword "method" at
    this stage. We have several CPAN modules supplying "method" keywords
    with various semantics, it's an unresolved area.
    To my knowledge, none of them import 'method' from feature.pm.
    If you can write the following to define a class, no problem.

    use 5.016;
    use Something::Which::Provides::Method;

    If you have to write the following to define a class using another module,
    maybe "method" is not the best choice of keyword.

    use 5.016;
    no feature 'method';
    use Something::Which::Provides::Method;

    As something to go in the core, I do not approve of this shortcut.
    You should definitely build the optree rather than stuff source.
    That means:

    * grabbing the optree *already generated* for the body of the sub
    * ...
    >

    Why can't the parser handle it when generating the optree in the first
    place? The parser knows that the block will be a method body before the
    block is parsed.

    - Eric
  • Zefram at Jan 21, 2011 at 3:05 am

    chromatic wrote:
    How do you use keyword hooks to add 'method' to the imports of feature.pm?
    You don't. But there's no reason for your particular version of "method"
    to be controlled by feature.pm.
    * grabbing the optree *already generated* for the body of the sub
    No. You add the pad entry *before* parsing the body. It's not as
    difficult as you make out.
    You could use as
    much existing code as possible (code that knows how to build an optree, code
    that knows how to create lexicals, code that knows how to decide $self is
    lexical, et cetera).
    The code that you're referring to there doesn't just generate ops and pad
    entries, it also parses general Perl code, in which (for example) "shift"
    could mean all sorts of things. Using lex_stuff, your implementation
    is liable to be broken by local redefinition of a keyword that doesn't
    appear in the user's source. That's OK for a prototype, but not at all
    OK for a serious language feature.

    -zefram
  • Chromatic at Jan 31, 2011 at 11:59 pm

    On Thursday 20 January 2011 at 11:28, chromatic wrote:

    The worst part is doing this all in a way that doesn't trip the strict
    pragma. I don't know how to do that.
    Okay, all of the explanations for how to do this are severely undocumented,
    but this swatch of optree building seems to do the trick.

    -- c
  • Zefram at Feb 2, 2011 at 10:10 pm

    chromatic wrote:
    but this swatch of optree building seems to do the trick.
    Reasonably sane implementation. Though I strongly suspect you could
    replace quite a bit of your added code with more reuse of existing code.

    I remain opposed to actually adding this to core. I don't see a
    justification for favouring this particular set of semantics for the
    "method" keyword over any of the other proposals; there's certainly
    no consensus yet about which version of it from CPAN is preferred.
    And of course it doesn't need to be in core to work.

    -zefram
  • Chromatic at Feb 2, 2011 at 10:29 pm

    On Wednesday 02 February 2011 at 14:10, Zefram wrote:

    Though I strongly suspect you could replace quite a bit of your added code
    with more reuse of existing code.
    I'm curious to see how. My perusal of the documented interfaces yielded little
    insight.

    -- c
  • David E. Wheeler at Feb 2, 2011 at 11:15 pm

    On Feb 2, 2011, at 2:10 PM, Zefram wrote:

    chromatic wrote:
    but this swatch of optree building seems to do the trick.
    Reasonably sane implementation. Though I strongly suspect you could
    replace quite a bit of your added code with more reuse of existing code.

    I remain opposed to actually adding this to core. I don't see a
    justification for favouring this particular set of semantics for the
    "method" keyword over any of the other proposals; there's certainly
    no consensus yet about which version of it from CPAN is preferred.
    And of course it doesn't need to be in core to work.
    Do you have a favorite, Zefram?

    Best,

    David
  • Zefram at Feb 2, 2011 at 11:23 pm

    David E. Wheeler wrote:
    Do you have a favorite, Zefram?
    Not of the currently-available ones, and I don't think we've yet got the
    facilities to design one that will stand the test of time. I want to
    see a proper signature system implemented, and then a round of designs
    for "method" built around that. *Then* we'll be in a position to start
    talking about blessing one.

    -zefram
  • Matt Sergeant at Feb 3, 2011 at 1:13 am

    Zefram wrote:
    Not of the currently-available ones, and I don't think we've yet got the
    facilities to design one that will stand the test of time. I want to
    see a proper signature system implemented, and then a round of designs
    for "method" built around that.*Then* we'll be in a position to start
    talking about blessing one.
    Is there any reason method signatures (or attributes) wouldn't work on
    top of this implementation?
  • Chromatic at Feb 3, 2011 at 1:20 am

    On Wednesday 02 February 2011 at 17:12, Matt Sergeant wrote:

    Is there any reason method signatures (or attributes) wouldn't work on
    top of this implementation?
    Attributes work, but the tokenizer deliberately rejects prototype syntax after
    a method keyword (given the uselessness of prototypes for methods). This
    implementation is certainly compatible with a general signature system added
    for both methods and subs.

    -- c
  • David Golden at Feb 3, 2011 at 7:44 am

    On Wed, Feb 2, 2011 at 6:23 PM, Zefram wrote:
    Not of the currently-available ones, and I don't think we've yet got the
    facilities to design one that will stand the test of time.  I want to
    see a proper signature system implemented, and then a round of designs
    for "method" built around that.  *Then* we'll be in a position to start
    talking about blessing one.
    FWIW, I would be happy to see 'method' added without signatures. Or,
    put differently, I'd hate to see 'method' not happen because we're
    waiting for an officially sanctioned implementation of signatures.

    Since I'd want signatures for regular (non-method) subroutines, too,
    I'd prefer to see the two concepts separated so I can have my cake and
    eat it while waiting for the next cake to arrive.

    -- David
  • David E. Wheeler at Feb 3, 2011 at 4:50 pm

    On Feb 2, 2011, at 11:44 PM, David Golden wrote:

    FWIW, I would be happy to see 'method' added without signatures. Or,
    put differently, I'd hate to see 'method' not happen because we're
    waiting for an officially sanctioned implementation of signatures.

    Since I'd want signatures for regular (non-method) subroutines, too,
    I'd prefer to see the two concepts separated so I can have my cake and
    eat it while waiting for the next cake to arrive.
    This seems entirely reasonable to me. I wouldn't mind seen a design spec for signatures, too, but that needn't hold up adding the method keyword any more than it would hold up the sub keyword. N'est pas?

    Best,

    David
  • Sam Vilain at Feb 3, 2011 at 1:54 am

    On 03/02/11 11:10, Zefram wrote:
    chromatic wrote:
    but this swatch of optree building seems to do the trick.
    Reasonably sane implementation. Though I strongly suspect you could
    replace quite a bit of your added code with more reuse of existing code.

    I remain opposed to actually adding this to core. I don't see a
    justification for favouring this particular set of semantics for the
    "method" keyword over any of the other proposals; there's certainly
    no consensus yet about which version of it from CPAN is preferred.
    And of course it doesn't need to be in core to work.
    MooseX::Method::Signatures suffers from huge performance problems,
    precisely because it is *not* in core - it has to use PPI to parse the
    signatures. That sucks very very much. It also has to try and apply
    those signatures using very hairy code. There is absolutely zero way
    that these type constraints can be proved at compile time even when you
    declare variables' types so you pay a huge runtime penalty.

    A project I worked on had to back out some very elegant (IMHO) use of
    MXMS because it was simply too slow and had a huge number of dependencies.

    Adding type constraints is supposed to help the computer execute the
    code faster, not slower. This needs to be on Perl's long-term roadmap IMHO.

    I think that we already have a great "preferred" approach for method
    signatures. All of the modules on CPAN that I have looked at simply
    choose a subset of MXMS as a compromise position to be faster.

    If declared well enough in advance, "use 5.014" implies "use feature
    'method'" is fair game IMHO. So long as there is a new API to access
    the parsed signature (yay, finally) and/or influence parsing (yuck) then
    the modules can adapt appropriately for the way forward.

    Sam
  • Reverend Chip at Feb 3, 2011 at 6:22 am

    On 2/2/2011 5:54 PM, Sam Vilain wrote:
    MooseX::Method::Signatures suffers from huge performance problems,
    precisely because it is *not* in core - it has to use PPI to parse the
    signatures. That sucks very very much. It also has to try and apply
    those signatures using very hairy code. There is absolutely zero way
    that these type constraints can be proved at compile time even when you
    declare variables' types so you pay a huge runtime penalty.
    Indeed, these latter problems are why I like Method::Signatures (which
    amounts to 'just' syntactic sugar), but not its MooseX sibling.
  • Zefram at Feb 3, 2011 at 11:04 am

    Sam Vilain wrote:
    MooseX::Method::Signatures suffers from huge performance problems,
    precisely because it is *not* in core - it has to use PPI to parse the
    signatures.
    That's going to get a lot better with the new parser callback interfaces
    in 5.14. No more PPI, you can call into the real parser.
    There is absolutely zero way
    that these type constraints can be proved at compile time even when you
    declare variables' types so you pay a huge runtime penalty.
    That wouldn't change if it were in the core.

    -zefram
  • Sam Vilain at Feb 4, 2011 at 1:30 am

    On 04/02/11 00:04, Zefram wrote:
    There is absolutely zero way
    that these type constraints can be proved at compile time even when you
    declare variables' types so you pay a huge runtime penalty.
    That wouldn't change if it were in the core.
    Not instantly, no - but it would be nice to be able to move towards a
    world where Perl is actually capable of skipping some run-time type
    checks because it already knows that they can't be violated. I'm not
    saying this is going to be easy!

    Sam
  • Chris Prather at Jan 20, 2011 at 9:16 pm

    On Thu, Jan 20, 2011 at 1:32 PM, Zefram wrote:
    You should prototype this as a CPAN module, using the keyword hook.
    Conceptually this is is a subset of MooseX::Method::Signatures[1],
    Method::Signatures::Simple[2] Method::Signatures[3], Perl6::Subs[4],
    as well as similar in principle to selfvars[5], self[6], and
    Object::LocalVars[7].

    What exactly are you looking for from a prototype that isn't provided
    in one of those seven (7!) modules?

    -Chris

    Note: I generated this list with a quick search for "self" and
    "method" on CPAN. Two of these modules I knew existed because various
    members of the Moose community use them in production environments
    (specifically MooseX::Method::Signatures and
    Method::Signatures::Simple). There may be other modules which
    replicate this behavior as well, I gave up when I found the two I knew
    about ... and five more.

    [1]: http://search.cpan.org/dist/MooseX-Method-Signatures
    [2]: http://search.cpan.org/dist/Method-Signatures-Simple
    [3]: http://search.cpan.org/dist/Method-Signatures
    [4]: http://search.cpan.org/dist/Perl6-Subs
    [5]: http://search.cpan.org/dist/selfvars
    [6]: http://search.cpan.org/dist/self
    [7]: http://search.cpan.org/dist/Object-LocalVars

Related Discussions