Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Methods Feedback #15

Closed
Ovid opened this issue May 21, 2020 · 13 comments
Closed

Methods Feedback #15

Ovid opened this issue May 21, 2020 · 13 comments
Labels
Feedback Cor Proposal Feedback

Comments

@Ovid
Copy link
Collaborator

Ovid commented May 21, 2020

Please leave comments on Methods here.

@haarg
Copy link

haarg commented May 22, 2020

How is private method dispatch expected to work? Would it be using the equivalent of a caller check? How would this apply to $object->$method or $object->can($method)?

In an overridden method, how would you call the parent class's method? next::method?

@haarg
Copy link

haarg commented May 22, 2020

The pseudo-grammar is missing the method name.

Would my $foo = method { ... }; or my method foo { ... } work?

@haarg
Copy link

haarg commented May 22, 2020

Multi-methods (just like signature enhancements) shouldn't apply to only methods. If they are implemented, they should apply equally to all subs. So I wouldn't consider them as part of the Cor proposal.

@Ovid
Copy link
Collaborator Author

Ovid commented May 22, 2020

@haarg Regarding multi-methods, I agree. But since my work is for Cor and not the general language, I'm kinda stuck there. I don't know what the right answer is.

@Ovid
Copy link
Collaborator Author

Ovid commented May 22, 2020

@haarg: I've also tried a first-pass address of the missing method name issue. A signature is actually the method name plus the arguments.

@HaraldJoerg
Copy link
Contributor

I suggest to explicitly mention one of the important properties of methods: The instance is available as the lexical variable $self. Other languages use other names for this variable, and the reason for Perl's choice (writing my $self for 'myself') is no longer apparent in Cor methods.

About multi methods - if there ever is some conflict which feature should not be in the first minimum viable product, then multi methods would be a good candidate to drop. They may be a cool feature, but they aren't that useful without a type system.

Some remarks about your examples:

About authentication: what if you want authenticate($resource,$token)? I've been developing an authentication system for some years, and during that period, thanks to technical progress elsewhere, it saw two different token-based authentication schemes. The lesson here is: multi methods are tricky to extend. We don't want to see multi method authenticate($resource,$token,$junk,$junk) "I need two pieces of junk since the three-argument-version has already been taken". Cor takes the position you want your contract to be as small as possible is a rather eristic statement if the complexity is just shifted from method names to different lengths of argument lists.

The quicksort example makes traditional Perl look worse than it needs to be. Look at this:

sub quacksort (@list) {
    2 > @list  and  return @list;

    my $pivot = shift @list;
    return (
        quacksort( grep { $_ < $pivot } @list ),
        $pivot,
        quacksort( grep { $_ >= $pivot } @list ),
    );
}

You can't shortcut lists with 0 and 1 elements like this in a multi method. Also, there's an exercise: Rewrite quicksort so that the last element is taken as the pivot. The lesson is: this multi method example restricts options for implementation.

In my own Java practice, the most frequent use of multi methods was for parameters which could take different equivalent forms - an object, a key/value hashmap, or a serialisation thereof. Perl / CPAN has many of these cases where elements of @_ are examined whether they are references. Cor's multi methods won't help here.

So while I don't want to prevent Cor's multi methods from happening, I can live pretty well without them.

@haarg
Copy link

haarg commented May 24, 2020

@haarg Regarding multi-methods, I agree. But since my work is for Cor and not the general language, I'm kinda stuck there. I don't know what the right answer is.

Multi-methods (and signatures) are a general language feature. If you want them, create a separate proposal for them. You can work on two independent proposals at the same time.

@Ovid Ovid added the Feedback Cor Proposal Feedback label Jun 6, 2020
@HaraldJoerg
Copy link
Contributor

Some thoughts about keywords:

  • Instead of abstract method I suggest requires, like in roles - or more precisely, use the same keywords for both because they are pretty much the same thing.
  • shared private method gives me the shivers. We mean class methods here. If the parser gets confused with yet another occurrence of the class keyword, I'd prefer either a fixed order of keywords (private class method - but this doesn't really help) or (ugh) a new keyword class_method.

Yeah... I can imaging that parsing class method isa {...;} vs. class method isa does {...;} is tricky.

@duncand
Copy link

duncand commented Feb 22, 2021

It would be best to exclude multi-methods. These are a design smell in principle, and any case where one would be thinking of using them, they should instead be using normal different-named methods.

@duncand
Copy link

duncand commented Feb 22, 2021

If you're going to support private, rather than everything being public, then you should also support trusts like Raku has. Analogies in other languages are internal scope of .NET/C# and package-private scope of Java (but this is broken), but the .NET concept is based on the concept of a common assembly which doesn't exist in Perl. Raku's example is what you want to follow. I agree that protected isn't needed. Trusts is the best medium between private and public. Trusts or analogy is also necessary for many projects. Also one needs to be able to declare not only regular methods but also constructors and accessors such that certain other classes can call them but not the general public. For example, a class that should only be created by a class factory should say its constructor trusts the class factory class and is otherwise private.

@duncand
Copy link

duncand commented Feb 22, 2021

I propose simplifying things by omitting the whole concept of class methods, and make all methods instance methods that have a $self automatically in scope.

Generally the whole concept of a class method in other OO languages like Java is an artifact of their design that every package is a class and every routine is a method. But Perl already has non-object packages and subroutines which can satisfy that.

Unless you are forbidding things in classes that classic Perl packages support such as regular subs or $my things declared within the package/class scope, you can use those things for certain non-instance stuff.

What I propose is that the only way one is allowed to invoke a method is on an object, and they mot invoke a method directly on a class name, and every method has a $self. Fundamentally instantiating an object would have a special or factory-like syntax built-in to the language which is the only place the class name would appear for that purpose.

From a design point of view, even classes for whom you only expect to have a single instance within a running program are better implemented as object classes where you use an object to mediate everything it controls rather than a static class you don't instantiate. This is true in Java/etc and it would be true in Perl.

Where logically you must not have multiple instances or a singleton, you just accomplish this by not having any instance-specific slots and all slots are declared shared, or declared in class/package scope with my.

All construction methods in a class would have a $self with all the slots already available and with appropriate type-specific default values, which is undef by default.

Factories are just ordinary classes you first instantiate or select an object of and then use a method on that to create the object you actually want, or alternately Factories are non-object packages with normal subs.

So this normalizes the Perl code including that all methods are called with the same syntax and all methods reliably have a $self.

@duncand
Copy link

duncand commented Feb 22, 2021

Following my prior comment, this change should benefit users of otherwise static classes or packages making things more terse without relying on exporting/importing.

Instead of this:

use FooBarBaz;
FooBarBaz::a();
FooBarBaz::b();

You can have something like this:

use FooBarBaz;
my $fbb = select FooBarBaz();
$fbb->a();
$fbb->b();

This is also a good basic design in classic Perl 5 to normalize all code on OO syntax even when conceptually you don't have object instances.

This way you consistently use -> for calls, avoiding problems with ::, and you avoid repeating possibly long package names everywhere and without using importing/exporting.

@Ovid
Copy link
Collaborator Author

Ovid commented Aug 15, 2021

This is resolved for the MVP. Further issues should be new tickets.

@Ovid Ovid closed this as completed Aug 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feedback Cor Proposal Feedback
Projects
None yet
Development

No branches or pull requests

4 participants