Mailing List Archive

RFC: Amores. Introducing a `module` keyword
Author:  Curtis "Ovid" Poe <curtis.poe@gmail.com>
Sponsor: Paul "LeoNerd" Evans
ID:
Status:  Proposal
Title:   "Amores", the procedural sister to "Corinna"
Note: Paul asked that I submit this RFC, but he didn't specifically say he would be the sponsor. I'm just hoping :)
Abstract
Add a module keyword with basic, modern features to support common Perl use cases.
Similar to Corinna ...
    class My::Class :version(42) {
        ...
    }
... we have Amores, the procedural version, using a similarly structured KIM syntax (keyword, identifier, modifier: https://ovid.github.io/articles/language-design-consistency.html):
    use feature 'module';
    module My::Module :version(42) {
        # these subs are examples only. Their behavior isn't         # part of the proposal, though `:export` is.        sub my_sub :export          ($arg1, $args2) { ... }
        sub trim   :export(strings) ($string)       { ... }
        sub ltrim  :export(strings) ($string)       { ... }
        sub rtrim  :export(strings) ($string)       { ... }
        sub inc    :export(numbers) ($num)          { ... }
        sub dec    :export(numbers) ($num)          { ... }
        sub munge                   ($thing)        { ... }
    }

    use My::Module qw(ltrim my_sub);
    use My::Module ':strings';
    use My::Module 'munge';     # fatal, No :export modifier


Motivation
To bring more consistency and better defaults to Perl, but in a safe, lexical scope that offers a strong hint to the Perl developer that this is not your grandfather's Perl.
Rationale
Sometimes we have a bunch of things we'd like as defaults in Perl, but it's not always clear that we can enable them. Even something as simple as writing use v5.36.0 can break legacy code unless we use a block to limit its scope (I've had quite a few clients in the past couple of years who've had Perl as fragile as Kanye West's ego).
The idea behind Amores is to provide a convenient block-like structure with a syntax that mirrors Corinna, for a modern, consistent "feel" to the language. It's also designed to simplify exporting.
Syntax
We add only one keyword: module. Two modifiers (attributes) are added, :version and :export (:version also exists in Corinna and could be generally applicable outside the language).
Keyword: module
This is only enabled with use feature 'module';
The structure of this is:
    module MODULE_NAME OPTIONAL_VERSION POSTFIXBLOCK

At the end of the block, it yields a 1 whether you use or require it, eliminating the need for the trailing 1 (see also:https://github.com/Perl/perl5/issues/17921)

Example:
    module My::Module {
        ...
    }
    # or with a version    module My::Module :version(42) {
        ...
    }

The latter example is equivalent to:
    package My::Module {
        our $VERSION = 42;
        use strict;
        use warnings;        use feature 'signatures';        no feature 'indirect';
        no feature 'multidimensional';
        no feature 'bareword_filehandles';
        ...
    }

The feature list is deliberately kept small and sane to minimize danger. use utf8 was removed from the above list after P5P feedback. This discussion was referenced in that conversation: https://www.nntp.perl.org/group/perl.perl5.porters/2021/08/msg261164.html.
In other words, lots of useful boilerplate goes away.
Happy to discuss adding other features if necessary/useful.
Modifier: :version(...)
Optionally declared after the module name (and only after the module name to make it extremely predictable). Any valid version number may be specified.
Modifier: :export
This attribute controls exporting of functions from a module. It does not use the import mechanism, though if an import  sub is found, it will still be called in the normal manner. It just won't be needed for importing.
    module My::Module :version(42) {
        # these subs are examples only. Their behavior isn't part of the
        # proposal, though `:export` is.
        sub my_sub :export          ($arg1, $args2) { ... }
        sub trim   :export(strings) ($string)       { ... }
        sub ltrim  :export(strings) ($string)       { ... }
        sub rtrim  :export(strings) ($string)       { ... }
        sub inc    :export(numbers) ($num)          { ... }
        sub dec    :export(numbers) ($num)          { ... }
        sub munge                   ($thing)        { ... }
    }

This would mostly follow the syntax of the Perl6::Export::Attrs (https://metacpan.org/pod/Perl6::Export::Attrs) module, but with the following differences:
- :export is lower case
- User-specified export groups do not allow a colon (:export(strings, munging))
- Built-in export behavior requires a colon prefix (:export(:MANDATORY))
Naturally, any subroutines without an :export tag are not available for export.
Importing any group requires the colon:
    use Some::Module ':strings';
Possibly we may require user-defined groups to not be all upper-case.
Backwards Compatibility
Currently, Amores' syntax is almost entirely backwards-compatible because the code does not parse on older Perls that use strict. This is helped tremendously by requiring a postfix block syntax which encapsulates the changes, rather than the package syntax for which a postfix block is optional.
    $ perl -Mstrict -Mwarnings -E 'module Foo { sub {...} }'
    Odd number of elements in anonymous hash at -e line 1.
    Can't locate object method "module" via package "Foo" ...

Various incantations all cause the similar failures. If strict is not used, you will still get runtime failures with strange error messages due to indirect object syntax:
    $ perl -e 'module Foo { my $x }'
    Can't locate object method "module" via package "Foo" ...
In an edge case, if have module Foo { ... } and you already have a class by that name defined (and loaded) elsewhere, then Perl will try an indirect object method call and that might succeed, leading to strange behavior:
    package Foo {
        sub module { print "darn it\n" }
    };

    module Foo {}  # prints "darn it"

Tooling
As for tooling, we hope that B::Deparse (https://metacpan.org/pod/B::Deparse), Devel::Cover (https://metacpan.org/pod/Devel::Cover), and Devel::NYTProf (https://metacpan.org/pod/Devel::NYTProf), won't be impacted too strongly. However, this has not yet been tested, obviously.
PPI (https://metacpan.org/pod/PPI) and dependent modules such as Perl::Critic (https://metacpan.org/pod/Perl::Critic) and friends) will be impacted.
Feature Guard
For newer Perl's, Amores will not be available by default. Instead, it will start with a feature guard:
    use feature 'module';
    module Some::Utils {
        ...
    }

Later, it will likely be automatically available with use v8; (speculating about the version number).
Security Implications
Most of what we plan leverages Perl's current capabilities, but with a different grammar. We don't anticipate particular security issues. In fact,due to increased encapsulation, Amores might actually be a bit more secure due to its ability to limit behavior it exposes (assuming we remove the subs from a namespace).
Scope for future work
Plenty of scope, because we have a lexically scoped block to constrain changes, but for now, I think something small is the way to go.
Future: Inner Modules

It would be nice to see public and private inner modules which are hidden from the outside world. These would be analogous to the utility of inner classes.
    module Math {
        sub foo {
            # available to Math::Integer and Math::Float, but not exposed
            # publicly because it has no :export
        }

        module Integer { # exposed as Math::Integer
            ...
        }
        module Float { # exposed as Math::Float
            ...
        }
        module Some::Thing :private { # not exposed
            # I'm less sure about the utility vis-a-vis inner classes
            # because procedural code doesn't really have native requirements
            # for state, but it allows us to create utility modules            # which are private        }
    }

Eventually, package could be used for older namespace declarations, while modules would be first-class and not necessarily exposed via the namespace mechanism unless they were public (or perhaps not even then).
Future: Script Support
Something like Raku's MAIN function (https://docs.raku.org/language/create-cli) would make it easier to write scripts directly, rather than choosing (and arguing over) myriad command-line handling functions.
Why not stick with package?
Because I want us to have something clearly analogous to Corinna in terms of structure (KIM syntax) and clearly something new to show movement rather than "here's a new feature we just tossed in." That last bit is important because I want a to avoid the issue of us just throwing random features at Perl independently without them being thought out holistically.
I've thought about Amores for a long time and to be honest, it scratches my personal itches and it's not entirely fair to assume that everyone itches in the same spot. However, I've tried to ensure that this proposal is the simplest MVP that can be both effective and forward-looking and handles some of the worst nits of Perl.
The syntax and intent of module mirrors the intent of Corinna's class, but clearly on a much smaller scale because the core of Perl procedural code is pretty solid, but fine-tuning for common defaults is useful. And by using postfix blocks, we minimize the risk of these features leaking into "legacy" code. And if this remains experimental for a while and we want to add new features (e.g., inner modules), we have a fresh, new playground to play with that doesn't break older code.
I think Amores and Corinna together greatly improve the overall utility of Perl. Corinna makes modern OOP possible (and native), while Amores removes a number of warts. The actual value of Amores as a single proposal is marginal, but when coupled with Corinna, Perl starts moving towards a more consistent, modern future that's easier to reason about and teach (especially when using KIM to limit keywords).
Best,Ovid-- 
IT consulting, training, specializing in Perl, databases, and agile development
http://www.allaroundtheworld.fr/. 

Buy my book! - http://bit.ly/beginning_perl
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
On Tue, 25 Jan 2022 16:40:31 +0000 (UTC)
Ovid via perl5-porters <perl5-porters@perl.org> wrote:

> Author:  Curtis "Ovid" Poe <curtis.poe@gmail.com>
> Sponsor: Paul "LeoNerd" Evans
> ID:
> Status:  Proposal
> Title:   "Amores", the procedural sister to "Corinna"

...

The usual process for RFCs is to send a PR to the RFCs repo, so
discussions can happen on that rather than the mailing list.

Can you copy this to there please?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
Will do.
-- IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl

On Tuesday, 25 January 2022, 17:48:57 CET, Paul "LeoNerd" Evans <leonerd@leonerd.org.uk> wrote:

On Tue, 25 Jan 2022 16:40:31 +0000 (UTC)
Ovid via perl5-porters <perl5-porters@perl.org> wrote:

> Author:  Curtis "Ovid" Poe <curtis.poe@gmail.com>
> Sponsor: Paul "LeoNerd" Evans
> ID:
> Status:  Proposal
> Title:   "Amores", the procedural sister to "Corinna"

...

The usual process for RFCs is to send a PR to the RFCs repo, so
discussions can happen on that rather than the mailing list.

Can you copy this to there please?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/https://www.tindie.com/stores/leonerd/
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
I'm on a separate branch, but it won't let me push it:
06:16:17 (ovid/13-module-keyword) ~/projects/perl/perl-rfcs $ git push --set-upstream origin ovid/13-module-keywordERROR: Permission to Perl/RFCs.git denied to Ovid.fatal: Could not read from remote repository.
Please make sure you have the correct access rightsand the repository exists.
My .git/config:
[core]        repositoryformatversion = 0        filemode = true        bare = false        logallrefupdates = true        ignorecase = true        precomposeunicode = true[remote "origin"]        url = git@github.com:Perl/RFCs.git        fetch = +refs/heads/*:refs/remotes/origin/*[branch "master"]        remote = origin        merge = refs/heads/master
Have I misunderstood something?
Best,Ovid-- IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl

On Tuesday, 25 January 2022, 18:04:57 CET, Ovid via perl5-porters <perl5-porters@perl.org> wrote:

Will do.
-- IT consulting, training, specializing in Perl, databases, and agile developmenthttp://www.allaroundtheworld.fr/. 
Buy my book! - http://bit.ly/beginning_perl

On Tuesday, 25 January 2022, 17:48:57 CET, Paul "LeoNerd" Evans <leonerd@leonerd.org.uk> wrote:

On Tue, 25 Jan 2022 16:40:31 +0000 (UTC)
Ovid via perl5-porters <perl5-porters@perl.org> wrote:

> Author:  Curtis "Ovid" Poe <curtis.poe@gmail.com>
> Sponsor: Paul "LeoNerd" Evans
> ID:
> Status:  Proposal
> Title:   "Amores", the procedural sister to "Corinna"

...

The usual process for RFCs is to send a PR to the RFCs repo, so
discussions can happen on that rather than the mailing list.

Can you copy this to there please?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/https://www.tindie.com/stores/leonerd/
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
On Tue, 25 Jan 2022 17:19:01 +0000 (UTC)
Ovid via perl5-porters <perl5-porters@perl.org> wrote:

> I'm on a separate branch, but it won't let me push it:

Is this a "How do I github?" question?

The usual process is to fork the repo to your own account, edit there,
then send a PR against that.

Or is there more subtlety to the question that I haven't intuited here?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
On Wed, 26 Jan 2022 at 00:40, Ovid via perl5-porters <perl5-porters@perl.org>
wrote:

> Add a module keyword with basic, modern features to support common Perl
> use cases.
>

First off, the idea is interesting but I disagree with the overall concept:
this seems to be conflating "we should improve the way libraries of non-OO
functions are provided" and "let's apply lots of new defaults".
Implementing just the `:export()` attribute seems a much better - and
simpler! - option.

The lack of versioning means you're locked in to a particular snapshot of
Perl features.

We end up with something that applies to these library files but isn't
available in a script... why make that distinction? There's mention of MAIN
and extending this to cover scripts, but...

Wouldn't we just put all that `indirect/multi_dimensional/signatures/etc.`
into `use 5.038` so that it's available in *all* code? We've already
reduced boilerplate to a single line, while making it clear to the Perl
interpreter what behaviour we expect.

There are a lot of key technical details missing here, for example:

- what do these exports actually do?
- is there any introspection?

Is it implementing the same mechanism that people would expect from
Exporter, i.e. populating the symbol table of the target package? If so, is
that guaranteed - can this be used to implement mixins, for example? Or
would it allow for subs that are only visible to the caller?

Does @EXPORT get populated? How about @EXPORT_OK, %EXPORT_TAGS?

Can all subs be marked as exported without having to put the `:export` tag
on each one? If that's the case, what happens to `our $VERSION`, would that
overwrite the caller's copy? Is $VERSION automatically populated by the
`:version()` attribute?

What happens if you have `module X { sub import { ... } }`? Can you push
imports up a level, e.g. something like `module X { use List::Util qw(min);
sub min : export }`?

Why does it have to be a block - can't we have `module X; ...` to avoid
that extra indentation level?

Two minor things:

- you mention "Currently, Amores' syntax is almost entirely
backwards-compatible because the code does not parse on older Perls that
use strict"... then the first example shows that it *does* indeed parse
perfectly happily, those are *runtime* errors
- getting way offtopic, but... the RFC is in violation of the "civility"
core P5P policy: "stick to the facts while avoiding demeaning remarks,
belittling other individuals", even if the person is famous, perhaps not
appropriate to criticise their ego in a core Perl document

>
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
Ignore this email. It’s late, I’m tired, and I was being stupid. 


Sent from Yahoo Mail for iPhone


On Tuesday, January 25, 2022, 9:08 PM, Tom Molesworth via perl5-porters <perl5-porters@perl.org> wrote:

On Wed, 26 Jan 2022 at 00:40, Ovid via perl5-porters <perl5-porters@perl.org> wrote:

Add a module keyword with basic, modern features to support common Perl use cases.

First off, the idea is interesting but I disagree with the overall concept: this seems to be conflating "we should improve the way libraries of non-OO functions are provided" and "let's apply lots of new defaults". Implementing just the `:export()` attribute seems a much better - and simpler! - option.
The lack of versioning means you're locked in to a particular snapshot of Perl features.
We end up with something that applies to these library files but isn't available in a script... why make that distinction? There's mention of MAIN and extending this to cover scripts, but...
Wouldn't we just put all that `indirect/multi_dimensional/signatures/etc.` into `use 5.038` so that it's available in *all* code? We've already reduced boilerplate to a single line, while making it clear to the Perl interpreter what behaviour we expect.
There are a lot of key technical details missing here, for example:

- what do these exports actually do?
- is there any introspection?

Is it implementing the same mechanism that people would expect from Exporter, i.e. populating the symbol table of the target package? If so, is that guaranteed - can this be used to implement mixins, for example? Or would it allow for subs that are only visible to the caller?

Does @EXPORT get populated? How about @EXPORT_OK, %EXPORT_TAGS?

Can all subs be marked as exported without having to put the `:export` tag on each one? If that's the case, what happens to `our $VERSION`, would that overwrite the caller's copy? Is $VERSION automatically populated by the `:version()` attribute?

What happens if you have `module X { sub import { ... } }`? Can you push imports up a level, e.g. something like `module X { use List::Util qw(min); sub min : export }`?

Why does it have to be a block - can't we have `module X; ...` to avoid that extra indentation level?

Two minor things:
- you mention "Currently, Amores' syntax is almost entirely backwards-compatible because the code does not parse on older Perls that use strict"... then the first example shows that it *does* indeed parse perfectly happily, those are *runtime* errors- getting way offtopic, but... the RFC is in violation of the "civility" core P5P policy: "stick to the facts while avoiding demeaning remarks, belittling other individuals", even if the person is famous, perhaps not appropriate to criticise their ego in a core Perl document
RFC: Amores. Introducing a `module` keyword [ In reply to ]
Some issues / questions about this idea. I agree with others that there are a lot of different ideas here that could be broken down and considered separately.

1) module keyword

I don’t like the term package much, but “module” is currently used to refer to a group of files distributed together (e.g., https://www.cpan.org/modules/index.html ) and I think using it here would just invite more confusion.

Maybe “toolbox” is a good word for a collection of functions?

There are some things that both export a function and are also classes (e.g., Path::Tiny), and I’m not sure how any new keyword would deal with that.

It seems to me that all the actual advantages of having a new keyword were listed under “Scope for future work” (such as inner modules) and there’s no particular reason to not allow something declared with package to, e.g., export via an attribute.

2) attributes on packages/modules

I could imagine using those for other things so I think that makes sense to have in a new keyword, or to add to package if it can be done without breaking backward compatibility.

3) exporting via attributes

I like the idea of exporting with this syntax, but I have a number of questions with the proposal.

Exporter is just one module used for exporting, and there are other ones with much more functionality (e.g., Sub::Exporter or Exporter::Tiny). Could another module intercept whatever it is that would handle the :export attribute in Amores? Would some of the additional features (“-as”, “-prefix”, “-suffix”) be available in Amores exporting?

Listing exports is just one of the many uses of the argument list in “use”, since the “import” sub can do whatever it wants. How would whatever handles exporting distinguish between exports and other arguments to “use”?

The proposal is to have :export(tag), which implies that a tag is a literal. How can a tag be built programmatically? Will :export($tag) work? How about :export(tag1, tag2) ?

It occurs to me that one could have, on the module/package declaration, an attribute that would export all subs, or export all subs whose names don’t begin with an underscore.

4) requiring the use of a postfix block instead of, as with package, “from here to end of scope"

Even if one could fix the automatic formatting tools to ignore the outermost braces, it would still be irritating boilerplate to have to put a trailing brace at the end of every module. Isn’t getting rid of irritating boilerplate part of what this proposal is about?


--
Aaron Priven, aaron@priven.com, www.priven.com/aaron



--
Aaron Priven, aaron@priven.com, www.priven.com/aaron
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
On Tue, Jan 25, 2022 at 11:40 AM Ovid via perl5-porters <
perl5-porters@perl.org> wrote:

> Author: Curtis "Ovid" Poe <curtis.poe@gmail.com>
> Sponsor: Paul "LeoNerd" Evans
> ID:
> Status: Proposal
> Title: "Amores", the procedural sister to "Corinna"
>
> Note: Paul asked that I submit this RFC, but he didn't specifically say he
> would be the sponsor. I'm just hoping :)
>
> *Abstract*
>
> Add a module keyword with basic, modern features to support common Perl
> use cases.
>
> Similar to Corinna ...
>
> class My::Class :version(42) {
> ...
> }
>
> ... we have Amores, the procedural version, using a similarly structured
> KIM syntax (keyword, identifier, modifier:
> https://ovid.github.io/articles/language-design-consistency.html):
>
> use feature 'module';
>
> module My::Module :version(42) {
>
> # these subs are examples only. Their behavior isn't
> # part of the proposal, though `:export` is.
> sub my_sub :export ($arg1, $args2) { ... }
> sub trim :export(strings) ($string) { ... }
> sub ltrim :export(strings) ($string) { ... }
> sub rtrim :export(strings) ($string) { ... }
> sub inc :export(numbers) ($num) { ... }
> sub dec :export(numbers) ($num) { ... }
> sub munge ($thing) { ... }
> }
>
> use My::Module qw(ltrim my_sub);
> use My::Module ':strings';
> use My::Module 'munge'; # fatal, No :export modifier
>
>
> *Motivation*
>
> To bring more consistency and better defaults to Perl, but in a safe,
> lexical scope that offers a strong hint to the Perl developer that this is
> not your grandfather's Perl.
>
> *Rationale*
>
> Sometimes we have a bunch of things we'd like as defaults in Perl, but
> it's not always clear that we can enable them. Even something as simple as
> writing use v5.36.0 can break legacy code unless we use a block to limit
> its scope (I've had quite a few clients in the past couple of years who've
> had Perl as fragile as Kanye West's ego).
>
> The idea behind Amores is to provide a convenient block-like structure
> with a syntax that mirrors Corinna, for a modern, consistent "feel" to the
> language. It's also designed to simplify exporting.
>
> *Syntax*
>
> We add only one keyword: module. Two modifiers (attributes) are added,
> :version and :export (:version also exists in Corinna and could be
> generally applicable outside the language).
>
> *Keyword: module*
>
> This is only enabled with use feature 'module';
>
> The structure of this is:
>
> module MODULE_NAME OPTIONAL_VERSION POSTFIXBLOCK
>
> At the end of the block, it yields a 1 whether you use or require it,
> eliminating the need for the trailing 1 (see also:
> https://github.com/Perl/perl5/issues/17921)
>
> Example:
>
> module My::Module {
> ...
> }
> # or with a version
> module My::Module :version(42) {
> ...
> }
>
> The latter example is equivalent to:
>
> package My::Module {
> our $VERSION = 42;
> use strict;
> use warnings;
> use feature 'signatures';
> no feature 'indirect';
> no feature 'multidimensional';
> no feature 'bareword_filehandles';
> ...
> }
>
> The feature list is deliberately kept small and sane to minimize danger. use
> utf8 was removed from the above list after P5P feedback. This discussion
> was referenced in that conversation:
> https://www.nntp.perl.org/group/perl.perl5.porters/2021/08/msg261164.html.
>
> In other words, lots of useful boilerplate goes away.
>
> Happy to discuss adding other features if necessary/useful.
>
> *Modifier: :version(...)*
>
> Optionally declared after the module name (and *only* after the module
> name to make it extremely predictable). Any valid version number may be
> specified.
>
> *Modifier: :export*
>
> This attribute controls exporting of functions from a module. It does not
> use the import mechanism, though if an import sub is found, it will
> still be called in the normal manner. It just won't be needed for importing.
>
> module My::Module :version(42) {
>
> # these subs are examples only. Their behavior isn't part of the
> # proposal, though `:export` is.
> sub my_sub :export ($arg1, $args2) { ... }
> sub trim :export(strings) ($string) { ... }
> sub ltrim :export(strings) ($string) { ... }
> sub rtrim :export(strings) ($string) { ... }
> sub inc :export(numbers) ($num) { ... }
> sub dec :export(numbers) ($num) { ... }
> sub munge ($thing) { ... }
> }
>
> This would mostly follow the syntax of the Perl6::Export::Attrs (
> https://metacpan.org/pod/Perl6::Export::Attrs) module, but with the
> following differences:
>
> - :export is lower case
> - User-specified export groups do not allow a colon (:export(strings,
> munging))
> - Built-in export behavior requires a colon prefix (:export(:MANDATORY)
> )
>
> Naturally, any subroutines without an :export tag are not available for
> export.
>
> Importing *any* group requires the colon:
>
> use Some::Module ':strings';
>
> Possibly we may require user-defined groups to not be all upper-case.
>
> *Backwards Compatibility*
>
> Currently, Amores' syntax is almost entirely backwards-compatible because
> the code does not parse on older Perls that use strict. This is helped
> tremendously by requiring a postfix block syntax which encapsulates the
> changes, rather than the package syntax for which a postfix block is
> optional.
>
> $ perl -Mstrict -Mwarnings -E 'module Foo { sub {...} }'
> Odd number of elements in anonymous hash at -e line 1.
> Can't locate object method "module" via package "Foo" ...
>
> Various incantations all cause the similar failures. If strict is not
> used, you will still get runtime failures with strange error messages due
> to indirect object syntax:
>
> $ perl -e 'module Foo { my $x }'
> Can't locate object method "module" via package "Foo" ...
>
> In an edge case, if have module Foo { ... } and you already have a class
> by that name defined (and loaded) elsewhere, then Perl will try an indirect
> object method call and that might succeed, leading to strange behavior:
>
> package Foo {
> sub module { print "darn it\n" }
> };
>
> module Foo {} # prints "darn it"
>
> *Tooling*
>
> As for tooling, we hope that B::Deparse (
> https://metacpan.org/pod/B::Deparse), Devel::Cover (
> https://metacpan.org/pod/Devel::Cover), and Devel::NYTProf (
> https://metacpan.org/pod/Devel::NYTProf), won't be impacted too strongly.
> However, this has not yet been tested, obviously.
>
> PPI (https://metacpan.org/pod/PPI) and dependent modules such as
> Perl::Critic (https://metacpan.org/pod/Perl::Critic) and friends) will be
> impacted.
>
> *Feature Guard*
>
> For newer Perl's, Amores will not be available by default. Instead, it
> will start with a feature guard:
>
> use feature 'module';
>
> module Some::Utils {
> ...
> }
>
> Later, it will likely be automatically available with use v8;
> (speculating about the version number).
>
> *Security Implications*
>
> Most of what we plan leverages Perl's current capabilities, but with a
> different grammar. We don't anticipate particular security issues. In fact,
> due to increased encapsulation, Amores might actually be a bit more secure
> due to its ability to limit behavior it exposes (assuming we remove the
> subs from a namespace).
>
> *Scope for future work*
>
> Plenty of scope, because we have a lexically scoped block to constrain
> changes, but for now, I think something small is the way to go.
>
>
> *Future: Inner Modules*
>
> It would be nice to see public and private inner modules which are hidden
> from the outside world. These would be analogous to the utility of inner
> classes.
>
> module Math {
> sub foo {
> # available to Math::Integer and Math::Float, but not exposed
> # publicly because it has no :export
> }
>
> module Integer { # exposed as Math::Integer
> ...
> }
> module Float { # exposed as Math::Float
> ...
> }
> module Some::Thing :private { # not exposed
> # I'm less sure about the utility vis-a-vis inner classes
> # because procedural code doesn't really have native
> requirements
> # for state, but it allows us to create utility modules
> # which are private
> }
> }
>
> Eventually, package could be used for older namespace declarations, while
> modules would be first-class and not necessarily exposed via the namespace
> mechanism unless they were public (or perhaps not even then).
>
> *Future: Script Support*
>
> Something like Raku's MAIN function (
> https://docs.raku.org/language/create-cli) would make it easier to write
> scripts directly, rather than choosing (and arguing over) myriad
> command-line handling functions.
>
> *Why not stick with package?*
>
> Because I want us to have something clearly analogous to Corinna in terms
> of structure (KIM syntax) and clearly something new to show movement rather
> than "here's a new feature we just tossed in." That last bit is important
> because I want a to avoid the issue of us just throwing random features at
> Perl independently without them being thought out holistically.
>
> I've thought about Amores for a long time and to be honest, it scratches
> my personal itches and it's not entirely fair to assume that everyone
> itches in the same spot. However, I've tried to ensure that this proposal
> is the simplest MVP that can be both effective and forward-looking and
> handles some of the worst nits of Perl.
>
> The syntax and intent of module mirrors the intent of Corinna's class,
> but clearly on a much smaller scale because the core of Perl procedural
> code is pretty solid, but fine-tuning for common defaults is useful. And by
> using postfix blocks, we minimize the risk of these features leaking into
> "legacy" code. And if this remains experimental for a while and we want to
> add new features (e.g., inner modules), we have a fresh, new playground to
> play with that doesn't break older code.
>
> I think Amores and Corinna together *greatly* improve the overall utility
> of Perl. Corinna makes modern OOP possible (and native), while Amores
> removes a number of warts. The actual value of Amores as a single proposal
> is marginal, but when coupled with Corinna, Perl starts moving towards a
> more consistent, modern future that's easier to reason about and teach
> (especially when using KIM to limit keywords).
>

Want to get my comments on this RFC down before I forget.

As in the previous discussion on this, I feel that there are some useful
feature requests here, but not a cohesive feature where a new feature flag
and keyword (especially such a heavily charged keyword) is warranted.

1. The :export feature, or some other standardized syntax to mark subs
exportable in an intentional design, would be a huge improvement over the
Exporter situation. I think this warrants an RFC and discussion on its own.

2. You haven't explained how requiring a block scope is beneficial (other
than the note in backwards compatibility, which doesn't seem a useful
distinction when the proposal is intended to be feature-gated). Lexical
declarations work perfectly fine without being attached to a block, and can
be surrounded by a block if you need one, and the option to write a module
as the entire contents of a file without an extra scope seems important to
preserve, popular, and exactly as featureful.

3. To wit, all of the features being enabled here are just an unversioned
feature bundle (in the use VERSION sense). This seems like something that
would quickly become an outdated featureset and interact confusingly with
feature bundles that already exist.

4. Version declarations in package statements are already-existing syntax.
I don't feel there's a strong case to add a second slightly different
version of it.

Putting this all together as you envision would be a fine job for a CPAN
module, but for a core feature it is a tough sell for me, apart from the
export mechanism.

-Dan
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
On Tue, Jan 25, 2022 at 8:50 PM Dan Book <grinnz@gmail.com> wrote:

> 1. The :export feature, or some other standardized syntax to mark subs
> exportable in an intentional design, would be a huge improvement over the
> Exporter situation. I think this warrants an RFC and discussion on its own.
>

Did forget one part of this: at least as proposed, this should not require
a feature flag or cause any incompatibility.

-Dan
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
RFC now properly submitted.

Best,
Ovid
-- 
IT consulting, training, specializing in Perl, databases, and agile development
http://www.allaroundtheworld.fr/. 

Buy my book! - http://bit.ly/beginning_perl






On Tuesday, 25 January 2022, 17:48:57 CET, Paul "LeoNerd" Evans <leonerd@leonerd.org.uk> wrote:





On Tue, 25 Jan 2022 16:40:31 +0000 (UTC)
Ovid via perl5-porters <perl5-porters@perl.org> wrote:

> Author:  Curtis "Ovid" Poe <curtis.poe@gmail.com>
> Sponsor: Paul "LeoNerd" Evans
> ID:
> Status:  Proposal
> Title:   "Amores", the procedural sister to "Corinna"

...

The usual process for RFCs is to send a PR to the RFCs repo, so
discussions can happen on that rather than the mailing list.

Can you copy this to there please?


--
Paul "LeoNerd" Evans


leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/
Re: RFC: Amores. Introducing a `module` keyword [ In reply to ]
> Status: Proposal
> Title: "Amores", the procedural sister to "Corinna"

Perl core used to provide a set of tools for modules to build upon.
But this proposal is a final implementation with very fine details
included that other's can't extend in any meaningful sense. Is that's
what is perl about from now on?

Best regards,
Sergey Aleynikov