Perl-Apollo / Corinna

Corinna - Bring Modern OO to the Core of Perl
Artistic License 2.0
157 stars 19 forks source link

RFC Feedback #26

Closed Ovid closed 3 years ago

Ovid commented 3 years ago

Please leave feedback on the Corinna RFC here.

duncand commented 3 years ago

A detail point, on the first page, METHODNAME and IDENTIFIER should be harmonized; one says [:alpha:] {[:alnum:]} and the other says [a-zA-Z_]\w*; I see no reason for them to differ from each other, and if they did then they should use the same elements, either the newer or older format but not both.

duncand commented 3 years ago

On the first page, does VERSION need to be exactly 3 integers in a row or can it be N integers in a row?

EDIT: I see now that https://github.com/Ovid/Cor/wiki/Corinna-Overview says semantic-versions-only is intentional, so it seems that answers my question.

duncand commented 3 years ago

On the first page, does ROLES need to be a single instance of the keyword plus a comma list or is it reasonable for each named role to have its own keyword, eg does Foo does Bar vs does Foo, Bar? Is one of those options chosen on purpose or is it arbitrary? Do you want to support both? For my part I'm fine with the way you have it, that's probably what I would have done, a single keyword and a list as its payload, which is arguably much simpler, especially when represented as an AST where does and isa and etc are each keys in a hash.

boftx commented 3 years ago

I think that something like this should be released as a module, like Moose and Moo, to see how well it is received and used before it is brought into core. There is little doubt that both Moo and Moose have been widely adopted and have become the standards for Modern Perl.

And if I might put my foot in my mouth, it is my opinion that it was changes like this that led to the discord associated with P6/Raku and the eventual split from P5. Going straight to core with this before seeing if people actually want/use it is a mistake in my opinion.

duncand commented 3 years ago

@boftx From my reading that is already in the cards, and the module implementation would run on any Perl version 5.14 and later.

boftx commented 3 years ago

@boftx From my reading that is already in the cards, and the module implementation would run on any Perl version 5.14 and later.

I hope that is the case. Given all that has happened over the last 10 - 15 years in our community I am leery of any major addition like this that is intended to replace a well established base and is essentially untested. I feel there needs to be real-world acceptance testing before such a major step.

xenu commented 3 years ago

If I'm reading it correctly, the grammar seems to require BLOCK after class and role. That's inconsistent with how package works and also Object::Pad doesn't seem to require it. Is that an oversight?

duncand commented 3 years ago

If I'm reading it correctly, the grammar seems to require BLOCK after class and role. That's inconsistent with how package works and also Object::Pad doesn't seem to require it. Is that an oversight?

That is by design i believe and it is a vast improvement.

xenu commented 3 years ago

I don't see how requiring a pointless, Java-style additional level of indentation is an improvement, especially considering that in the majority of cases there's just one class per file.

Note that I'm not saying that the BLOCK form should be removed, it's handy when you want to define multiple classes in a single file, I just don't want it to be the only option.

duncand commented 3 years ago

There's no extra indentation, Perl did and still does let you indent however you want.

The block form has the benefit of making everything more clearly scoped.

duncand commented 3 years ago

I do however accept that not requiring braces is probably best. The package declaration has had optional braces, but still gives you a choice, for several major Perl versions. I don't see a problem with them being optional for class/role too.

Ovid commented 3 years ago

@xenu wrote:

I don't see how requiring a pointless, Java-style additional level of indentation is an improvement, especially considering that in the majority of cases there's just one class per file.

It is not pointless. It was a design decision made with reluctance, but it was pretty clear from the start that we didn't have a choice.

P5P has been extremely clear that they do not want to accept changes that will cause your code to break if you upgrade your Perl version. They've accepted breaking changes in the past, but with reluctance. For a change this big, it would have sweeping effects on the Perl language were it not block-scoped. Imagine every codebase using Moo/se and their has function clashing with ours.

There are other keywords being introduced and we'll have more in the future. By requiring the block, we tremendously reduce the risk of breaking existing Perl installations. See also, the Backwards Compatibility section of the RFC.

xenu commented 3 years ago

I really don't understand your point. It's feature.pm's job to guarantee the backwards compatibility. And even if we had been living in a parallel universe where there is no feature.pm, I don't see what difference BLOCK makes:

<has doesn't work>
class Foo;
<has and friends now work>
Ovid commented 3 years ago

@xenu: the feature guard is there to ensure we can test ideas out. In the future, it's intended that the guard be dropped and simply use v... should enable modern features. Of course, one shouldn't just do that blindly on older code, but by keeping the changes to a clearly defined scope, we mitigate even that risk.

xenu commented 3 years ago

the feature guard is there to ensure we can test ideas out.

No, that's not the purpose of feature. Also, the old Perl 7 plan was (thankfully!) cancelled.

Ovid commented 3 years ago

Also, this has, surprisingly, been one of the least contentious issues (I thought more people would be unhappy, but most just shrug). However, when this goes from a proposed RFC to an actual RFC, please feel free to share your concerns with P5P. They could easily have a different opinion and I'm OK with that.

Alternatively, if the proposal is accepted, I'm sure there will be plenty of future RFCs to change/add syntax. That's yet another approach which might help.

boftx commented 3 years ago

I am going to restate my initial position in a slightly different way. Given the clumsiness of "use feature" to avoid compatibility issues I believe that something as significant as Corina should be tested as a CPAN module if possible before being brought into core. Some of you are aware of my objections to the prosed try/catch feature as opposed to the existing Try::Tiny module. Just looking at the reverse dependencies shows that Try::Tiny is far more popular (over 1300 reverse dependencies I think) when compared to Syntax::Keyword::Try (about 30 as I recall) that the proposed try/catch is based on. My disagreement is not with a given feature, it is with the process of deciding that it should in fact be brought into core. I am firmly against the new try/catch feature based on the acceptance I see in CPAN. I would like to see the same for Corina before bringing it in. The "use feature" option has caused enough problems already. Testing new ideas as a CPAN module seems much more flexible to prevent compatibility issues.

haarg commented 3 years ago

What is the clumsiness or "problems" of "use feature"?

Try::Tiny has been around a lot longer and satisfies two concerns, backwards compatibility and pure-perl usage, which give it an advantage over Syntax::Keyword::Try. Those are not relevant to a core feature. Considering only the number of dependents is a poor metric for how to design a core feature. Try::Tiny has large caveats and I've seen it cause problems numerous times, not to mention its performance impact. Those issues are a direct result of its backwards compatibility and pure-perl nature.

While some of Corrina is currently being prototyped in Object::Pad, there's no guarantee it will be able to be fully implemented as a module. And it will never overtake the Moo/Moose ecosystem in number of users on CPAN. If your success criteria is "most widely used" then Corrina is impossible.

duncand commented 3 years ago

My disagreement is not with a given feature, it is with the process of deciding that it should in fact be brought into core. I am firmly against the new try/catch feature based on the acceptance I see in CPAN. I would like to see the same for Corina before bringing it in.

I agree with your desire that Corinna should get a CPAN release first so people can try it out and see how it really behaves in working code and not just in documentation. And that duals to supporting it with older Perls. So I want this too. It means I can use Corinna, which I want to do, in my own upcoming CPAN modules, but doing so wouldn't require me to require Perl 5.36 and above.

Regarding the try/catch thing, I feel that CPAN acceptance is only a weak indicator of fitness. I expect that almost everyone who chose Try::Tiny was cargo-culting and just used it because they saw someone else using it in code they copied, rather than Try::Tiny actually being better than Syntax::Keyword::Try. Try::Tiny is a much older module so would have more mind-share for that reason. I didn't have a preference between the various try/catch solutions, but I did just read a comparison between the 2 mentioned and there seemed to be a stronger case for Syntax::Keyword::Try being "better".

haarg commented 3 years ago

I don't see how requiring a block changes the backwards compatibility concerns at all.

A valid class block, with or without instance variables, can be valid perl code on older perl versions. It would compile to a mess of sub calls and indirect object calls. Instance variables would not violate strict if they had been installed via something operating like use vars. This is all exactly the same if using a class Foo::Bar; statement. A feature flag will always be required to disambiguate the syntax. And if a feature flag is required, we can do pretty much whatever we want with the syntax.

tm604 commented 3 years ago

@boftx http://metacpan.org/pod/Object::Pad has been on CPAN for over a year now - the test-in-CPAN approach is already happening.

What specific changes or extra steps are you suggesting there? Have you tried Object::Pad already?

boftx commented 3 years ago

Try::Tiny is a much older module so would have more mind-share for that reason.

Try::Tiny has been around since 2009. Syntax::Keyword::Try has been around since 2016. There can be no comparison between which has been more accepted over time, given that the younger has 5 years behind it. Try::Tiny is more popular by about two orders of magnitude with only double the lifespan.

boftx commented 3 years ago

@boftx http://metacpan.org/pod/Object::Pad has been on CPAN for over a year now - the test-in-CPAN approach is already happening.

What specific changes or extra steps are you suggesting there? Have you tried Object::Pad already?

In the four years since it's release (2017) it has only 37 modules listed in the reverse dependencies. I'm not even going to bother with how many Moose or Moo has. Community acceptance counts.

duncand commented 3 years ago

In the four years since it's release (2017) it has only 37 modules listed in the reverse dependencies. I'm not even going to bother with how many Moose or Moo has. Community acceptance counts.

I still attribute that to a large part to cargo culting. People chose Moose/Moo because they saw others using it, not because they compared all the options and picked the "best". Because of the paralysis of 40 choices or whatever, don't bother trying to find the best, just use what others are using. Core has different criteria.

duncand commented 3 years ago

http://metacpan.org/pod/Object::Pad has been on CPAN for over a year now - the test-in-CPAN approach is already happening.

What specific changes or extra steps are you suggesting there? Have you tried Object::Pad already?

I was under the impression that Corinna was still under active design even in the last few months. So whatever Object::Pad did as of 1 year ago wouldn't be what the latest Corinna proposal is. If I am wrong, then I believe the Corinna RFC should gain very prominently at the top a statement saying, the current version of this proposal is implemented right now for CPAN as Object::Pad, try it out! If it can't do that, then Object::Pad isn't near enough the same thing to count yet. Since Corinna was under active design, I assumed that the CPAN implementation wasn't ready yet and would come in the future.

tm604 commented 3 years ago

@duncand perhaps that's something you could contribute? Review the Object::Pad documentation and the Corinna RFC, flag anything that's missing or inconsistent, and raise a PR to add that wording?

duncand commented 3 years ago

@duncand perhaps that's something you could contribute? Review the Object::Pad documentation and the Corinna RFC, flag anything that's missing or inconsistent, and raise a PR to add that wording?

Sorry, I don't have the savviness or time to do that much. The ones who should know best are the authors.

You @tm604 said Object::Pad was a sufficiently complete implementation. @Ovid would know best if it is, and when he has the confidence that it is, then his declaring such prominently would be the indication of that confidence.

Ovid commented 3 years ago

@duncand: Not having the time I can believe, but you have the savviness :)

Object::Pad isn't yet sufficiently complete. It's a subset of what Corinna is trying to provide and it also diverges in some ways (object construction isn't automatic, for example).

duncand commented 3 years ago

@duncand: Not having the time I can believe, but you have the savviness :)

Object::Pad isn't yet sufficiently complete. It's a subset of what Corinna is trying to provide and it also diverges in some ways (object construction isn't automatic, for example).

Thank you for confirming what I suspected.

I understand that they won't be perfectly aligned because some details could only be in core, but basically when it gets as close as is technically possible to the Corinna spec, that you'd document this is the case prominently. So those wanting to try out before supporting it going in core can do so.

As for what I want, I generally trust that if this gets into core it will be good, and I can judge a lot just from the spec. Mainly it is testing edge cases that the CPAN is good for.

As for what I want, being in the core is the entire point. For my CPAN modules I want to have zero dependencies that aren't in core. If this makes it into core then I will use it. If it doesn't then I will use bless instead. I personally am not interested in using Object::Pad except sole for expanding support to older Perls, but I at least expect my modules to be able to use the newest version of Perl with no other external dependencies.

cavac commented 3 years ago

In Corinna, class and instance data is fully encapsulated unless you choose to explicitly make it public.

And that's exactly the reason i don't like C++, Java or "modern Perl" OO.

While i'm certainly all for a more modern way to write OO objects, i like the "soft" option of blessed hashrefs for my own projects. For me, everything in a running perl program should be changeable.

Ovid commented 3 years ago

@cavac I get where you're coming from. I really do. But I frequently work on large (million LOC+) systems for clients and "everything ... should be changeable" is one of the reasons why large Perl code bases are so painful to maintain. We've been approached several times by companies with large Perl code bases who are sick of the lack of safety and who've said they're fed up and want an exit strategy from Perl.

leonerd commented 3 years ago

@boftx

I think that something like this should be released as a module, like Moose and Moo, to see how well it is received and used before it is brought into core. There is little doubt that both Moo and Moose have been widely adopted and have become the standards for Modern Perl.

Released as a CPAN module - that's exactly what Object::Pad is.

kernigh commented 3 years ago

I don't like how, in Perl, I need to set $self in each method, like my $self = shift;. A system to automatically set $self would be welcome. Corinna might be such a system.

How would I make a new object in Corinna? Suppose that I want to convert this code.

package Zorg;
use Carp qw(croak);
use constant SIZE => 12;
sub new {
  my ($class, $fh) = @_;
  read($fh, my $it, SIZE) == SIZE or croak "short zorg";
  bless \$it, $class
}
sub foo  { unpack('0x N', shift->$*) }
sub bar  { unpack('4x n', shift->$*) }
sub baz  { unpack('6x n', shift->$*) }
sub quux { unpack('8x N', shift->$*) }

The usage is my $zorg = Zorg->new($fh) to read 12 bytes from a filehandle, and $zorg->foo and $zorg->baz to unpack some fields. The code shift->$* is a shortcut for my $self = shift; $$self to dereference those 12 bytes.

This code defies the advice in perlootut to use a system like Moose. Those systems wouldn't help. Zorg has only 1 attribute (its 12-byte string) and does no roles, so it doesn't want Moose to declare attributes nor define roles. Moose and the other systems don't help with my $self = shift;.

Corinna might help if I declare a slot variable $buf for the 12-byte string,

class Zorg;
has $buf;
...
method foo()  { unpack('0x N', $buf) }
method bar()  { unpack('4x n', $buf) }
method baz()  { unpack('6x n', $buf) }
method quux() { unpack('8x N', $buf) }

Corinna might set $self, but $buf would implicitly belong to $self, so I wouldn't mention $self in these methods. (The current grammar has class Zorg { ... } with a block, but I want to use a pragma to enable the class Zorg; syntax.)

The hard part is to set $buf in a new object. The next example would be wrong,

# This wants to be the class method Zorg->new($fh)
common method new($fh) {
    # Corinna might have set $class = "Zorg"
    my $it = $class->SUPER::new();
    read($fh, my $nbuf, SIZE) == SIZE or croak "short zorg";
    $buf of $it = $nbuf;
    $it
}

Corinna wouldn't parse $buf of $it. I have programmed in Ruby, so I know how Ruby's class method ::new forwards its arguments to the new object's method #initialize. If Corinna's Zorg->new($fh) would call $new_object->initialize($fh), then I would write,

method initialize($fh) {
    read($fh, $buf, SIZE) == SIZE or croak "short zorg";
}

The ADJUST block (in the Corinna Overview), or the BUILD block (in PAD::Object), might not do what I want.

tm604 commented 3 years ago

@kernigh why not give it a try?

The relevant Object::Pad code would be:

use Object::Pad;
class Zorg;
use Carp qw(croak);
use constant SIZE => 12;

has $buf;

BUILD ($fh) {
  read($fh, $buf, SIZE) == SIZE or croak "short zorg";
}

method foo()  { unpack('0x N', $buf) }
method bar()  { unpack('4x n', $buf) }
method baz()  { unpack('6x n', $buf) }
method quux() { unpack('8x N', $buf) }

Not really clear on what you mean by the $buf of $it = $nbuf; part, is this for inheritance? If so, just expose $buf as a method and have subclasses use that?

raforg commented 3 years ago

Just some possible typos:

s/along for disabling/along with disabling/
s/expose them in same way/expose them in some way/
s/will note that that between/will note that between/
Ovid commented 3 years ago

@raforg All fixed now. Thank you :)

duncand commented 3 years ago

This comment copies something I just said on perl5-porters.

I completely agree with the proposal to drop "modern" from Corinna's title/description/etc as proposed by Tom Molesworth, but it hadn't occurred to me before.

Using "modern" to describe something is so over-used its lost all meaning. It feels like every module on CPAN providing an object system calls itself "modern". So by NOT doing so, Corinna would actually stand out more.

I propose the term "effective" rather than "modern", barring that something better comes along. Also "concise" is good. You can use more than one.

Frequently when I'm trying to figure out a name for something, including in my own language/format development, I explore thesaurus-dot-com which has been immensely helpful.

xenu commented 3 years ago

Limiting versions to semver seems extremely arbitrary, especially considering that overwhelming majority of CPAN dists aren't following that versioning system.

duncand commented 3 years ago

Limiting versions to semver seems extremely arbitrary, especially considering that overwhelming majority of CPAN dists aren't following that versioning system.

I agree. I know that the Corinna docs said that semver was an intentional choice, but at the same time I feel there is absolutely no technical reason for it. Nothing possibly short of a packaging system would be making decisions based on semantic versioning logic. But more critically, this is completely orthogonal to anything to do with an object system. The only reason I can think of in support of it is if the extended package format we already have package Foo vN {...} has the same restriction, and then you are matching it.

Ovid commented 3 years ago

Versions in Perl are a trainwreck. I don't want Corinna to ride that train.

xenu commented 3 years ago

So you expect all the CPAN authors who want to use Corinna to change their versioning scheme?

duncand commented 3 years ago

Versions in Perl are a trainwreck. I don't want Corinna to ride that train.

@Ovid Again, versions have NOTHING to do with OO or what Corinna's about. The only appropriate thing to do here is that versions declared inline in Corinna class declarations accept all of the same formats they do with package declarations. And you just point to the same version-implementing code rather than having your own. There is NO reason to have your own of this. Versions being a train wreck or whatever is an independent thing, and if its going to be fixed it should be fixed universally.

boftx commented 3 years ago

At this point I am going to address the 800lb gorilla in the room. Stop trying to make Perl something else! Yes, Perl is not perfect, but many of us who have made our living with it for the last 25 years (or more) love what it is and do NOT want to see it changed to be more like other languages!

Now you want to change how we version things?!? We already have gone through this once before, do we really need to do it again?!?

This is exactly what led to over a decade of discord and discontent with Perl 6/Raku, We do NOT need to do that all over again!

Ovid commented 3 years ago

@boftx Yes, and many (more, it appears, from the feedback across multiple forums) want the bugs fixed.

Please, let us confine ourselves to the technical discussions here. You've repeatedly expressed, on more than one forum, that you like things they way you are. That's fine. You don't have to use any of the new tools and we have no plans to take away the old tools. If you like them, use them.

And please do not bring up the Perl 6/Raku issue again. This has caused too many fights, too many hurt feelings, and I have zero interest in rekindling that here. I want to fix the problems, not the blame.

Ovid commented 3 years ago

@duncand @xenu You may be right about the versioning. However, this again falls back on "what the simplest thing we can possibly use to allow this" (from the user's standpoint, not the implementers). If we allow everything which is broken as the Perl versioning system and we realize later we made a mistake and shouldn't do that, then we're kinda stuck and we can't back out of that.

However, the reverse is not true. If we stick to semver and later realize it's too limiting, we can back out of that decision. It's important that Corinna have the chance to be parsimonious and open up later.

duncand commented 3 years ago

However, the reverse is not true. If we stick to semver and later realize it's too limiting, we can back out of that decision. It's important that Corinna have the chance to be parsimonious and open up later.

@Ovid Yes, you have a good point there, and it aligns with a recommendation I've made several times before. From the user's point of view, being more restrictive in what syntax/etc users can access up front gives us forwards compatibility to loosen it up later, but the reverse isn't true. I withdraw my objection to the version number strictness. Anyone actually using the new Corinna feature would have to use a new version anyway, so why not format it this semver way. It may not be their preference but it is compatible with the old versions as they directly correspond per X.00Y00Z.

duncand commented 3 years ago

Stop trying to make Perl something else! Yes, Perl is not perfect, but many of us who have made our living with it for the last 25 years (or more) love what it is and do NOT want to see it changed to be more like other languages!

I strongly disagree.

Perl with Corinna IS STILL PERL.

Perl is not losing anything over this, you can still continue to use it as you did before. Corinna is just adding a new option for those who want to use it.

This is very much in contrast from the other language you mention which was not backwards-compatible.

merrilymeredith commented 3 years ago

Could a trailing comma be permitted on the role list following does, or was there already a decision against it?

Most examples seen so far have this all in one line but inevitably one will need to line break to write a hellclass with 5 painroles all under the company namespace prefix and I was exploring how I might style that:

class Frob
does
  Foo,
  Bar,
  Xyzzy
{

Right now in the grammar and in Object::Pad, a trailing comma is not permitted, while that's not the case dealing with the comma operator in general perl syntax. Obv don't want to get into the reasons devs are for/against trailing commas, but I wasn't sure if this was oversight or intentional.

leonerd commented 3 years ago

Object::Pad happens not to currently permit it, due to the way that XS::Parse::Keyword's XPK_COMMALIST structure works. There's no inherent design reason to forbid it, it just falls out of the current implementation that it gets upset. I should see if I can fix that sometime.

duncand commented 3 years ago

Could a trailing comma be permitted on the role list following does, or was there already a decision against it?

Oh, YES!

This is another thing I push heavily for in language design. For EVERY context where you have a comma-list of something, trailing and leading commas should be allowed. One should be able to format their lists with one item per line and every item has the same format as the others, no special exceptions for the first or last item.

At least, that should be the case where the list context has unambiguous delimiters, such as it being surrounded by parenthesis or braces or brackets. Where that's not the case it can get more complicated. But the trailers should be allowed anywhere there is no ambiguity.

We can avoid the problem here by having the does require some kind of bracketing pair, I recommend parenthesis specifically, when there's more than one item.