in reply to Database design and Class::DBI

without addressing the main issue (because i don't have any good ideas,) i will mention that when i see code like

sub SALE_PRICE_ID {1} sub LIST_PRICE_ID {2} sub COST_ID {3}

i find people usually mean

sub SALE_PRICE_ID() {1} sub LIST_PRICE_ID() {2} sub COST_ID() {3}

which will inline these subs. for a sub to be inlined into a constant, it must have a prototype of "()". you (and others) can find more on this in perlsub, under the "Constant Functions" heading.

~Particle *accelerates*

Replies are listed 'Best First'.
Re: Re: Database design and Class::DBI
by Ovid (Cardinal) on Mar 05, 2003 at 21:16 UTC

    First, these are method calls and prototypes on method calls are ignored. I realize this is a special case that allows for constant folding -- I don't want to use prototypes for the only and only case where they actually work with methods :) I might encourage others to do Bad Things.

    Second, the discussion of void prototype issues and the resultant "mysterious" behavior is enough for me to avoid using them unless I really, really want them. Also, subclassing them doesn't always work if they've been optimized away. Later versions of Perl (IIRC >= 5.8?) will optimize away the subroutine itself, thus ensuring that calls to SUPER from a subclass will have disappointing results.

    Cheers,
    Ovid

    New address of my CGI Course.
    Silence is Evil (feel free to copy and distribute widely - note copyright text)

      Is there a reason you didn't use the "constant" pragma? Personally I find it annoying and use package variables instead, but I believe it does exactly what you just did.

        I just ran a quick test on 5.8 to ensure that there were no problems with inheriting constants and, as far as I can tell, there aren't any, but I do worry about it because of issues like this:

        $ perl -MO=Deparse -e 'sub foo(){3};print foo()' print 3;

        Note that the sub declaration is gone and, due to the constant folding optimization, the value of the constant is hardcoded into the program at compile time. As a result, I tend to avoid constants if they're to be used outside of a given package. For example, I used to do this:

        use constant DEBUGGING => 0; # later if (DEBUGGING) {...}

        I would try to override DEBUGGING in a test suite ...

        local *Some::Package::DEBUGGING = sub {0};

        ... only to discover that because use of the constant had been optimized away, there was nothing left to override. I've personally found that bugs like this can be very difficult for me to debug as these are "behind the scenes" compile-time actions. I wound up sticking explicit sub declarations (with no prototype) in my code and my problems went away.

        In other words, I use the constant pragma quite a bit, but again, only if said constant isn't to be used outside of a given package (or is to be explicitly exported to another package).

        My coworker and I had quite a bit of debate about these issues and whether or not to use constants, but what finally settled it was simple: these are properties of a class, so we should provide accessors to them and ensure that the interface to class data is consistent. The only consideration we gave to the special case is that the accessors are ALL CAPS, which should be a clue to any programmer that there's something odd going on.

        Cheers,
        Ovid

        New address of my CGI Course.
        Silence is Evil (feel free to copy and distribute widely - note copyright text)