Object::InsideOut - why on earth use it?

TeeJay on 2007-11-26T14:08:53

I'm dealing with a relatively recent codebase where the programmer has decided to use Object::InsideOut - and I'm really getting annoyed with it.

It doesn't offer any actual benefits over using a sane class system, such as Class::Accessor, doesn't provide any persistence (so that's all tacked on seperately via a heath-robinson contraption involving large SQL snippets all over the shop). I'd really like to replace all the Object::InsideOut code with DBIx::Class.

*sigh*

Today's fun problem is that I've added a new attribute, but the getter methods don't seem to exist, despite being specified in exactly the same way as all the others, naturally no useful information is provided about why it doesn't exist - merely that (despite all the code being in place) it doesn't.


But but...

sigzero on 2007-11-26T15:05:54

I thought InsideOut objects was *the* thing to do in OO Perl now?

Re:But but...

Alias on 2007-11-26T15:33:35

It was *A* thing for a while.

Most of the noise was taking the idea and working out which implementations don't suck.

Re:But but...

Aristotle on 2007-11-26T23:11:19

The implementation that doesn’t suck is called Hash::Util::FieldHash, courtesy of 5.10, coming to a CPAN near you soon.

Geroff my privates!

educated_foo on 2007-11-26T15:28:49

It may be tricky to add that attribute, but once you do it will be, like, totally encapsulated...

cultural solutions

rjbs on 2007-11-26T18:10:19

Inside-out objects are really neat and cool. That's why I don't think I will use them.

There are definite benefits, like improved encapsulation, but I don't need a shotgun -- especially one that has lots of overhead costs. In Perl, avoiding tight coupling can be reduced to a cultural problem, in my experience.

Sometimes, I use a pattern like this:

    $object->{__PACKAGE__}{attr} = $value;

Now the object's guts are well divided into areas of authority. If you, Subclass::Happy start screwing around in $self->{Superclass::Emotive}, you can... but you are even more obviously an ass.

I think that with inside-out objects, the cure is worse than the disease -- at least if the disease is being treated with a course of peer review.

Re:cultural solutions

Aristotle on 2007-11-26T23:13:41

avoiding tight coupling can be reduced to a cultural problem

I suppose Ruby-community-style monkeypatching is OK with you too?

Re:cultural solutions

rjbs on 2007-11-26T23:59:37

What the hell is that supposed to mean? I said that you should avoid tight coupling and screwing around in the guts of objects you don't destroy, but that the solution of inside-out objects can be a greater cost than is needed if you can effect a cultural solution.

How is that an endorsement of anything even remotely like monkeypatching?

Re:cultural solutions

lachoy on 2007-11-27T14:32:40

...and what the heck is monkeypatching?

Re:cultural solutions

rjbs on 2007-11-27T15:21:05

In Perl, it would be this:

use File::Spec;
use Other::Modules::Also;
 
sub File::Spec::catdir {
  shift;
  return join('//', @_);
}
 
do_stuff;
...
my $path = File::Spec->catdir(@parts);
...
do_things;
In other words: change the behavior of shared code by messing about with its guts, rather than by producing a subclass that you use. It's fast and easy (so a monkey can do it), acts like you've patched the source, and affects all the other code you've loaded and probably not reviewed for how it will be affected by your change. Oops!

Re:cultural solutions

lachoy on 2007-11-27T16:05:29

I think calling it 'monkeypatching' might be doing it an injustice. It's not pretty, but it's also something that (IMO) is useful when you know what you're doing, kind of like mucking with symbol tables. But it sounded from Aristotle's comment that this is SOP for Ruby folks, which I agree is scary.

Re:cultural solutions

Aristotle on 2007-11-27T17:00:34

I agree it can be useful in limited and highly constrained circumstances. It has its place, much like GOTO, which I am fond of defending against dogmatists despite the fact that I practically never use it.

The most common form among Ruby folk is adding methods to classes you don’t own. That does indeed seem to be SOP. Eg. Rake (the build system written in Ruby) stuffs a kitchen sink of filesystem-related methods into Object. Changing existing behaviour is less common, but they do that too; cf. the Chainsaw Infanticide Logger Manoeuvre. The Rails crowd is particularly given to using this… technique.

Re:cultural solutions

rjbs on 2007-11-27T18:57:28

What's worse is the use of it in JavaScript. For example:

Array.prototype.dump_it = function () { ... }
That doesn't seem so bad except that because of the way the for/in operation works in JavaScript, this is now broken:

for (i in some_array) { ... }
It will now loop over: 0, 1, 2, 3, dump_it.

Oops.

Re:cultural solutions

Aristotle on 2007-11-27T16:41:33

You made an unqualified claim that inside-out objects have some unspecified overhead cost and then said the absence of their benefits is only a problem if you make it one. That’s the same sort of argument by which monkeypatching gets justified – “it’s only a problem in practice if you make it one, and doing it this way is easier.” I cringe in embarrassment whenever Perl hackers trot out the living-room-and-shotgun line in the presence of others (and when it’s just Perl folk I roll my eyes).

What are those rumoured costs anyway? The only ones I’m aware of are second-order effects of DESTROY being broken and threads being terrible in Perl. Thankfully, 5.10 hacks around both of these. (Well, personally I don’t care about threads, so that one doesn’t affect me in any case.) Is there any counterargument if 5.10 is presumed?

Re:cultural solutions

rjbs on 2007-11-27T17:11:54

You made an unqualified claim that inside-out objects have some unspecified overhead cost and then said the absence of their benefits is only a problem if you make it one. That’s the same sort of argument by which monkeypatching gets justified – “it’s only a problem in practice if you make it one, and doing it this way is easier.” I cringe in embarrassment whenever Perl hackers trot out the living-room-and-shotgun line in the presence of others (and when it’s just Perl folk I roll my eyes).
I must not have been clear enough. I will be very plainspoken and see if that helps me communicate any better: It is always a bad practice to alter an objects behavior without limiting the scope of those modifications. It is also always a bad practice to alter the data associated with an object without controlling the way that the object 's methods and its data interact. Unfortunately, it is difficult to do this in Perl. One solution is inside-out objects, which prevent the user from altering an object's data easily. However, inside-out objects have costs. These costs are added complexity due to garbage collection, threading problems, and difficulty when serializing. These problems may be mitigated by using an inside-out object framework, but then the framework itself is a cost. One of these frameworks is very simple fieldhash system in perl 5.10. Unfortunately, it requires perl 5.10, which has not yet been released as a stable product, and which will take time before it is deployed into vendor perls.

So, if it is possible to create a *cultural* solution by having coding rules that ban unjustified alteration of foreign objects, this may be preferable to inside-out objects. The shotgun analogy is correct, here. Perl does not come equipped with a shotgun (encapsulation), so manners may have to do. Trying to bolt the shotgun on can prove more dangerous (to maintainability) than simply behaving well.

The shotgun metaphor need not be a reason to never *add* a native shotgun. I like field hashes, and I think they are a good step toward correcting the errors in language design that have made encapsulation in Perl objects problematic. I am certainly more likely to use fieldhashes for encapsulated data than I am to use Class::InsideOut or Object::InsideOut.

Abigail's point about compile time errors versus runtime errors was an excellent one, and I don't mean to address it at all, above.

Re:cultural solutions

TeeJay on 2007-11-27T10:00:17

Agreed totally - it's trivial to avoid the problems that Object::Std and O::IO try to solve without all the extra nonsense, what's more you can still use a sensible class framework.

Not once in the decade I've been writing Perl have I needed O::IO or it's ilk.

Re:cultural solutions

Abigail on 2007-11-27T12:50:45

That solves only one of the two problems Inside-Out Objects try to solve.

The other is turning (possibly hard to find) runtime errors into compile time errors.

Preferring $hash -> {attr} (or $hash -> {__PACKAGE__} {attr}) over $attr {refaddr $ref} is, IMO, as sane as preferring package variable and 'no strict' over lexical variables and 'use strict'.

Inside-Out Objects has never been about providing encapsulation with a shotgun. It simply favours perl5-style variables ('strict', 'lexical') over perl4-style variables ('no strict', 'package'). An attribute, after all, is simply a variable.

Re:cultural solutions

rjbs on 2007-11-27T13:41:39

Yes, that's a very good point, and what I suggested doesn't address it at all. I wonder whether a bit of sugar around restricted hashes could provide something 80% as useful without many of the drawbacks of inside-out objects... but I haven't given it much thought, let alone experimentation.

OIO Assistance

jdhedden on 2007-11-26T18:25:13

I'm disheartened to hear that you're having trouble with another programmer's code, and laying the blame solely on OIO. If you need help, OIO's POD references both the module's discussion forum and the author's email: jdhedden AT cpan DOT org.

While OIO's POD does discuss some of the advantages of using the inside-out object model, it also lists several more involved discussions on the matter including Damian Conway's book Perl Best Practices.

OIO does provide methods for maintaining persistent data, but not directly to a database. However, I don't see why this would be difficult as it would only require two simple methods in the parent class: one to dump the object and store it in the DB, and the other to retrieve and reconstitute the object. Your comment of large SQL snippets all over the shop sounds more like implementation issues rather than a deficiency with OIO.

With regard to the problem you're having with adding a new attribute, if you email me directly with the details (and perhaps an example), I'll do my best to help. Thanks.

Re:OIO Assistance

TeeJay on 2007-11-27T09:56:40

I was having problems with O:IO because of it's frankly bizarre idea of requiring a user to provide regexen to match method/attributes, not to mention it's abuse of attributes syntax (yummy - whitespace sensitive code for no good reason).

The number of places where it was needlessly complex and required copy and pasting where any sensible Class framework allows you to just specify the columns and have it DTRT.

"OIO does provide methods for maintaining persistent data, but not directly to a database. However, I don't see why this would be difficult as it would only require two simple methods in the parent class: one to dump the object and store it in the DB, and the other to retrieve and reconstitute the object."

There is a great deal more to useful object persistence than a couple of SQL statements - any decent ORM provides serialisation of complex attributes, searching, iterators of results, deletion, insertion, update-on-change, etc.

"Your comment of large SQL snippets all over the shop sounds more like implementation issues rather than a deficiency with OIO."

No - the SQL snippets could easily have been avoided by using a sensible class framework with real persistence like DBIx::Class or Class::DBI - both of which are far more useful, and can integrate well with validation, etc.

Like I said - O::IO and it's ilk are interesting illustrations of some concepts but have no place in production code.

Re:OIO Assistance

Aristotle on 2007-11-27T16:26:51

Errm, DBIx::Class is an object-relational mapper, not a class framework. Criticising Object::InsideOut for not being an ORM is like criticizing perl for not being an editor. What are you even talking about?

Re:OIO Assistance

TeeJay on 2007-11-28T09:30:09

DBIx::Class is also a class framework, same as Class::DBI and Class::Accessor - all of which are much easier to use and maintain than O::IO.

Re:OIO Assistance

Aristotle on 2007-11-28T10:03:00

No, CDBI and DBIC are not the same kind of thing as Class::Accessor. You don’t write programs with CDBI/DBIC if they have nothing to do with a database, and you don’t stick non-database-related logic in your CDBI/DBIC classes either.

The Right Tool for the Job

jdhedden on 2007-11-27T21:07:07

"requiring a user to provide regexen to match method/attributes"

It's not a requirement - it's optional. Cut out the regexes, and your preformance will go up (probably significantly). The regex option is there to provide greater programming flexibility if that is desired. As with any feature, if it's not needed, then don't use it.

"There is a great deal more to useful object persistence than a couple of SQL statements..."

The requirement to tie your objects to a database was evidently something the original coder failed to properly take into account. As OIO does not support this sort of thing, then obviously it was not the right tool for the job. It's senseless to condemn the screwdriver for not being a very good hammer.

"O::IO and it's ilk are interesting illustrations of some concepts but have no place in production code."

In your humble opinion, of course. OIO is being used quite a bit in production code (based on the correspondences I have had with users). So it's down do agreeing to disagree.

'Nuff said. Good luck with your rewrite. Sorry I couldn't be of any help.

Re:The Right Tool for the Job

TeeJay on 2007-11-28T09:33:59

Great :) I'd love to get rid of the regexen, but now they are there I don't know where they are used and would need to check - it looks to me that the original author cargo culted because the documentation wasn't clear enough - I certainly didn't find a nice simple example in the documentation.

Class::Accessor and it's like allow me to specify my attributes in a single line, even Moose is less bizarre in how you specify attributes.

I'm surprised people would choose to use O::IO in production code, I certainly wouldn't use it out of choice and will probably be replacing it with DBIx::Class.

You are quite right - I don't think the original author chose the right tool, that's not O::IO's fault :)