[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.