Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Private attribute in class makes typed public attributes undefined

Tags:

raku

I'm writing a class that looks like this:

class ListenSocket is Tap {
    has         $!VMIO;
    has Promise $.socket-host;
    has Promise $.socket-port;

    method new(&on-close, Mu :$VMIO, Promise :$socket-host, Promise :$socket-port) {
        self.bless: :&on-close, :$VMIO, :$socket-host, :$socket-port;
    }

    submethod BUILD(Mu :$!VMIO) { }
}

When I try to construct the class with defined Promises for $socket-host and $socket-port, their attributes in the class end up becoming undefined for whatever reason. What can I do to fix this?

like image 782
Kaiepi Avatar asked Oct 08 '18 06:10

Kaiepi


People also ask

Should class attributes be private?

A private attribute provides you a level of protection from the users of your class, for that attribute. If you use a public attribute, you will need to add in more logic to test for invalid values up front, which can be more work, as well as more computationally expensive.

Can attributes be private?

In many object-oriented languages, certain attributes can be declared as private, making it impossible for users of a class to directly view or modify their values. The designer of the class then provides methods to control the ways in which these attributes can be manipulated.

How do you define a private attribute in Python?

Here in Python, we can make an attribute private by adding 2 underscore characters _ in front of our variable name. Here, instead of using name , we use __name as our variable.

Why is it recommended to keep the class attributes private?

By defining the class members' private , we can protect the data from accidental corruption. The following are the benefits of encapsulation: Protection of data from accidental corruption. Specification of the accessibility of each of the members of a class to the code outside the class.


1 Answers

I should have started off with what Liz wrote. Switch BUILD to TWEAK. Then the default BUILD will do its thing and your socket attributes will get correctly initialized.

The next problem is &on-close. See Lizmat's answer to Constructors in subclases showing how to deal with that if you can modify the superclass (Tap in this case) or Jonathan's authoritative answer to Inheriting private attributes in Perl 6 (which is about any access whatsoever to another class's attributes) showing you're out of luck if you can't modify the superclass.


Note that the above two issues aren't really about "private attributes" in a class making "public attributes" undefined. Nor are types relevant.

All attributes are technically private. The private/public distinction is about whether there's a public accessor for a private attribute.

Your custom BUILD is only initializing $!VMIO, the one that doesn't have a public accessor. You have neglected to initialize $!socket-host and $!socket-port, the attributes that do have public accessors (due to use of the public accessor twigil . when declaring them).

You presumably wrote a custom BUILD because the default BUILD only initializes attributes with public accessors. But if you do that you are taking on full responsibility for object construction and you must initialize all attributes that you want initialized.

It's better to write a TWEAK. Then you can just deal with the attributes without public accessors. A TWEAK just adds further initialization to the BUILD, which for the default BUILD is just initialization of the attributes with public accessors.

like image 123
raiph Avatar answered Jan 04 '23 12:01

raiph