Does breaking encapsulation indicate the wrong type of hammer?

I've had the pleasure of exchanging several emails with Dave Rolsky, author of a new OO tutorial on the subject of whether to introduce treating objects as the underlying hash reference.

He says he won't include even one example because "it really doesn't send the right message. My revisions to perlobj will explain how to implement accessors using the object as a hash reference."

I was shocked, because I find I need to visualize my object's data structures. Also, in several cases, reading or writing attributes directly allows me to implement some needed functionality.

I gave one example of this in a previous post..

Dave suggested the reason I needed to break encapsulation this way is that

  1. I haven't designed my objects properly or

  2. I haven't taken advantage of a full OO framework.

He concludes that I'm using the same coarse hammer to solve all my programming problems, because I'm simply not aware of better solutions.

Those are interesting criticisms.

The second point is absolutely right: I began my OO experiment with Object::Tiny, adding a setter and other facilities as I needed them. In fact, I am proud of this incremental approach, admittedly chosen for my own learning.

Regarding the first point, "design smarts" for me is an extremely limited resource. So I substitute an iterative process of problem-solving and refactoring.

Is it acceptable to use standard Perl tools for this, or should I be reaching higher, tapping more advanced tools? Suppose I had used Moose. Could I have solved my problems easier, more elegantly, with less stumbling?

Well, for one I would have had to ask for help in the Moose community, whereas with hand-rolled OO, I can understand the entire codebase, even if it doesn't meet certain standards of tidiness, design or even hygiene.

On the other hand, I do want my code to be beautiful, for various aesthic reasons, for ease of testing and maintenance, and also to have a code base that will be sufficiently attractive to other people to hack on.

With the aim of exploring whether I can achieve something better using Moose, Mouse, Moo or other advanced framework, in my next post, I'll give an example of some of my more advanced needs, and the naive, if not neolithic ways I implemented them.

8 Comments

Sometimes breaking encapsulation like that is outright-essential. Consider local in:

sub with_debug
{
my $self = shift;
my ( $code, @args ) = @_;
local $self->{debugging} = 1;
$self->$code( @args );
}

That simply cannot be done without breaking the encapsulation. There are many occasions in my code I've found the neatest solution to a problem is to localise a member value in an object.

While "encapsulation" is generally a good idea, remember that it's also a dogma, so people will start from the assumption that you shouldn't have broken it, and work backwards to come up with reasons. I wouldn't worry about it. If you run into a situation in the future where lack of encapsulation gives you a problem that's hard to fix, figure out why that happened and avoid making the same mistake again.

I've said this elsewhere, but it's worth repeating: We need to keep in mind the differences between tutorials and reference materials.

Tutorials are not for teaching the reader a solution to every possible scenario they might encounter. Rather, they're for arming the reader with just enough tools that they feel confident handling common scenarios, and the wisdom to know when diving into more detailed docs is required.

In your linked earlier post, you said "We should avoid absolutist language, especially in tutorials." I advocate the exact opposite approach: Absolutist language is forgivable, and perhaps desired in tutorials.. whereas we should avoid it in reference materials.

We teach the rules first. Only when you know the rules can you effectively decide when to break them.

You, Joel, obviously know the rules. You are not the target audience of a Perl OO tutorial. ;)

@Joel: You say "I believe that people are not able to visualize what their code signifies until they appreciate the underlying reality."

So you weren't able to understand Perl object until you understood hash refs, but you weren't able to understand hash refs until you understood the HV* data structure in the Perl, and you couldn't understand that until you understood the hash bucket algorithm, and you couldn't understand any of it until you understood the assembly generated for the processor, which you couldn't understand until you understood how processors work, which you could understand until you understood the underlying physics.

I think the main factor governing how much of the underlying substrate you need to understand depends on how leaky the higher-level abstraction is.

Traditionally, Perl objects have been extremely leaky. With something like Moose, most of the leaks are plugged.

Leave a comment

About Joel Roth

user-pic I blog about Perl.