Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

On the involuntary encapsulation violation

by bronto (Priest)
on Aug 26, 2003 at 08:38 UTC ( #286624=perlmeditation: print w/replies, xml ) Need Help??

This meditation arises from an afternoon when I discovered how bad I coded a module; I put it here as an amonishment of a bad practice that I, and others hopefully, will definitely avoid in the future.

A couple of days ago, I was playing with a module of mine that I dared to put on the CPAN. The module seemed to work so well in all previous tests I made that I was planning to put out a 1.00 version and to work on a 2.00 release that would use delegation instead of inheritance.

At a certain moment, I saw something in my application that wasn't working as expected... for some reason, an array had one more element added on its tail without any direct intervention. After peeking around the values into the array in different points of the program I concluded that the array was altered inside the module and not by the application.

What happened was that on object creation I passed a reference to the array as a parameter.

Unfortunately, the code of my module looks like this:

. . . sub new { my $class = shift ; my %args = @_ ; . . . my %localparms ; @localparms{@myParmNames} = delete @args{@myParmNames} ; . . . while (my ($parm,$value) = each %localparms) { $ldap->{"net_ldap_express_$parm"} = $value ; } return $ldap ;

As you can see, the reference you pass to the new method goes directly into the object. Therefore, if you alter the array in your program it will be altered for the object, too; vice-versa, if the object alters the array, your application data will be garbled

A safer implementation would, first of all, use accessors to set the values in the object; in turn, the accessors would copy the values inside the object instead of putting them directly into it.

Happy coding!

Update (after diotalevi's reply): If I pass, say, an array reference to an object, and the object alters the referenced array, I don't like it, but I still can stand it (once I know that the object will do that, of course ;-). What I find definitely a bad thing is the opposite effect: you change something in the program, and that alters the internal state of an object... isn't it a violation of encapsulation? And in OOP, isn't that a bad thing?

The very nature of Perl to be like natural language--inconsistant and full of dwim and special cases--makes it impossible to know it all without simply memorizing the documentation (which is not complete or totally correct anyway).
--John M. Dlugosz

Replies are listed 'Best First'.
Re: On the involuntary encapsulation violation
by diotalevi (Canon) on Aug 26, 2003 at 12:58 UTC

    No, that makes perfect sense. If I pass in a reference while keeping a local copy then I'm free to alter the reference at will. Put differently - if I pass in an object as a parameter then that object is still free to modify itself independant of what the other enclosing object's needs are.

    This is how things are supposed to be, or at least I don't see why things should be different. It works this way if I think if it in terms of C or in terms of perl.

    Added: Further, I know that when I know I need to copy an array, I do exactly that. So instead of writing ->new( foo => \ @ary ) I'm likely (assuming I'm thinking clearly) to write ->new( foo => [ @ary ] ). That assumes its a one level array with no further references but I think you get the picture. I explicitly copy when I mean to and references retain all of their associated meaning.

    Added again: While I've never found the need for it if I did need a deep copy I understand that Storable's dclone() does this nicely. This of course completely blows lots of XS modules out of the water since they have external non-perl structures that wouldn't be copied. I don't think there is a safe or sane way to copy those beasts.

Re: On the involuntary encapsulation violation
by PodMaster (Abbot) on Aug 26, 2003 at 16:29 UTC
    I find this to be a matter of documentation. There are no standards. You can do anything you want, all willy-nilly and whatnot. Whenever I see data being passed by reference to a module(method/function), I assume it's fair game for that data to be modified, unless the docs explicitly state that's not gonna happen. If the docs say it's not gonna happen, and it does, then it is clearly a bug (otherwise it's fair game, like i already said).

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: On the involuntary encapsulation violation
by Aristotle (Chancellor) on Aug 28, 2003 at 12:41 UTC

    If I pass \@array to something, I expect to be able to "garble" that data. If I want to give it a copy, I write @array .

    And what if you get passed an arrayful or references? If you make a copy of the array, the references in it still point to the same things. You'd need to make a deep copy..

    This is not something your module is not handling correctly. I submit that it's a misconception in your expectations. Perl is not a functional language.

    Makeshifts last the longest.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://286624]
Approved by valdez
Front-paged by rinceWind
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (7)
As of 2022-08-18 08:08 GMT
Find Nodes?
    Voting Booth?

    No recent polls found