in reply to Some thoughts on Moose Attributes

Or perhaps $self->input_line_number(1+$self->input_line_number);. But, recall that the ++ syntax is beloved by millions and for a reason! It is quite a bit out of the way to not be able to manipulate things in-place.

I've made that same observation here several times, and it is one of the reasons that underlies my earlier response on a similar topic. In particular, the last couple of paragraphs.

The oft noted problem with lvalue setters is that, as implemented in Perl 5, you cannot validate the value assigned. But, this is only really a problem if you have public setters for attributes, where you do not have control over the code that will do the assignment.

As previously discussed, I don't allow public accessors. Which means that any values that get assigned to attributes come into the object as (or are derived from) the arguments to public methods where I have the opportunity to validate them before setting them into the attributes. This means I do not have to waste cycles by having the setters validate the values every time they are set.

External values are only validated as they transition the public/private boundaries. Internal code that modifies attributes is under my control, and can be validated by testing during development thereby avoiding the overhead of continual revalidation during production runtime.

Of course, once you do away with the need for runtime validation of individual attributes, then the need(*) for internal use accessors disappears also, which leaves you directly accessing the attributes internally and doing away with another layer of subroutine call and so benefiting performance even further.

(*)Of course, some will argue that you should use accessors rather than direct access internally anyway. Because, they will suggest, this allows you to isolate the internal code from future changes in the structure of the attributes.

I believe this to be a justifiction. Here's why. Let's say you have a piece of code in a method that does:

class Xyz; attribute x; attribute size; someMethod( arg, ... ) { ... assert( arg > x && arg < y ); ... x = ( x * arg ) % size; ... }

With internal accessors you might, at not inconsiderable cost, write that as:

class Xyz; attribute x; attribute size; someMethod( arg, ... ) { ... assert( arg > x && arg < y ); ... self->set_x( ( self->get_x() * arg ) % self->get_size() ); ... }

But the question is, what does that buy you that is worth the cost? In what way could x change in the future such that the change to x would not require the code that uses x to be modified also?

I've still yet to see a good example of a case where using internal accessors. allows the nature of the attribute to change, without also requiring change to the code that uses them?


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re^2: Some thoughts on Moose Attributes
by John M. Dlugosz (Monsignor) on May 01, 2011 at 17:04 UTC
    If I understand you, the (only) reason against having lvalue accessors is because it can't run the validation, coersion, triggers, etc. on a SET.

    Meanwhile, you say none of that is necessary on private data anyway.

    But, the representation of the class is opaque. I can't get at the slot without going through the MOP or inline functions generated by the MOP.

    Does the average class need to have complete freedom to separate instantiation representation from the class? That's akin to the 'tie' feature in classic Perl 5, and agree that this is better served using abstract interfaces. I won't be changing the "bits" suddenly to a different implementation. Hmm, or will I? In Perl 5.xx+ maybe an efficient XS-based slot mechanism will be added to some platforms, and my existing classes and most of CPAN and all the Catalyst stuff should just work and suddenly work faster! So, maybe I want to keep my options open just now.

    Now roles on the other hand can be added to any kind of class, and can't assume the storage layer in use by whatever class it winds up in. So it should be more abstract, unless it's app-specific and knows something about where it's going.

    So, maybe you and I would both like a lvalue option. Declare my private instance data with some keyword or something that makes it generate an lvalue accessor for combined get/set usage, with no init-arg, type check, etc.

    Another idea would be a Moose implementation layer that guaranteed a certain naming convention among its use of hash keys, and was known to be a blessed hash. Then you could add your own instance data among the $self->{keys} in the classic manner. You would define that you wanted that implementation metaclass (whatever it's properly called in Moose) when you created that class.

      In Perl 5.xx+ maybe an efficient XS-based slot mechanism will be added to some platforms, and my existing classes and most of CPAN and all the Catalyst stuff should just work and suddenly work faster! So, maybe I want to keep my options open just now.

      Hm. That seems like a prime example of the whatifitis I've been decrying elsewhere :)

      Without claiming any great expertise in XS, the idea that calling an XS subroutine to access a variable could ever be quicker than a direct hash element look up doesn't seem at all feasible, let alone likely.

      I guess using internal accessors would (in Perl) facilitate changing the blessed reference type from hashref to arrayref. Or possibly vice versa, though a reason for doing the latter doesn't instantly spring to mind. But the main reason for switching from a hashref to an arrayref is performance. Array lookups using constant subs is a tad quicker than hash lookups.

      But if performance is the reason for the change, then you'd achieve greater gains by dropping the accessor methods and going direct to the hash.

      The only other reason I can think of for why you might consider the switch from hashrefs to arrayrefs is to reduce storage requirements. But if you have a class that has sufficient instance attributes to make that switch significant on a per-instance basis, then there is something cock-eyed with your design anyway. And if you are using sufficient individual instances of a given class to make the combined storage requirements of the instances worth switching, then you should be using an aggregate rather than individual instances anyway.

      So, maybe you and I would both like a lvalue option.

      The only half-good reason (that I can see) for using lavlue accessors for private attributes is the simplified syntax. $self->x++; is nicer than $self->{x}++; or $self->[X]++;.

      And for non-performance critical classes that would, indeed has been, sufficient reason for me to use lvalue methods.

      Now roles on the other hand can be added to any kind of class, and can't assume the storage layer in use by whatever class it winds up in. So it should be more abstract, unless it's app-specific and knows something about where it's going.

      My thought processes come a little unstuck when it comes to Roles. Basically, I haven't used them.

      The main disadvantage of composition relative to inheritance is that where the latter allows $self->superclassMethod();, the former requires $self->{compositeObject}->method();.

      I mostly see Roles as a way of avoiding inheritance whilst avoiding the double indirection required by composition. In that scenario, the internals of the Roles class are (by my rules) entirely transparent to and inaccessible from the incorporating class. That is, there doesn't seem much point in incorporating a Role into a class, if the class needs to manipulate the attributes within the Role directly, The class might just as well declare an instance and manipulate it. The Role needs to provide methods that do things to or with the state they incorporate, otherwise there is little purpose in them.

      And that brings me to the thorny issue of the Role operating not on its own internal state, but rather on the attributes of the class into which it is incorporated. This, on the surface at least, appears to be a useful possibility.

      And as far as I can see, there are 3 ways a Role could be written to have access to its peers attributes:

      • It could require that its peer use well-known names for any state and/or methods that it needs to access.

        Whilst simple to implement, it seems that this would be a particularly crude way to go about it. Whatever names were chosen might make sense in terms of the generic Role, but no sense at all in terms of the classes that use that Role. It is easy to see that a method provided by a Role might have a positive connotation in one calling class but a negative connotation in another. And if the Role specifies a neutral 'well-known name' then you end up with the worst of all worlds where it makes no sense in the contexts of either type of using class.

      • It might be possible to it by introspection.

        Though it would still need to know what methods to look for, so I see no advantage in that.

      • Or the using class could provide either names or references (delegates) to the Role's constructor.

        This seems to be the 'best' method (I can think of), but do Roles have constructors?

      As you can probably tell, I'm not really up with how Roles are actually implemented. Or used for that matter. I did start to look into their implementation in Moose once a while ago, but the complexity left me cold. Not so much that I couldn't follow it through all the layers--though it was definitely tough going in several places. Mostly, I just got disheartened to see just how much complexity was involved to achieve something that I can implement myself using standard Perl in a couple of dozen lines.

      As you've probably worked out by now, I'm not, nor ever likely to be, a Moose user. But I'm not critical of Moose. If you need its facilities, or can llve with its costs for your application, then it is an absolutely amazing piece of work with some major benefits, especially for Perl/OO beginners.

      I just don't happen to fit into any of those categories.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        As you've probably worked out by now, I'm not, nor ever likely to be, a Moose user.

        Holy Crap! Really!!! Now it all makes sense! ;)

        But I'm not critical of Moose.

        Kinda, sorta, not really. But that is okay, we can take it, nothing should ever be above criticism. Perl is built on the foundation of TIMTOWTDI, which means that the language itself is flexible and can very easily be different things for different people.

        -stvn
        I guess using internal accessors would (in Perl) facilitate changing the blessed reference type from hashref to arrayref. Or possibly vice versa, though a reason for doing the latter doesn't instantly spring to mind. But the main reason for switching from a hashref to an arrayref is performance. Array lookups using constant subs is a tad quicker than hash lookups.
        I recall in the earlier days of Perl 5 there was an array-based mechanism added that pre-compiled the slot names into indexes. That was indeed faster, but it was deprecated and removed due to some issues I've forgotten.

        There may be more experiments later, with Perl-6 lust and current work in moving parts of Moose to XS. Abstraction opens up all possibilities.

        Hm. That seems like a prime example of the whatifitis I've been decrying elsewhere :)

        Without claiming any great expertise in XS, the idea that calling an XS subroutine to access a variable could ever be quicker than a direct hash element look up doesn't seem at all feasible, let alone likely.

        I was thinking more along the lines of intrinsic support, using a mechanism like Perl 6. But furthermore it might be available on some platforms and not others, or use XS to backport some of the higher stuff to other versions so the same support _seems_ to be there but is not as snappy.

        Maybe I'll load a Perl 5 Moose-based module into a Perl 6 program.

        You digressed a bit to talk about Roles...that could be a new topic. I know Roles (in the abstract sense) quite a lot better than I do about Moose. One of the things you mentioned makes me ponder a bit, but my meditation queue is a bit long already.

        (I've also noticed how delegation makes aggregation much cleaner to use. So... if the Role doesn't mess with the containing object, just use delegation and containment. Using 'handles' you have the clean syntax without mentioning the composited object.) Why am I likely to remain a Moose user?

        For the same reason that Perl's best feature is CPAN; Moose has "community support". It does do things for me that I've gotten benefit from, and many new features and different ways of approaching things is already published and ready to reuse.

        Also, major packages like Catalyst and FormFu are Moose-ified, so if I will monkey around with those I need to know what I'm doing.

        So, you didn't comment on the second of my ponderables: can Moose live with direct access to state as hash elements of $self?

      Does the average class need to have complete freedom to separate instantiation representation from the class?

      As an implementor, I answer wholeheartedly yes.

      The naïve implementation of an object system in Perl 5 (stolen almost whole cloth from Python) actively presentsprevents many simple and nearly all clever optimizations. Decoupling representation from behavior at the class or metaclass layer would allow gradual and progressive optimizations for memory usage or compatibility with C data structures or persistence mechanisms or JIT with much less work (and much, much less cleverness) than doing so with the simple hash-based lookup mechanism currently in place in Perl 5.

      In the Moose API, compatibility with existing classes is probably more of a concern.

        (stolen almost whole cloth from Python)
        Really? I had no idea!
        As an implementor, I answer wholeheartedly yes. The naïve implementation of an object system in Perl 5 (stolen almost whole cloth from Python) actively presents many simple and nearly all clever optimizations. Decoupling representation from behavior at the class or metaclass layer would allow gradual and progressive optimizations for memory usage or compatibility with C data structures or persistence mechanisms or JIT with much less work (and much, much less cleverness) than doing so with the simple hash-based lookup mechanism currently in place in Perl 5.

        Sorry, but that is tantamount to the single most dishonest thing I've ever seen expressed on PerlMonks!

        I usually refrain from trying to predict the future, but: It ain't never gonna happen. Any of it.

        You don't need to implement the whole solution to prove me wrong. Just a single demonstration of method call being faster than a hash lookup in Perl 5.

        Implement the extension/optimisation in any language you like, but I bet you cannot return a previously set value, to perl via method call, quicker than it can be retrived from a hash.

        Note: I'd really like you to prove me wrong. Because such an optimisation could be very beneficial in almost every area of perl.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.