Mailing List Archive

`meta` module experimentation
As part of PP0022, the metaprogramming API, I've uploaded a new
version of the `meta` module to CPAN:

https://metacpan.org/pod/meta

I've also started using it in a few modules, notably my various
Syntax::Operator::* modules, for implementing symbol export at `use`
time. As an example, here's a change that was made:

- no strict 'refs';
- $on ? *{"${caller}::$_"} = \&{$_}
+ $callerpkg //= meta::get_package( $caller );
+
+ $on ? $callerpkg->add_symbol( '&'.$_ => \&{$_} )

I'll gradually go around more of my modules, looking for more places
where `no strict 'refs'` currently appears and replace them with some
nicer code based on `meta`.

The entire point of experimenting with this module on CPAN is to allow
us to get a good feel for what API shape is best, so it'd be really
useful in that regard if more folks could start to make use of this and
test it out in a variety of situations. I'd love to receive more
feedback on what new bits of API need adding, or what changes to make
to things already there.

Once this becomes a bit more battle-tested and stable the module will
become a core-supplied dual-life one, but before that happens we need
more folks testing it out.

Thanks,


SEE ALSO

https://github.com/Perl/PPCs/blob/main/ppcs/ppc0022-metaprogramming.md

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: `meta` module experimentation [ In reply to ]
On 2023-12-29 19:10, Paul "LeoNerd" Evans wrote:
> [...]
> https://github.com/Perl/PPCs/blob/main/ppcs/ppc0022-metaprogramming.md
> |set_subname |$metasub->set_subname($name);# returns $metasub Sets the subname for a previously-anonymous
> subroutine, such as one generated by|sub { ... }|syntax.
> TODO: Specify what happens if you try to do this on a regular symbol
> table subroutine. We probably shouldn't allow it.
|I would expect it to create an (deep) alias. But I don't know how||(for
example)||further properties like prototype and signature are keyed, and
inherited. If any subroutine-name is merely a lookup-name, to get to the
one and only plausible subroutine-structure, that would be feasible. --
Ruud |
Re: `meta` module experimentation [ In reply to ]
On 2023-12-29 19:10, Paul "LeoNerd" Evans wrote:
> [...]
> https://github.com/Perl/PPCs/blob/main/ppcs/ppc0022-metaprogramming.md
> |set_subname |$metasub->set_subname($name);# returns $metasub Sets the
> subname for a previously-anonymous subroutine, such as one generated
> by|sub { ... }|syntax.
> TODO: Specify what happens if you try to do this on a regular symbol
> table subroutine. We probably shouldn't allow it.

I would expect it to create an (deep) alias. But I don't know how (for
example) further properties like prototype and signature are keyed, and
inherited.

If any subroutine-name is merely a lookup-name, to get to the one and
only plausible subroutine-structure, that would be feasible.

-- Ruud

(no idea why my previous email was so weirdly formatted, likely a recent
Thunderbird bug)
Re: `meta` module experimentation [ In reply to ]
Paul \"LeoNerd\" Evans writes:

> As part of PP0022, the metaprogramming API, I've uploaded a new
> version of the `meta` module to CPAN:
>
> https://metacpan.org/pod/meta

Nice! Thank you for doing this. It looks really useful, and a massive improvement on the existing ways of achieving equivalent things.

> + $callerpkg //= meta::get_package( $caller );
> +
> + $on ? $callerpkg->add_symbol( '&'.$_ => \&{$_} )

With get_package() returning an object, it's effectively a constructor — but it doesn't really look like one. Elsewhere in Perl, constructors are mostly class methods, on the class of the object you'll get back. And the ones that aren't are generally imported ‘shortcut’ functions (such as path in Path::Tiny), which don't specify a namespace when being used. Calling meta::get_package() as a function is a slightly awkward combination of the two.

Apologies for the bikeshedding, especially when you've obviously thought about this way more than I have (so please feel free to completely ignore me), but might it seem more intuitive — and also less likely to make users question the syntax to use for constructors in completely unrelated classes — if it meta::get_package($name) were instead something like:

meta::package->get($name)

with the object returned being an instance of the meta::package class?

Then the subsections ‘Methods on Metapackages’, ‘Methods on Metasymbols’, and so on, could be ‘meta::package methods’, ‘meta::symbol’ methods, etc, which would probably be clearer, because the various classes would be explicit. Currently the docs mention that different types of objects can be returned, but doesn't say what packages those are in ... which seems a little ironic for a metaprogramming feature!

Smylers
Re: `meta` module experimentation [ In reply to ]
On Sat, 30 Dec 2023 21:26:33 +0100 (CET)
"Smylers  " via perl5-porters <perl5-porters@perl.org> wrote:

> > + $callerpkg //= meta::get_package( $caller );
> > +
> > + $on ? $callerpkg->add_symbol( '&'.$_ => \&{$_} )
>
> With get_package() returning an object, it's effectively a
> constructor — but it doesn't really look like one. Elsewhere in Perl,
> constructors are mostly class methods, on the class of the object
> you'll get back. And the ones that aren't are generally imported
> ‘shortcut’ functions (such as path in Path::Tiny), which don't
> specify a namespace when being used. Calling meta::get_package() as a
> function is a slightly awkward combination of the two.
>
> Apologies for the bikeshedding, especially when you've obviously
> thought about this way more than I have (so please feel free to
> completely ignore me), but might it seem more intuitive — and also
> less likely to make users question the syntax to use for constructors
> in completely unrelated classes — if it meta::get_package($name) were
> instead something like:
>
> meta::package->get($name)
>
> with the object returned being an instance of the meta::package class?

Yes; that's a reasonable thought. It's the way that
Object::Pad::MOP::Class works, for example. It didn't feel very "core
perlish", but that's very subjective. Perhaps it would be better as a
class constructor in that form, indeed.

I could add some alternative forms in that shape and see how each feels
to use in practice.

I should also add (that I forgot to add in documentation so far) that
the whole thing is very experimental anyway, so no promises about API
stability at this time. Now's a great time to experiment with what
might work and find the best shape.

> Then the subsections ‘Methods on Metapackages’, ‘Methods on
> Metasymbols’, and so on, could be ‘meta::package methods’,
> ‘meta::symbol’ methods, etc, which would probably be clearer, because
> the various classes would be explicit. Currently the docs mention
> that different types of objects can be returned, but doesn't say what
> packages those are in ... which seems a little ironic for a
> metaprogramming feature!

Mmmyes another entirely fair point there :)

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: `meta` module experimentation [ In reply to ]
On Sun, Dec 31, 2023 at 4:01?PM Paul "LeoNerd" Evans <leonerd@leonerd.org.uk>
wrote:

> > meta::package->get($name)
> >
> > with the object returned being an instance of the meta::package class?
>
> Yes; that's a reasonable thought.
>

I would like to second the idea of having an OO interface. While I'm not a
huge fan of inheritance, I could easily see people subclassing this, or
applying roles to it, and having MyMeta->new(%args)->add_symbol(...).

Exposing the constructor might seem like a bit of an annoyance, but since
most of my metaprogramming stuff seems to be encapsulated in one place,
having a meta object to pass around seems convenient to me. See
https://metacpan.org/module/MooseX::Extended::Core/source for an example.

Best,
Ovid
Re: `meta` module experimentation [ In reply to ]
Some updates:

Latest CPAN version now has experimental warnings, and adds a few more
methods. It expands on the `get` idea to have `try_get` (that returns
undef) and some `get_or_add` for lazy creation. I found that was
necessary for making this change:

- no strict 'refs';
- push @{"${caller}::ISA"}, __PACKAGE__;
+ my $callermeta = meta::package->get( $caller );
+ push @{ $callermeta->get_or_add_symbol( '@ISA' )->reference },

I've also raised a PR to edit the PPC0022 document to bring it a little
more in line with what the current state of the implementation actually
is:

https://github.com/Perl/PPCs/pull/46

I don't really have a good feel for how quickly we should keep editing
the PPC document to track the implementation, so will take further
guidance from folks if anyone has any comment to make.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: `meta` module experimentation [ In reply to ]
On 5 Jan 2024, at 22:49, Paul LeoNerd Evans <leonerd@leonerd.org.uk> wrote:
> Some updates:
>
> Latest CPAN version now has experimental warnings, and adds a few more
> methods. It expands on the `get` idea to have `try_get` (that returns
> undef) and some `get_or_add` for lazy creation. I found that was
> necessary for making this change:
>
> - no strict 'refs';
> - push @{"${caller}::ISA"}, __PACKAGE__;
> + my $callermeta = meta::package->get( $caller );
> + push @{ $callermeta->get_or_add_symbol( '@ISA' )->reference },

This is purely bikeshedding, but “get or add” rubbed me up the wrong way at first; like the method is both an accessor and a constructor?

(SQL goes the other way and lets you say “CREATE TABLE IF NOT EXISTS”.)

I wonder if ensure_symbol would be less weird?

Sam
--
Website: http://www.illuminated.co.uk/blog/
Re: `meta` module experimentation [ In reply to ]
On Sat, 6 Jan 2024 00:34:37 +0000
Sam Kington <sam@illuminated.co.uk> wrote:

> This is purely bikeshedding, but “get or add” rubbed me up the wrong
> way at first; like the method is both an accessor and a constructor?
>
> (SQL goes the other way and lets you say “CREATE TABLE IF NOT
> EXISTS”.)
>
> I wonder if ensure_symbol would be less weird?

Yeah, perhaps. I don't know. I spent a long time thinking on verbs and
got #perl/Libera.chat involved as well. We came up with quite a lot of
verbs but none of them really felt like it conveyed the "create if not
exists yet" feel.

Though also I was trying to view it from a lens of "how would new users
react to this word?". The name `get_or_create` is a bit long and clumsy
but it's really clear what it does when you first encounter it. Maybe
something like `ensure` is a bit more subtle and needs reading
documentation before you really understand what it does.

Yes it is a bike-shed but it's one I spent a long time thinking about,
and I'm glad to see others are still thinking and discussing it too. So
I'm happy to continue to think it over.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: `meta` module experimentation [ In reply to ]
> On 6 Jan 2024, at 23:02, Paul "LeoNerd" Evans <leonerd@leonerd.org.uk> wrote:
>
> ?On Sat, 6 Jan 2024 00:34:37 +0000
> Sam Kington <sam@illuminated.co.uk> wrote:
>
>> This is purely bikeshedding, but “get or add” rubbed me up the wrong
>> way at first; like the method is both an accessor and a constructor?
>>
>> (SQL goes the other way and lets you say “CREATE TABLE IF NOT
>> EXISTS”.)
>>
>> I wonder if ensure_symbol would be less weird?
>
[…]
> Yes it is a bike-shed but it's one I spent a long time thinking about,
> and I'm glad to see others are still thinking and discussing it too. So
> I'm happy to continue to think it over.
>
> --
> Paul "LeoNerd" Evans
>
> leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
> http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/

Likewise, get_or_add sits uneasily for me. Partly language pedantry, as it’s behaviour is more like get_or_add_and_get.

That aside though, I wonder if this couldn’t be collapsed into get_symbol (etc), much as get_package /add_package have changed since the PPC? If $valueref is provided, get_or_add behavior, if no $valueref and it doesn’t exist, throw the exception. Allows the ensure_symbol behavior, optionally. Naively, it seems this would capture the likely intent(s) of the programmer, but I’m sure I’m missing something…

James
Re: `meta` module experimentation [ In reply to ]
Op 06-01-2024 om 23:45 schreef James Watson:
> Likewise, get_or_add sits uneasily for me. Partly language pedantry, as it’s behaviour is more like get_or_add_and_get.
>
> That aside though, I wonder if this couldn’t be collapsed into get_symbol (etc), much as get_package /add_package have changed since the PPC? If $valueref is provided, get_or_add behavior, if no $valueref and it doesn’t exist, throw the exception. Allows the ensure_symbol behavior, optionally. Naively, it seems this would capture the likely intent(s) of the programmer, but I’m sure I’m missing something…


At first glance looks like a good solution, but gets very confusing if
you want to use undef as the default value when adding the symbol. Not
sure if that is a realistic scenario though, and also not sure if the
drawback is bigger than the advantages, because it does feel natural.


HTH,

M4
Re: `meta` module experimentation [ In reply to ]
On 1/5/24 19:34, Sam Kington wrote:
>> +   push @{ $callermeta->get_or_add_symbol( '@ISA' )->reference },
>
> This is purely bikeshedding, but “get or add” rubbed me up the wrong
> way at first
> ...
> I wonder if ensure_symbol would be less weird?

How about $callermeta->symbol('@ISA', AUTOCREATE)->... where AUTOCREATE
is the constant 1.  Other flags could be added later.  Absence of flags
means it either returns undef or dies if the symbol isn't defined.

-Mike