p5-mop-redux icon indicating copy to clipboard operation
p5-mop-redux copied to clipboard

attribute defaults should have the invocant in $self, not $_

Open doy opened this issue 12 years ago • 23 comments

doy avatar Oct 15 '13 14:10 doy

I dunno, I think $self outside of method bodies is really strange, I actually like $_ personally.

stevan avatar Oct 15 '13 14:10 stevan

It follows perl 6:

$ perl6 -e 'class Foo { has $.foo = self.build_foo; method build_foo { 1 } }; say Foo.new.foo'                                               
1

doy avatar Oct 15 '13 14:10 doy

Yes and no, in Perl 6, $self is spelled self which gives it a very different feel

stevan avatar Oct 15 '13 14:10 stevan

p5-mop could provide a self keyword for the invocant just like Perl 6 does.

An issue with this is how self would work with closures. p5-mop could also provide syntax to explicitly declare the invocant within a method (again, just like Perl 6) for those times when you need a var to close over: method foo ($self: @other_stuff) { ... } This also has the advantage (IMHO) that no specially-named scalars are magically appearing in scope; the programmer either declares a name or uses the self token.

perlpilot avatar Oct 15 '13 16:10 perlpilot

The more I think about it, the more I do kind of like self instead of $self. Having variables magically spring into existence without being declared is weird.

doy avatar Oct 16 '13 22:10 doy

I am not against this

On Oct 16, 2013, at 6:55 PM, Jesse Luehrs [email protected] wrote:

The more I think about it, the more I do kind of like self instead of $self. Having variables magically spring into existence without being declared is weird.

— Reply to this email directly or view it on GitHub.

stevan avatar Oct 16 '13 23:10 stevan

+1 on self() ( and arguments() ) to match caller()...

nicomen avatar Oct 18 '13 03:10 nicomen

arguments() gives me Javascript flashbacks, so I am not so sure about it. Also @_ is a core part of Perl anyway, whereas $self is not.

stevan avatar Oct 18 '13 12:10 stevan

My +1 would go to $self. It works inside closures (including Try::Tiny, Log::Contextual, and all other internal or external uses of the (&) prototype. It is always consistent (map { self->foo($_) } ... vs. mymap { $self->foo($_) ...). From a semantics and usage side, a lexical is the more simple, easy and understandable solution.

If the invocant variable has to be specified in every signature explicitly, then I have to add $self: to every signature if I want to be consistent across the project, because I usually use a couple closures. This takes a bit away of the visibility of having a changed invocant variable (method ($x) vs. method ($class: $x)).

If a self keyword is desired, how about it is provided along with a $self variable? Then you have the best of both worlds.

My main confusion however is this: What does the keyword variant buy you that a lexical doesn't, besides having to write one less character? Not to mention that I find it more odd to have a lower-case keyword to access a simple value that is only available in a specific scope. I'd expect something like that to look like like SUB.

phaylon avatar Oct 18 '13 14:10 phaylon

@phaylon - the advantage of self is simply that it is not injecting a variable, to be honest, I prefer $self too, but I can see the logic in going with self.

stevan avatar Oct 18 '13 14:10 stevan

The main reasons are that nowhere else in the language does a lexical variable spring into existence without having been explicitly declared somewhere, and that perl 6 uses self by default (and we've been trying to follow perl 6 syntax when reasonable).

doy avatar Oct 18 '13 14:10 doy

But is it worth all of the above? In all my uses of syntax extensions on CPAN providing an implicit invocant lexical, I never longed for it to be a keyword instead. I would find it rather odd to refactor my signature and other invocant uses just because I want to use Try::Tiny. Also, other single scoped value access keywords in Perl 5 look like __SUB__, not like undef().

With regards to Perl 6, I'm trying to make the case that it might not be reasonable to complicate the semantics and make a fully consistent usage more wordy. How does Perl 6 deal with the issue of closures for example?

phaylon avatar Oct 18 '13 14:10 phaylon

I think if self didn't work for thing as simple as Try::Tiny then it is a deal breaker and we stick with $self, but I am not sure that self won't work fine with Try::Tiny.

stevan avatar Oct 18 '13 14:10 stevan

I think it would be favorable to have it work in all closures. Meaning you can go from map { self->foo } ... to my_parallel_map { self->foo } ... to my_iterator_map { self->foo } ... (note that the last one might return something that closes over self, which might be invoked in the methods of different objects. It would basically have to turn self into a lexical-variable-masked-as-keyword, which we also don't have yet in Perl 5.

phaylon avatar Oct 18 '13 14:10 phaylon

@doy, @phaylon makes some really good points here, just sayin'

stevan avatar Oct 18 '13 14:10 stevan

I imagine things like Try::Tiny would continue to work, because the closure is invoked immediately. The case that wouldn't work without marking something explicitly would be somewhere where you want to return something that closes over $self.

doy avatar Oct 18 '13 14:10 doy

There's also the case of closing over self in something you pass on:

self->_find_items(sub { self->_item_is_blue($_) })

Since that might or might not be executed by a method on the same object. It could also be delegated to a container object managing the items.

phaylon avatar Oct 18 '13 15:10 phaylon

I don't get it, if you want to close over, you close over it, you don't call a unclose-overable method/keyword from inside the block...

nicomen avatar Oct 25 '13 04:10 nicomen

The thing is, if you can't close over it at all, it severely limits it's use. If you can only close over it sometimes, it makes the matter more complicated.

phaylon avatar Oct 25 '13 20:10 phaylon

I'm still not entirely sure that "you can close over it when you declare it" is too complicated, although I could be wrong.

doy avatar Oct 25 '13 20:10 doy

My issue is, if I start out with using the keyword variant and suddenly have to close over it I have two choices: use both variants in a single method, or have a commit that changes large parts of the method for possibly just a single line. I'd just prefer to have a default, simple way to access the invocant without having to be explicit in every signature.

phaylon avatar Oct 25 '13 20:10 phaylon

Gotta continue to agree with @phaylon, if you can't easily close over it, and have to do extra work in order to do that, thats a no-go for me.

stevan avatar Oct 25 '13 21:10 stevan

Another data point here is that we need to be able to close over attributes themselves, which effectively means implicitly closing over the invocant without the invocant necessarily explicitly existing (for instance, class Foo { has $!bar; method baz { return sub { $!bar } } }). So a lexical version of the invocant is going to need to exist regardless of what we decide otherwise.

doy avatar Nov 06 '13 22:11 doy