Instance data/accessor syntax: self->, $self->, $., setter(newval), lvalue setter, ?
cxw42 opened this issue · 17 comments
@Ovid I think we could productively build this bikeshed in its own lot rather than overwhelming #4 :) . Feel free to close this issue if you disagree.
There was considerable discussion in the gist about the syntax for accessing slots. Some options are listed below - vote for the ones you like! I have listed them in the order I encountered them in the gist, followed by the ones from the wiki. Apologies if I missed any! These are not necessarily mutually exclusive, so feel free to vote for more than one.
Note that we have the opportunity to use new syntax, since Cor will be written in C rather than Perl.
(For what it's worth, I have changed my mind over the last six months, so don't feel locked in to earlier discussion.)
Keyword self
: self->attribute
(possibly with self->{attribute}
as the underlying storage)
$self
as an automatically-declared variable: $self->attribute
Twigil: $.attribute
Plain lexical: $attribute
Naming convention with a plain lexical: $_attribute
(or $O_attribute
)
Special form: ${^self}->attribute
(or ${^attribute}
)
Twigil option 2: $:attribute
Twigil option 3: $->attribute
New sigil: §attribute
(or other alternative punctuation)
Position For forms other than lexical/twigil/sigil, accessors as lvalues. E.g., self->x = 42;
Position For forms other than lexical/twigil/sigil, setters take a parameter. E.g., self->x(42);
Keyword
self
:self->attribute
(possibly withself->{attribute}
as the underlying storage)
As in storing attributes in a hashref? So you keep all the things which make the current Perl OO bad?
Unless we come up with a truly compelling reason otherwise, I expect we'll stick with using lexicals and naming conventions will grow organically.
I've taken two (informal) surveys on Facebook and Twitter. Admittedly, those would be biased, but what came out of both is roughly half willing to ditch the current behavior (which is good, because that's what we're going to do), and people strongly favoring lexicals over twigils.
Currently, having a poll doesn't work because there need to be explanations of why different forms would or would not be preferred.
- Current syntax: it's actually slow (method call overhead), overly verbose, and can sometimes lead to inappropriate coupling with child classes
- Syntax which introduces even more punctuation to learn is not remotely interesting to me and might just complicate parsing (witness the difficulties of switching to a dot syntax for method calls)
- It's possible that we might use a hashref for the storage mechanism for the first pass, but that would be a disaster to keep in the long term.
- Lvalues: no. Similar issues with current syntax and the only benefit I can see is that it offers (slightly less typing) is even improved with the
has $foo
syntax. Further, it offers a different syntax for regular methods and slot methods, meaning that you can't switch back and forth between the two easily when refactoring.
Using the lexical has $x
means:
- Less concern for the parser
- No method call overhead when getting/setting
- (Longer term) Better encapsulation by not exposing data in a hashref
- It's dead simple to do
- No introduction of more punctuation
- It reads very naturally and concisely (e.g.,
has $volume :reader = $height * $width * $depth;
)
So at this point (this has honestly been a ton of work just to get Cor to this point), I am not inclined to change this part of the proposal based on a vote. I need strong, solid technical reasons why an alternative is better than lexicals.
Side note, Github has a third-party app for polls.
I'm very much in favour of using lexicals for attribute values (which for me was a major design issue when coming up with Inside Out objects).
I do have a question what has $volume :reader = $height * $width * $depth;
means. Does that get evaluated once? Each time volume
is queried? That is, is it more equivalent to my $volume = $height * $width * $depth
, or to sub volume ($self) {$self -> height * $self -> width * $self -> depth}
. The syntax suggests the former, but for an attribute, I expect the latter.
@Ovid Thanks for the explanation and summary! I'm sorry for the bother --- I didn't realize I had missed so much of the conversation. Best wishes with the design!
(Leaving open for Abigail's question above --- feel free to close once that's answered.)
has $volume :reader = $height * $width * $depth;
That's more or less equivalent to the following Moose code.
has 'volume' => (
is => 'ro',
init_arg => undef,
lazy => 1,
default => sub ($self) {
return $self->width * $self->height * $self->depth;
},
);
Thus, it's lazily evaluated once and only once. The main differences are that it's encapsulated (we don't store the data in a hashref) and it's much easier to write.