in reply to %hash (@array && use constant) in Modules

Array versus hash isn't an issue if you ask me. The penalty you pay for constants is probably larger than those for a hash lookup. Constants are really subroutines, and subroutine calls use the stack.

The advantage of array-based objects, as far as I can tell, is reduced memory usage. You are only storing data and not hash-keys. They are faster, in theory, it would seem, but not in practice. If you used Filter instead of constant, then I might agree. A small compile-time penalty for a large run-time improvement. Another alternative, although a bit bold, is to use pseudo-hashes.

Hash-based structures are fully extensible, and can be sub-classed easily. I don't think the same holds true for the array-based ones. How do you know where the parent left off, index wise? Do you have to keep track with another constant?

All of this is speculation, of course, until some testing is done to see if it is true.

One thing I would like to do is take something like Autoload::Hash and extend it into a module which could fully realize the benefits of the array-based object (speed, memory) without requiring more code maintenance. Automatic code generation means referential integrity.
  • Comment on Re: %hash (@array && use constant) in Modules

Replies are listed 'Best First'.
Re: Re: %hash (@array && use constant) in Modules
by Elian (Parson) on Apr 23, 2002 at 22:05 UTC
    Array versus hash isn't an issue if you ask me. The penalty you pay for constants is probably larger than those for a hash lookup. Constants are really subroutines, and subroutine calls use the stack.
    Constant subs get (or at least should get) their values inlined at compile time. No runtime penalty there.
      "Should get" versus "do get" is an important distinction. Have a look inside constant and see:
      { no strict 'refs'; my $full_name = "${pkg}::$name"; $declared{$full_name}++; if (@_ == 1) { my $scalar = $_[0]; *$full_name = sub () { $scalar }; } elsif (@_) { my @list = @_; *$full_name = sub () { @list }; } else { *$full_name = sub () { }; } }
      Looks like a regular subroutine for me. No inline. Maybe in Perl 6.
        Incorrect. If it looks like a regular subroutine to you that only means you don't know what an inlined subroutine looks like! I suggest you spend some time with Benchmark and prove to yourself that "use constant" really does result in inlined subroutines.

        -sam

        Benchmarking tells you if something is faster or not. B::Deparse tells you how Perl compiled your code. Both are useful in a case like this, so here's the Deparse way...
        <mir 112 [8:56] ~ >perl -MO=Deparse -le 'use constant X=>17; print X' -e syntax OK sub X () { package constant; $scalar; } print 17;

        When the person above you said 'inline', I don't think he was referring to Inline::C or anything like that. Rather, that the Perl compiler knows to optimize "constant" subroutines at compile-time and replace its subroutine/stack-calling stuff with... well, constant values

        As an example, I created a program around the "Foo" package example we're using here, and I expanded the "Foo" package as well. Here it is:

        #!/usr/bin/perl -w
        
        use strict;
        
        my $foo = Foo->new();
        
        $foo->setBar('10');
        
        print "\$foo's 'bar' value is = " . $foo->getBar() . "\n";
        
        exit 0;
        
        package Foo;
        
        use constant BAR      => 1;
        use constant BAZ      => 2;
        use constant SO_ON    => 3;
        use constant SO_FORTH => 4;
        
        sub new {
            return bless ([], +shift);
        }
        
        sub getBar {
            my $self = shift;
            $self->BAR;
        }
        
        sub setBar {
            my $self = shift;
            $self->BAR = +shift;
        }
        

        Now, look at what this looks like when I run it through B::Deparse

        rdice@tanru:~$ perl -MO=Deparse,-uFoo constants.pl
        my $foo = 'Foo'->new;
        $foo->setBar('10');
        print q($foo's 'bar' value is = ) . $foo->getBar . "\n";
        exit 0;
        sub Foo::BAR () {
            package constant;
            $scalar;
        }
        sub Foo::BAZ () {
            package constant;
            $scalar;
        }
        sub Foo::SO_ON () {
            package constant;
            $scalar;
        }
        sub Foo::SO_FORTH () {
            package constant;
            $scalar;
        }
        sub Foo::new {
            package Foo;
            return bless([], shift @_);
        }
        sub Foo::getBar {
            package Foo;
            my $self = shift @_;
            $$self1;
        }
        sub Foo::setBar {
            package Foo;
            my $self = shift @_;
            $$self1 = shift @_;
        }
        constants.pl syntax OK
        

        This is a reflection of how Perl sees this program after compilation and optimization. Notice that there is NO subroutine call within sub Foo::getBar or sub Foo::setBar with regards to the BAR 'constant', which is really a subroutine, but has been optimized back to being a constant -- namely, "1".

        Cheers,
        Richard