Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re: Private attributes in Perl 6 objects

by duelafn (Parson)
on Nov 02, 2015 at 14:39 UTC ( [id://1146717]=note: print w/replies, xml ) Need Help??


in reply to Private attributes in Perl 6 objects

Actually, you have it a bit backwards, get can see $!z just fine, it is the constructor which is not setting $!z (because it is private).

If you really want to allow setting a private attribute at object creation time you can use a BUILD submethod:

class Dot { has $.x; has $.y; has $!z; # Fancy syntax which simply sets each private variable. submethod BUILD(:$!x, :$!y, :$!z) { say "Initializing!"; } method get { return ($!x, $!y, $!z); } }; my $a = Dot.new(x => 23, y => 42, z => 2); say $_ for $a.get;

Notice that if you create BUILD you are responsible for handling all your attributes.

Though if $!z is private, you probably want to do some checking on it before setting (else, why is it private?). That can be done too by not using the special syntax:

# Blindly accept x and y, but do extra checks on z: submethod BUILD(:$!x, :$!y, :$z) { say "Initializing!"; die "z too big!" if $z > 10; $!z = $z; }

Of course, there are a million other ways to do validation of an attribute (some are better than this), just showing this way since it is relevant to your current investigations.

Update: Oh, and perl6 has a really smart say (ok, smart objects, but whatever), no need to loop anymore just for debugging statements: say $a.get works nicely (as does say $a.get.perl).

Good Day,
    Dean

Replies are listed 'Best First'.
Re^2: Private attributes in Perl 6 objects
by Anonymous Monk on Nov 02, 2015 at 15:37 UTC
    Hi Dean,

    thank you very much for your answer. ++ And, yes, it does work and solve the issue.

    And although I said that the get method was not seeing $!z, yes, I also suspected that it could also possibly be the constructor not setting it, but had not real way to tell the difference.

    There may probably be some good reasons for that behavior, but I find it is sort of a pity that the default new constructor can't deal with private attributes, thus forcing the user to use a lower-lever BUILD submethod, especially in view of the fact that the documentation says again and again that attributes are defaulted to private. Also this seems to lead to the fact that if I have another class inheriting from Dot (which I do have in my real case), then that subclass will also presumably need the BUILD submethod, since submethods are not inherited to the child methods, which is less practical. Well, this is just said from the tip of my mind, I have to do further testing to fully understand the implications.

    The example I gave in my original post was just a much simplified version of the code I was working on, which had quite a few other methods: this simplified code was just trying to investigate and show the problem with the smallest possible program, in accordance with the usual PM guidelines. The only reason I had public x and y and private z in this example here was not that there was anything special about z, but was to show clearly the difference between the two situations. My real aim (in my real program) was to try to build strong encapsulation for all attributes. I can see that this is quite possible, but less naturally that I was hoping it to be.

    As for your update about smarter ways to print the object's content, yes, I know and I tried them in various ways (both inside and outside the class), but, in the sample code here, I just wanted to display the list of values returned by the get method to show my problem with the private $!z attribute.

    Well, anyway, again, thanks a lot for your very useful explanations.

      All "BUILD" methods in the inheritance chain will be called, so subclasses need not know about parents:

      class Dot { has $.x; has $.y; has $!z; submethod BUILD(:$!x, :$!y, :$!z) { say "Initializing!"; } method get { return ($!x, $!y, $!z); } method getz { return $!z; } } class Dot2 is Dot { has $!w; submethod BUILD(:$!w) { say "Initializing 2!"; } method get { # No access to $!z here of course (it is private) # Also note use of public $.x, $.y not private $!x, $!y return ($.x, $.y, $!w); } } my $a = Dot2.new(x => 23, y => 42, z => 2, w => 12); say $a.get; say $a.getz;

      Good Day,
          Dean

        Thank you very much, Dean, for this additional information.

        Have a nice day.

      There may probably be some good reasons for that behavior, but I find it is sort of a pity that the default new constructor can't deal with private attributes
      Allowing a private attribute to be set via the constructor (in the way you're trying to do) effectively makes the attribute public, since it is now exposed to the outside world.

      The whole point of private attributes is that they are unknown to the outside world, so the class author can change them without affecting users of the class.

      Do you know what Tight Coupling means? Making private attributes public, and use of inheritance both guarantee Tight Coupling.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1146717]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2024-03-29 14:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found