[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Omaha.pm] Class::Date - change once set




On Oct 26, 2005, at 9:32 AM, Kenneth Thompson wrote:
Actually, I'm not so sure this is as bad a thing at it seems on the
surface. The perldoc states that it
exposes the internal pieces via an array of parts/formats:

-------------
INTERNALS
This module uses operator overloading very heavily. I've found it quite
stable, but I am afraid of it a bit.
A Class::Date object is an array reference.
-------------

Given that the array has been exposed and documented on purpose, I
wouldn't think that this type of manipulation would be bad. Even if they change the array, it's setting one object's internals equal to the other
objects internals. Is that the same as accessing the internals for
manipulation?

In my opinion, breaking encapsulation is always a bad idea and should be avoided at all costs.

What if...
- The class changes to a hash implementation a year from now?
- The package is (or someday starts to) keep counts inside its scope or UNIVERSAL so copying that value breaks something? - One of the elements of the array ref is supposed to be unique? Memory pointer? Database ID? Any persistence ID? - the package overrides the assignment operator, causing weird things to occur?

Even if the module author tempts you, do not partake of the forbidden fruit.

Breaking encapsulation just begs your code to break some day, a year from now, when you've forgotten all about this class and have much better things to be working on than some mystery thing that "used to work". Unnecessary risk with no upside. Fragile code that will shatter time and time again.

Of course the hard count reference (0..9) should be a
little more dynamic in case the array size is increased for some reason.

Yes, I agree -- If you're going to jump out of an airplane w/o a parachute, then landing on your feet is probably a good idea. I predict the fall will still kill you, though. -grin-

Better yet, take a parachute with you! (Leave encapsulation intact!)

However- what about a whole different approach? Maybe a referenced
workaround?

use Class::Date qw( date );
#Clone a date object into and existing date object

my $d1 = Class::Date->new("1971-01-01");
my $d1R = \$d1;
my $d2 = Class::Date->new("2000-01-01");

print "[".$d1."][$d2]\n";
stuff($d1, $d2);$d1 = $$d1R;
print "[$d1][$d2]\n";


sub stuff {
    my ($d1, $d2) = @_;
    if ($d2 > $d1) {
      $d1R = \$d2;   # <---- I want to overwrite the existing $d1 here
    }
}

And for discussion- why

    my ($d1, $d2) = @_;

and not

    ($d1, $d2) = @_;

? (by the way... The second way works the way you wanted it to)

In both of those examples you're reusing a variable that's been scoped to be global throughout your program. As we all know, globals are another evil root of maintainability doom.

Pretend our little demo is part of a larger (real world) program by expanding the demo to 2 files (a .pl and a .pm) and "use strict;" and you'll see that strict won't let you play those particular reindeer games:

----
$ cat j2.pl
use strict;
use Class::Date;
use Printer;

my $d1 = Class::Date->new("1971-01-01");
my $d2 = Class::Date->new("2000-01-01");

Printer::print($d1, $d2);

$ cat Printer.pm
package Printer;
use strict;

sub print {
   print "[$d1][$d2]\n";
}

1;
$ perl j2.pl
Global symbol "$d1" requires explicit package name at Printer.pm line 5.
Global symbol "$d2" requires explicit package name at Printer.pm line 5.
Compilation failed in require at j2.pl line 3.
BEGIN failed--compilation aborted at j2.pl line 3.
----

The

   my ($x, $y, $z) = @_;

idiom is how you know for sure that your sub/method has its own scoped copies of or references to the arguments that were just handed it.

Two things I learned setting up this demo:

(1) "use strict" doesn't detect scoping problems if you define multiple packages in the same file. Doh! I don't do this in real life anyway, but it surprised me. (2) You have to "use strict" in both files to get it to complain. I thought once you "use strict"'d anywhere in your program that it would protect you across all your packages. Not true! Note to self: DO explicitly type "use strict;" into EVERY Perl file to make sure you don't burn yourself!

Encapsulation good. Globals bad.

I'll solve my original problem by storing the Class::Date objects in a location that both my main and my package can access. (Attributes of a commonly accessible class...)

I hope that helps,

j
long winded soap box dude

P.S. Damian Conway's OO Perl book delivers the encapsulation lecture far better than I can.