Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^2: Class attribute handling

by Dirk80 (Pilgrim)
on Dec 12, 2019 at 15:33 UTC ( [id://11110017]=note: print w/replies, xml ) Need Help??


in reply to Re: Class attribute handling
in thread Class attribute handling

Thank you all so much. So many cool answers and that so quick. I'm impressed.

It took me a while to understand everything. Now I understood it completely and your code is working successfully.

Because my code is also using the _get_attr_data as object and not only as package, I had to rewrite the beginning of _get_attr_data. And I added another cache to this class method, so that not each time the attribute data of a inherited class has to be recomputed again.

... # Encapsulated class data my %_attr_data; # for each package: stores reference to its attrib +ute data only my %_mro_cache; my %_attr_data_cache; # for each package stores reference to its a +ttribute data + inherited attribute data # Class methods to operate on encapsulated class data sub _get_attr_data { my $caller = shift; my $package = ref($caller) || $caller; return %{$_attr_data_cache{$package}} if defined $_attr_data_c +ache{$package}; my @parents = @{ $_mro_cache{$package} ||= mro::get_linear_isa +($package) }; my %return; for my $parent (@parents) { # assure that a reference is inside $_attr_data{$parent} ref $_attr_data{$parent} or next; for my $attr (keys %{$_attr_data{$parent}}) { $return{$attr} ||= $_attr_data{$parent}{$attr}; } } $_attr_data_cache{$package} = {%return}; return %return; } ...

In this case the %_mro_cache should not be needed anymore. Because this method returns if it already handled the attribute data of an inherited package before. Is this method rewritten in a good manner?

Of course you convinced me. I'll learn Moo or Moose and stop using my concept.

Ah, and one other question. In the documentation of ref they write that a direct truth test could be wrong, because 0 which is false could be returned for a reference. Could this happen in my case? When would ref return a 0 for a reference? Would you always recommend to test against the empty string?

Replies are listed 'Best First'.
Re^3: Class attribute handling
by tobyink (Canon) on Dec 12, 2019 at 23:14 UTC

    It took me a while to understand everything.

    I do often write quite dense code, compressing a lot of ideas into just a few statenments. For example, a lot of people would do this in at least two lines of code:

    my @parents = @{ $_mro_cache{$package} ||= mro::get_linear_isa($packag +e) };

    And I added another cache to this class method, so that not each time the attribute data of a inherited class has to be recomputed again.

    Yeah, caching the hashref like you're doing is probably a good idea. A more efficient one than caching the result of mro::get_linear_isa. The disadvantage is that if _set_attr_data gets called on a class after _get_attr_data it will invalidate the cached data for that class, plus the cached data for any derived classes. I would love to sound clever and claim that's why I didn't do it that way, but honestly, I just didn't think of it!

    The invalidation issue can be easily solved by putting %_attr_data_cache=(); in _set_attr_data. Yes, this wipes out your whole cache whenever _set_attr_data gets called, but in most cases, your _set_attr_data calls will all happen early on, before _get_attr_data ever gets called, so it won't cause any practical slow downs.

    I'll learn Moo or Moose and stop using my concept.

    I mean, there's certainly nothing wrong with rolling your own as a learning exercise, but the existing solutions on CPAN offer some really good and useful features, have optimized the hell out of everything, and have already thought through all the weird edge cases and gotchas.

    As well as Moose and Moo, consider Class::Tiny if you need a really light solution, even lighter than Moo.

    Moose and Moo each have a fairly interoperable syntax, though there are minor differences. Class::Tiny differs quite a lot in syntax but it interacts pretty well with Moo (and Moose? Not sure!) in terms of inheritance. You can write a base class with Class::Tiny and derived class with Moo, and things should "just work".

    In the documentation of ref they write that a direct truth test could be wrong, because 0 which is false could be returned for a reference. Could this happen in my case? When would ref return a 0 for a reference? Would you always recommend to test against the empty string?

    ref doesn't just randomly return '0' for fun sometimes, but will do so in one very specific situation: you can create a package called '0' and bless stuff into it. But I'd argue that anybody who is doing that is probably intending for you to treat their blessed references as if they were non-references. (Otherwise they'd have no reason to choose such a bizarre package name.) So for this reason, I wouldn't normally recommend checking to see if ref returned an actual 0.

      Thanks again for your explanations!! I also invalidated the cache now at setting time. Works great. And of course I'll try Class::Tiny. It looks interesting.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (None)
    As of 2024-04-25 01:13 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found