https://github.com/Ovid/Cor/blob/master/rfc/overview.md#24-rationale
]]>I mean, why can't we have this (which IMHO sticks to the principle of least surprise):
method do_internal :private (...) {...}
and then have it implemented with whatever mechanism that is deemed better, e.g. lexical immutable thingies in a glass safebox under the sea.
I can only think of a trade-off in efficiency (both lowercase perl programmer-wise and lowercase perl-wise), because that would probably require revising how method resolution is performed today and have this resolution go through a private list first, then a public one, in lack of a way to distinguish a private and public method at the time of calling (which seems something that programmers would be happy to hand over to the compiler/interpreter, I guess).
]]>$object->&method_name
to call a lexical sub (my sub method_name
). This fits more with traditional perl OO, but it should be possible to extend to Cor methods.
]]>
class A { has $x;my sub _print_x() { # private method
say "x value for $self is $x";
}method print_x() {
_print_x(); # calling it, no dispatching required!
}
}
Alternatively, using
my method {...}.
The issue here is how you call a private method on a different object of the same class, but well, the same problem exists for accessing slots.
]]>Actually, the same logic can be applied to public methods too as in the following code:
class A { method foo() { ... }method bar() :private { ... } # or whatever syntax you want to
# use to signal bar is privatemethod doz() {
foo(); # method foo can be invoked as a sub,
# $self can be inferred from the contextbar();
}
}my $a = A->new();
$a->doz(); # ok
$a->foo(); # ok
$a->bar(); # fails!
The point remaining is how you call a private method on an object of the same class... Maybe using "&" to disable the special method calling.
class B { method bar() :private { ... } # or whatever syntax you want to # use to signal bar is privatemethod doz($other) {
bar();
&bar($other)
}
}
IIRC, perl does subroutine look up at compile time*. For instance, that's how arguments for subroutines with prototypes are parsed in accordance with the prototype.
So, extending it to also look for methods declared on the current class scope or up in its parents, doesn't seem too complex, and the runtime penalty is zero.
Regarding whether it is better to require the explicit $self->method() syntax. Well, I can see both pros and cons. As you say, it allows one to distinguish method calls from sub calls but on the other hand, not requiring it would result in more concise code.
Also, the same argument could then be applied to slots and so, being able to access object slots as regular variables shouldn't be allowed. Actually, my experience programming in other languages where slots and methods can be referenced without stating the object (Java, C++) is that the troublesome ones are usually not the methods but the slots.
* well, it tries to do the look up at compile time and if that fails, in some cases, it tries again at runtime.
]]>Well, I think this is just a semantic issue, but by lookup I was referring to the operation of traversing one or several tables containing mappings between names and the subroutines (currently, the package stash or the lexicals table) which is an expensive operation.
Perl does not store CV pointers directly on the OP tree, but the globs (GVs), so that operations like the one you describe above are possible, but accessing the CV slot of a GV is very, very cheap.
Regarding the second point about the importance of calling methods as $self->method, I still fail to see why it is important to differentiate sub/method calls **inside** a class, but it is ok to use the same syntax for lexicals/slots which are much more prone to collide.
]]>I think that is exactly the point where we disagree. I see them as different constructs but their interface and behaviors are so similar, that the same syntax can be used for both.
Also, there are several programming languages that use the same syntax for both, C++, C#, Java if you take its static methods as subs, Common Lisp/CLOS uses the same syntax for everything (mehtods, functions, generic functions, macros, accessors, etc.). Admittedly all this programming languages have their issues... but I never heard anybody say the overloaded subroutine call syntax was one of them.
I have to admit that for me, they real issue I have with supporting $self->private_method is that I see lots of issues at the implementation level.
For instance, what happens when you have two classes A and B so that B derives from A and both are implementing a private method with the same name. Just try to image in the following code how perl could resolve the method "foo" in every case:
class A { sub foo() :private { ... }sub bar() {
my $b = B->new();
my $c = C->new();
return $self->foo + $b->foo + $c->foo;
}
}class B extends A {
sub foo() :private { ... }sub doz() {
print "I use ".foo()." for something completely different!"
}
}
In any case, I think that going for $self->&private_method solves all of them too!
]]>return $self->foo # A::foo() called + $b->foo # Can't call private B::foo() outside class B + $c->foo; # C::foo() if public, otherwise exception
Oh, no, it is not that simple! The right think to do there is to call A::foo on $b as $b is of class A too. Otherwise you are requiring the B programmer to know about the private methods up the hierarchy class in order to avoid reusing their names.
In order to support that, it is not enough to have a-per class table mapping method names to CVs. Now, the interpreter would have to check at runtime for every call to a method having the same name as a private method if the object is of the class being declared and if so, redirect the call to the private method.
It can even be worse: Perl supports calling methods using the $self->$method syntax and that would have to play nicely with private methods too. So, for every $self->$method call, the interpreter would have to check whether a private method with the name in $method exists in order to call it or fallback to the public method.
]]>Yes, exactly, that's the only possible "right" behavior for private methods if for private you want to mean that they are completely invisible from outside the class where they are defined.
No, we are requiring all programmers not to attempt to call private methods on objects from outside those object’s own classes
Yes, but the issue there is that in general a programmer implementing a class B derived from A, doesn't necessarily have to know which private methods are defined in A (or in its parents). So, he could unintendedly add to B a method with the same name as some private method of A. Or a private method with a colliding name could be added in a later version of A.
IMO that is not a critical issue. Actually, the current practice of using a double underscore prefix to signal private methods is affected by it, people writes effective code in Perl and the collisions are very rare (but also, very unexpected). It is just that if you are designing a new OO extension to the language, I think you should try to account for it at least and try to avoid it.
That anything one might want to do via a private method would be much better done via a lexical subroutine.
And that was what I was trying to say in my initial reply. But then, the issue is that lexical subs don't have access to the object state. They only can access the object through its public interface. That's a severe limitation and, probably, most programmers would keep using the double underscore prefix convention for private methods.
... unless you give lexical subs the ability to access the object state directly. At the end, it is just a matter of scope.
For instance...
class A { slot $x;method inc() {
$x++;
return sub {
--$x;
}
}
}
I hope I am not the only one that would expect that closure over the slot $x to work, so, why not this one below?
class A { slot $x;my sub _dec {
--$x;
}method dec() {
_dec();
}}
After all, $x is in scope when _dec is declared.
]]>Yes, and there are other issues. AFAIK, supporting class methods is planned (tagging then with :common) and lexical subs should be callable from those, and that creates several edge cases that could be quite difficult to support.
class A { field $a :common; field $b; my sub priv { eval '$a + 1'; # which fields are visible from this eval? # depends on whether priv was called from # foo or from bar! } method foo :common { priv(); } method bar { priv(); } }
So, I think that declaring explicitly those subs as methods would simplify everything both at the conceptual and implementation levels:
my sub { ... } # no field access allowed my method { ... } # access to all fields allowed my method : common { ... } # access to class fields allowed
So, the issue remaining is how to call those subs/methods...
And our ongoing disagreement on the correct semantics for them leads me to conclude that the only reasonable approach left is:... $self->&increment_counter(); # Lexical method call syntax ...
Let me start by saying that I would be happy with that solution as I think it provides the correct semantics for private methods.
It is just that I think it is quite ugly and doesn't really blends well in the language. At least for me, "->" means method dispatching and "&" means subroutine and more specifically to strip a sub of any special behavior. Private (lexical) methods are not dispatched, and we are calling a method, not a sub... I think the only positive point for that syntax is that it is available!
After all, it would just be a fancy way to write "increment_counter($self)". So, why do we need it?
And at that point, if it was ok for you to have lexical subroutines with access to the object fields as in...
class A { field $x; my sub _inc { $x += 1 } method inc { _inc } }
Is not ok to just do the same with lexical methods?
class A { field $x; my method _inc { $x += 1 } method inc { _inc } }
So that the keyword "method" means it has access to the object/class fields and "my"/nothing controls whether the sub/method goes into the stash becoming callable through "->".
And the only special behavior of private methods is having the $self/$class object being passed implicitly at the call point (which could be disabled using & as in "&_inc($other)").
]]>Isn’t the answer simply “none”? It seems a trick question. Fields aren’t visible inside a sub
, whether it’s lexical or not, no?
Isn’t the answer simply “none”?
Yes, that was the conclusion: it is not a good idea to let lexical subroutines, declared at the class top level, access the object fields.
It seems a trick question. Fields aren’t visible inside a sub, whether it’s lexical or not, no?
Well, IMO, they should be visible if the sub is declared inside a method. For instance, I would expect the following code to work:
use Scalar::Util qw(first);]]>class A {
field $x;
method foo(@args) {
return first { $_ > $x } @args;
}
}
Well, yes, obviously, a closure is a different kind of situation. The question would be what happens in a named sub declared inside a method – where I would expect the exact same behaviour that the “variable will not stay shared” warning cautions against currently. And I would expect the use of a lexical sub to cure the problem, the same way it currently does for regular subs.
]]>has been supported by Zydeco for over a year. documentation.
]]>