Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Encapsulation through stringification - a variation on flyweight objects

by robartes (Priest)
on Apr 01, 2003 at 22:17 UTC ( [id://247369]=perlmeditation: print w/replies, xml ) Need Help??

Most of us are familiar with the term 'flyweight objects' in Perl OO speak, which refers to objects where the blessed thingy is a scalar that is the index into something (a hash or array) containing the object's attributes. This container is lexically scoped to a bare block in the package implementing the object's class, thus providing fairly strong encapsulation.

One way of subverting this encapsulation is a basic 'identity switch' job. A flyweight object does not carry its own attributes around, but it does carry an index around. This index can be modified to take on the identity of some other object in the same class. One way of getting around this is simply making the index harder to guess by randomizing it.

While idling away at the keyboard tonight, I came up with what might be another way of strenghtening the encapsulation in flyweight objects: instead of having the object carrying an index around, have the object be its own index:

package Camel; { my %camels; sub new { my $class=shift; my %args=@_; my $self={}; bless $self, $class; my $key=qq/$self/; $camels{$key}={ %args }; return $self; } } 1;
As you see, the index into the attribute container is a stringified version of the blessed reference itself. The blessed reference is just an empty anonymous hash, so there's no longer an index to play around with. The object is empty - to get at the attributes, you would have to write accessor methods inside the scoping block of package Camel. Encapsulation!

Am I missing something here? Can anybody poke some holes in this? And if not, can anybody come up with a nice name for this little gimmick ;) ?

CU
Robartes-

Replies are listed 'Best First'.
Re: Encapsulation through stringification - a variation on flyweight objects
by Abigail-II (Bishop) on Apr 01, 2003 at 22:27 UTC
    That's what I am already doing with Inside-Out objects.

    There are some problems though. First, you have a memory leak. If an object goes out of scope, you aren't cleaning up the attributes. To do so, write a DESTROY function (just like with Inside-Out objects). Second, you'll get a problem if you want to overload stringification.

    Abigail

      I thought it would be a bit too much to have been the first to think of this <g>. I had super searched but not on 'Inside-Out objects'.

      I know about the memory leak, I have not included a DESTROY method as this was just an example (the same reason I have not included any accessors, or attribute validation). It's still a valid point though.

      Stringification overload is indeed problematic. One hole poked ;).

      Thx for the comment.

      CU
      Robartes-

        BTW, you can overload stringification /or/ numification just fine, but not both.


        Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Re: Encapsulation through stringification - a variation on flyweight objects
by dragonchild (Archbishop) on Apr 01, 2003 at 23:18 UTC
    Personally, I think that going for this kind of hard encapsulation is self-defeating. The whole point of OOP is to decouple your code. If your colleague is violating this decoupling, then it is incumbent upon you to educate your colleague. Education is better done non-coercively. If your colleague refuses to learn, quit. Life is too short and, despite the general slowdown, the jobs are out there.

    If you're providing a module for general consumption, you don't have to do B&D development. This is not consistent with the culture of the entire LAMP model. If someone abuses your appropriately-documented interface, that's their problem, not yours. It's your job to make your stuff mistake-proof, not fool-proof. Fools are infinitely more cunning than any of us can ever be.

    Now, this form of implementing flyweight objects is flyweight only in the creation and memory usage (and if you're using stringification of hashrefs as your index, you don't even have that benefit).

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      Personally, I think that going for this kind of hard encapsulation is self-defeating. The whole point of OOP is to decouple your code. If your colleague is violating this decoupling, then it is incumbent upon you to educate your colleague.

      We've had this discussion before but I just can't let it go :-)

      I agree when the violation is deliberate. The problem with the "normal" perl OO model is that you can interfere accidentally with "private" methods and attribute.

      Even if they completely stick to the documented API they can be bitten if there is a change to the private implementation if it is done in the naive perl OO style.

      The good news is that, in my experience, it doesn't happen very often. However, I'm still very much looking forward to being able to get around this nicely when perl6 hits the streets.

        The problem with the "normal" perl OO model is that you can interfere accidentally with "private" methods and attribute.

        This kind of assertion demands an example. I humbly await your response.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

(dkubb) Re: (1) Encapsulation through stringification - a variation on flyweight objects
by dkubb (Deacon) on Apr 02, 2003 at 13:59 UTC

    A couple of years ago I wrote a module that tried to implement the Flyweight pattern in perl, and submitted it for Code Review. I had originally planned to release it to CPAN, but reconsidered after I thought more about it. Looking at the code now, there wasn't much advantage to using my module versus just implementing it in modules that need it. Besides, my approach didn't really provide any real encapsulation of the data since it just returned the full data structure to the caller.

    However, I still believe it can be a useful approach if data encapsulation is important to you.

    In addition to the points Abigail-II identified (no garbage collection after the object goes out of scope, and inability to handle overload stringification) I'd like to add that you're $self doesn't need to be a blessed hash. Since you're only using the blessed hash's address when it's stringified as your object identifier inside the flyweight hash, you could use any type of blessed variable. In this case I'd recommend a simple blessed scalar, which would have less memory consumption and is cleaner IMHO.

    Below is a sample class that deals with all three of the issues. It uses overload's StrVal() function to get the scalar's address, bypassing string overloading. (However, I'd only recommend doing this if you actually are using string overloading, for performance reasons):

    package Flyweight; use strict; use overload (); { my %flyweight; sub new { my $self = bless \my $scalar => shift; # do other things to set up the object return $self; } sub get_attribute { my $self = shift; my $value = $flyweight{ overload::StrVal($self) }{attribute}; # do something to $value return $value; } sub set_attribute { my $self = shift; my $value = shift; # throw an exception if $value doesn't meet constraints $flyweight{ overload::StrVal($self) }{attribute} = $value; return; } # clean up the object when it goes out of scope sub DESTROY { delete $flyweight{ overload::StrVal(shift) } } } 1;

    Dan Kubb, Perl Programmer

Re: Encapsulation through stringification - a variation on flyweight objects
by dws (Chancellor) on Apr 02, 2003 at 18:20 UTC
    Most of us are familiar with the term 'flyweight objects' in Perl OO speak, which refers to objects where the blessed thingy is a scalar that is the index into something (a hash or array) containing the object's attributes.

    I happened to re-read the Flyweight pattern a few nights ago, and that description doesn't quite do the pattern justice. People often assume that "flyweight" means "small", since the point of the pattern is to separate intrinsic from extrinsic state such that objects that carry only intrinsic state (i.e., flyweights) can be shared multiple times. A common optimization is to have the flyweight hold an index into an attribute table, but important distinction is that attributes can't refer to state outside of the object itself if that reference would render the flyweight unsharable. Any non-shareable needs to be passed in by the client. A good test for whether you're really doing Flyweight right is to consider whether you can implement individual flyweight objects as singletons.

Re: Encapsulation through stringification - a variation on flyweight objects (see Class::InsideOut)
by Aristotle (Chancellor) on Apr 02, 2003 at 22:46 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (3)
As of 2024-03-19 04:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found