Discussion:
Pre-PPC discussion: lexical method calls
(too old to reply)
Paul "LeoNerd" Evans
2024-08-13 21:45:03 UTC
Permalink
We have lexical subs. They're nice for keeping namespaces clean

my sub f ( $x, $y ) { ... }

say "The value of f is ", f(123, 456);

# calls the lexical f() even though there is no `sub f` visible in
# the package

Various discussions around object system ideas have been inspired the
idea that it'd be nice to be able to do this with methods as well.
Having lexically-scoped methods that are not visible outside the
lexical scope helps keep namespaces clean - doubly useful around object
classes where you expect external callers to call methods.

Already this is achievable by storing an anonymous method into a normal
lexical variable, in the same way you could have done that in perls
prior to 5.18 with subs. But it doesn't look very neat:

class C {
my $inner = method { ... };

method outer { $self->$inner() }
}

It's also potentially problematic for a bunch of upcoming-feature
reasons to simply have an anonymous method expression sitting around in
a lexical variable like that. Really, it wants to be properly supported
first-class syntax that the language properly knows about.

What we want is some kind of ability to write `my method ...` and be
able to call it.

We did briefly think about simply allowing that as part of normal
method resolution:

class C {
my method inner { ... }

method outer { $self->inner() }
}

However, this might be considered "surprising" by many. It's no more
surprising than lexical subs already are currently; but maybe that's
surprising enough as it is?

Another thought would be to have different notation at the callsite, to
make it obvious this is a lexical lookup. One idea was the `->&NAME`
arrow notation.

class C {
my method inner { ... }

method outer { $self->&inner() }
}

I've already got quite a few PPC documents open already, plus a few
more I'm in the middle of writing, so I'm kindof loathe to write yet
another one, but what does anyone think?

Moreover - does anyone feel sufficiently strongly about this idea that
they'd actually comment and contribute to such a PPC discussion? Or
should I just go ahead and skip straight to implementing and raising a
PR for it?
--
Paul "LeoNerd" Evans

***@leonerd.org.uk
http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
Martijn Lievaart via perl5-porters
2024-08-14 05:37:29 UTC
Permalink
Post by Paul "LeoNerd" Evans
What we want is some kind of ability to write `my method ...` and be
able to call it.
Sounds good..
Post by Paul "LeoNerd" Evans
We did briefly think about simply allowing that as part of normal
class C {
my method inner { ... }
method outer { $self->inner() }
}
However, this might be considered "surprising" by many. It's no more
surprising than lexical subs already are currently; but maybe that's
surprising enough as it is?
Can you elaborate on how this is surprising?


HTH,

M4
Paul "LeoNerd" Evans
2024-08-14 11:22:43 UTC
Permalink
On Wed, 14 Aug 2024 07:37:29 +0200
Post by Martijn Lievaart via perl5-porters
Post by Paul "LeoNerd" Evans
However, this might be considered "surprising" by many. It's no more
surprising than lexical subs already are currently; but maybe that's
surprising enough as it is?
Can you elaborate on how this is surprising?
I guess it's only as surprising as lexical subs. I still find them
surprising, but in practice it doesn't come up very often. I don't
really ever make use of `my sub ...` directly. The only times that
lexical subs tend to be involved in code I write is toplevel imports
with things like `use builtin ...` so their lexical nature doesn't
really become apparent.

Whereas, most of the use-cases of lexical methods would be rather more
varied in different situations, so their differences might stand out
more.

Or they might not? Perhaps it's all fine and I'm overly panicing about
nothing...
--
Paul "LeoNerd" Evans

***@leonerd.org.uk
http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
Paul "LeoNerd" Evans
2024-08-14 11:18:56 UTC
Permalink
On Wed, 14 Aug 2024 08:54:41 +0200
my sub g;
# ...
sub g { ... } # defines lexical sub, despite no 'my'
Yeah I'm not really a fan of that one. I think if we allowed `my
method`, we'd want to ensure that if you split declaration and
definition like that, they both match (e.g. similar to the complaint
from a C compiler if you don't match `static` between a function's
declaration and definition).

But then further thinking about it, `my` always introduces a new name,
rather than changing the definition of an existing name.

class C {
my method g;

method surprise { $self->g; }

my method g { say "What does this do?" }
}

It's unclear what the author would mean by this...

However, I think because methods don't take prototypes, there's
basically no reason to pre-declare them lexical before defining them,
so maybe in practice if we just ban pre-declaration of methods most of
these problems go away?
If you write recursive lexical subs, they leak memory (which we
originally told people to do in an example in perlsub, until it was
changed five years later in 67bf5a37856bcd5).
Up until very recently, lexical subs were badly broken if defined
within a recursive (regular) sub (#18606, #21987; fixed in v5.40).
I'm not a big fan of lexical subs.
Those are certainly some unfortunate implementation bugs. Bugs that
would have been found far more quickly if more people had used them for
more things earlier. But they're not problems with the abstract idea or
design of lexical subs.
Post by Paul "LeoNerd" Evans
Already this is achievable by storing an anonymous method into a
normal lexical variable, in the same way you could have done that
class C {
my $inner = method { ... };
method outer { $self->$inner() }
}
I'd prefer this over lexical subs because it has clear semantics that
follow from the way variables work everywhere.
Sure, but as aluded to in my next paragraph, it causes problems.
Specifically, a simple anonymous CV sitting around in some scalar
somewhere is hard to find, whereas an actual named method body sitting
in the pad is in a known place where perl can find it in a variety of
situations.

Situations I'm thinking of are places like anonymous classes that want
to act as true closures:

my @objs;
foreach my $counter ( 1 .. 5 ) {
push @objs, (class {
my $inner = method { "Counter was $counter" };
method speak { say $self->$inner() }
})->new;
}
$_->speak for @objs;

That plain scalar variable is hard to find to apply the cv_clone()
action to when cloning the entire protoclass into a concrete class per
iteration of the foreach loop. It's also really surprising to change
the value of it, because it's just a plain scalar. I think it would be
less surprising if it was just a lexical sub in the scope pad.

Other situations are harder to explain as I don't have clear ideas of
the syntax you'd use to write them, but involve roles that are in some
way templatey-parametric, and have parameters passed in at application
time. These would act similar to the closures above.
Post by Paul "LeoNerd" Evans
Another thought would be to have different notation at the
callsite, to make it obvious this is a lexical lookup. One idea was
the `->&NAME` arrow notation.
class C {
my method inner { ... }
method outer { $self->&inner() }
}
At this point I'd rather have $self->$inner(). The call syntax
doesn't buy you anything ($self->&inner() and $self->$inner() are
equally ugly), but at least with the the latter you know what it's
doing.
True, at the callsite it's not much different. The main point of the
difference is outlined above: namely, that `my method ...` can live
directly in the pad where perl can find it much easier.
Also, what does $self->&inner do? The sensible thing
($self->&inner()) or the thing all other calls involving & do (such
as &foo, &{$foo}, or $foo->&* (and maybe even goto &foo if you
squint))? The latter is a footgun; the former is inconsistent with
the way & is used everywhere else.
Oh definitely the former - I wouldn't suggest it does the bizarre
Perl4-ish behaviour of implying the @_ array. But indeed as you point
out, it would be inconsistent.

I guess that suggests a sigil-less version of simply $self->inner
then?
--
Paul "LeoNerd" Evans

***@leonerd.org.uk
http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
Paul "LeoNerd" Evans
2024-09-20 19:59:18 UTC
Permalink
On Tue, 13 Aug 2024 22:45:03 +0100
Post by Paul "LeoNerd" Evans
Another thought would be to have different notation at the callsite,
to make it obvious this is a lexical lookup. One idea was the
`->&NAME` arrow notation.
class C {
my method inner { ... }
method outer { $self->&inner() }
}
I've already got quite a few PPC documents open already, plus a few
more I'm in the middle of writing, so I'm kindof loathe to write yet
another one, but what does anyone think?
Based on various discussions it seemed like using the '&' symbol here
would be better.

With that in mind it turns out to be justabout possible to write a
hacky implementation of it, which I've now done here:

https://metacpan.org/pod/Object::Pad::LexicalMethods

So now people can have a play with it and see if they like the idea of
it.
--
Paul "LeoNerd" Evans

***@leonerd.org.uk
http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
Loading...