Using lock_keys with strict and bless

Discussion in 'Perl Misc' started by lroland@gmail.com, Aug 8, 2005.

  1. Guest

    Hi

    I am trying to use "lock_keys" to create a unmodifiable perl module -
    my code is inspired by this article
    http://perltraining.com.au/tips/2005-01-31.html - I figured that if I
    do the following in my constructor then it works:

    ----------------
    my %i = ( name => undef );
    bless \%i, 'Misc';
    lock_keys(%i);
    ----------------

    unfortunately this is not very handy in a perl module rather than using
    a explicit hash I would like to use a reference in the style of:

    ----------------
    package Misc::Misc;

    use diagnostics;
    use warnings;
    use strict;

    use Hash::Util qw(lock_keys);
    use Data::Dumper;

    sub new
    {
    my ($this) = @_;
    bless {
    name => undef,
    info => {
    age => undef
    }
    }, $this;
    lock_keys(%$this); # this does not work
    }

    sub print
    {
    my ($this) = @_;
    my $content = Dumper($this);
    print "Hash content is:\n $content";
    }

    1;
    ----------------

    This does however not work, when trying to use the module:

    ----------------
    #!/usr/bin/perl
    use strict;
    use Misc::Misc;

    my $test = Misc::Misc->new();
    $test->{name} = "foobar";
    $test->{info}->{age} = "42";
    $test->print();
    ----------------

    perl complaints about wrong usage of strict refs - so does anyone know
    if lock_keys somehow can be used in a perl module such as the one
    created above ?


    --
    Lars Roland
     
    , Aug 8, 2005
    #1
    1. Advertising

  2. Paul Lalli Guest

    wrote:
    > ----------------
    > package Misc::Misc;
    >
    > use diagnostics;
    > use warnings;
    > use strict;
    >
    > use Hash::Util qw(lock_keys);
    > use Data::Dumper;
    >
    > sub new
    > {
    > my ($this) = @_;
    > bless {
    > name => undef,
    > info => {
    > age => undef
    > }
    > }, $this;
    > lock_keys(%$this); # this does not work
    > }


    You seem to be confused about how Perl modules work. In your code,
    $this is the class of which new() is a member. You cannot dereference
    $this as a hash, because it isn't a hash reference - or any reference
    for that matter. Your bless() statement blesses an anonymous hash into
    the class $class. Unfortunately, you did not provide any method by
    which to store this hash reference.

    Furthermore, you also apparently haven't read the documentation for the
    function your using.
    http://search.cpan.org/~nwclark/perl-5.8.7/lib/Hash/Util.pm#Restricted_hashes
    tells us: "Note: the current implementation prevents the hash from
    being bless()ed while it is in a locked state. Any attempt to do so
    will raise an exception. Of course you can still bless() the hash
    before you call lock_keys() so this shouldn't be a problem."


    > This does however not work, when trying to use the module:
    >
    > ----------------
    > #!/usr/bin/perl
    > use strict;
    > use Misc::Misc;
    >
    > my $test = Misc::Misc->new();
    > $test->{name} = "foobar";
    > $test->{info}->{age} = "42";
    > $test->print();
    > ----------------
    >
    > perl complaints about wrong usage of strict refs


    Please read the positing guidelines for this group. Specifically, do
    not give us the general theme of the error message - copy and paste the
    *exact* error message. Had you taken the time to look at what that
    error message actually told you: "Can't use string ("Misc::Misc") as a
    HASH ref while "strict refs" in use at Misc.pm line 19 (#1)", you might
    have been able to figure out that this error message had nothing to do
    with the lock_keys method.

    > - so does anyone know
    > if lock_keys somehow can be used in a perl module such as the one
    > created above ?


    Not the way you created it above, no. Again, read the documentation
    for the function you created, and then apply it to the standard way a
    constructor is written.
    Step 1: get the class name
    Step 2: create the hash reference
    Step 3: bless the hash reference into the class
    Step 4: lock the keys of the hash the reference references
    Step 5: return the blessed reference

    checkout
    perldoc perlmod
    perldoc perlobj
    perldoc perloot

    for more information on creating classes.

    Hope this helps,
    Paul Lalli
     
    Paul Lalli, Aug 8, 2005
    #2
    1. Advertising

  3. Guest

    Paul Lalli wrote:
    > You seem to be confused about how Perl modules work. In your code,
    > $this is the class of which new() is a member. You cannot dereference
    > $this as a hash, because it isn't a hash reference - or any reference
    > for that matter. Your bless() statement blesses an anonymous hash into
    > the class $class. Unfortunately, you did not provide any method by
    > which to store this hash reference.


    Thanks for the reply - if I however change the code to

    -----------
    package Misc::Misc;
    use strict;
    use Data::Dumper;
    use Hash::Util qw(lock_keys);

    sub new
    {
    my ($this) = @_;
    my $struct = {
    name => undef,
    info => {
    age => undef
    }
    };
    bless $struct, $this;
    lock_keys(%$struct);
    }
    sub print
    {
    my ($this) = @_;
    my $content = Dumper($this);
    print "Hash content is:\n $content";
    }
    1;
    -----------

    When I try to execute the following code:

    -----------
    use Misc::Misc;
    my $test = Misc::Misc->new();
    $test->{name} = "foobar";
    $test->{info}->{age} = "42";
    $test->print();
    -----------

    then I get the following error: "can't call method "print" on unblessed
    reference at misc.pl" - I realize that I have misunderstood something
    important here, but I have googled around, read the man pages and none
    of them seams to deal with locking the content of a hash used
    internally in a module (although some of them mention it is possible).

    > Furthermore, you also apparently haven't read the documentation for the
    > function your using.
    > http://search.cpan.org/~nwclark/perl-5.8.7/lib/Hash/Util.pm#Restricted_hashes
    > tells us: "Note: the current implementation prevents the hash from
    > being bless()ed while it is in a locked state. Any attempt to do so
    > will raise an exception. Of course you can still bless() the hash
    > before you call lock_keys() so this shouldn't be a problem."
    >


    Well I may be off (still new to OO perl) but the docs says "Of course
    you can still bless() the hash before you call lock_keys()" - when I
    do:

    -----------
    bless $struct, $this;
    lock_keys(%$struct);
    -----------

    is that not the same as a bless before locking ?.


    --
    Lars Roland
     
    , Aug 8, 2005
    #3
  4. Paul Lalli Guest

    wrote:
    > -----------
    > package Misc::Misc;
    > use strict;
    > use Data::Dumper;
    > use Hash::Util qw(lock_keys);
    >
    > sub new
    > {
    > my ($this) = @_;
    > my $struct = {
    > name => undef,
    > info => {
    > age => undef
    > }
    > };
    > bless $struct, $this;
    > lock_keys(%$struct);
    > }


    I'm going to paste back in my "five steps" that you snipped:
    > > Step 1: get the class name
    > > Step 2: create the hash reference
    > > Step 3: bless the hash reference into the class
    > > Step 4: lock the keys of the hash the reference references
    > > Step 5: return the blessed reference


    You have skipped step 5.

    > When I try to execute the following code:
    >
    > -----------
    > use Misc::Misc;
    > my $test = Misc::Misc->new();
    > $test->{name} = "foobar";
    > $test->{info}->{age} = "42";
    > $test->print();
    > -----------
    >
    > then I get the following error: "can't call method "print" on unblessed
    > reference at misc.pl" - I realize that I have misunderstood something
    > important here, but I have googled around, read the man pages and none
    > of them seams to deal with locking the content of a hash used
    > internally in a module (although some of them mention it is possible).


    That's because this has nothing to do with locking. You're assigning
    $test to be the return value of the call to new(). Perl subroutines
    return the last statement evaluated. In this case, that's the
    lock_keys() call. lock_keys() does not return your blessed reference.
    So $test does not contain your blessed reference. Add this line to the
    end of your constructor:

    return $struct;

    > Well I may be off (still new to OO perl) but the docs says "Of course
    > you can still bless() the hash before you call lock_keys()" - when I
    > do:
    >
    > -----------
    > bless $struct, $this;
    > lock_keys(%$struct);
    > -----------
    >
    > is that not the same as a bless before locking ?.


    That section of the code is 100% fine. Nothing wrong there.

    Paul Lalli
     
    Paul Lalli, Aug 8, 2005
    #4
  5. Guest

    Paul Lalli wrote:
    > I'm going to paste back in my "five steps" that you snipped:
    > > > Step 1: get the class name
    > > > Step 2: create the hash reference
    > > > Step 3: bless the hash reference into the class
    > > > Step 4: lock the keys of the hash the reference references
    > > > Step 5: return the blessed reference

    >
    > That's because this has nothing to do with locking. You're assigning
    > $test to be the return value of the call to new(). Perl subroutines
    > return the last statement evaluated. In this case, that's the
    > lock_keys() call. lock_keys() does not return your blessed reference.
    > So $test does not contain your blessed reference. Add this line to the
    > end of your constructor:
    >
    > return $struct;


    Thanks a lot for your help - I think I get your point - I seam to fail
    seeing the relationship between the internal struct and the
    encapsulation performed by bless - this is somewhat different to what I
    am used to in C++. I will try to get my hands on the OO perl book by
    Damian Conway so I can get this right.

    changing the module to:

    ------------
    package Misc::Misc;
    use strict;
    use Data::Dumper;
    use Hash::Util qw(lock_keys);

    sub new
    {
    my ($this) = @_;
    my $struct = {
    name => undef,
    info => {
    age => undef
    }
    };
    bless $struct, $this;
    lock_keys(%$struct);
    return $struct;
    }
    sub print
    {
    my ($this) = @_;
    my $content = Dumper($this);
    print "Hash content is:\n $content";
    }
    1;
    ------------

    does indeed make the code work but it does not ensure that the entire
    data structure is locked - if I execute the following code:

    ------------
    #/usr/bin/perl
    use Strict;
    use Misc::Misc;
    my $test = Misc::Misc->new();
    # change values is ok
    $test->{name} = "foobar";
    $test->{info}->{age} = "42";
    # this should not could happen
    $test->{info}->{fail} = "12";
    #print object
    $test->print();
    ------------

    then the resulting structure contains a key which was not created in in
    the constructor (i.e. {info}->{fail} )- Without having researched this
    further I am guessing that I it is because I am using a hash of hashes
    and lock_keys properly only function on the outer hash not the inner
    one.

    --
    Lars Roland
     
    , Aug 8, 2005
    #5
  6. Paul Lalli Guest

    wrote:
    > Thanks a lot for your help - I think I get your point - I seam to fail
    > seeing the relationship between the internal struct and the
    > encapsulation performed by bless - this is somewhat different to what I
    > am used to in C++. I will try to get my hands on the OO perl book by
    > Damian Conway so I can get this right.


    My appreciation for Mr. Conway's work notwithstanding, I would still
    recommend reading the free documentation that comes with Perl before
    spending money on a book. See if you can understand how to make your
    code work by reading the various references and tutorials.

    perldoc perlref - Reference about references
    perldoc perllol - Building "lists of lists"
    perldoc perldsc - Data Structures Cookbook
    perldoc perlobj - Perl objects
    perldoc perltoot - Object Oriented Tutorial
    perldoc perlmod - Modules and Namespaces
    perldoc perlnewmod - Writing your own new module


    > sub new
    > {
    > my ($this) = @_;
    > my $struct = {
    > name => undef,
    > info => {
    > age => undef
    > }
    > };
    > bless $struct, $this;
    > lock_keys(%$struct);
    > return $struct;
    > }


    > does not ensure that the entire data structure is locked - if I
    > execute the following code:
    >
    > ------------
    > #/usr/bin/perl
    > use Strict;
    > use Misc::Misc;
    > my $test = Misc::Misc->new();
    > # change values is ok
    > $test->{name} = "foobar";
    > $test->{info}->{age} = "42";
    > # this should not could happen
    > $test->{info}->{fail} = "12";
    > #print object
    > $test->print();
    > ------------
    >
    > then the resulting structure contains a key which was not created in in
    > the constructor (i.e. {info}->{fail} )- Without having researched this
    > further I am guessing that I it is because I am using a hash of hashes
    > and lock_keys properly only function on the outer hash not the inner
    > one.


    Mostly Correct. The hash that you locked contains exactly 2 keys -
    'name' and 'info'. The *value* of the hash at the key 'info' is a
    reference to another hash. That hash is not locked. You could, of
    course, lock it:
    lock_keys(%{$struct->{info}});

    Paul Lalli
     
    Paul Lalli, Aug 8, 2005
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. bwv549
    Replies:
    3
    Views:
    143
    Joel VanderWerf
    Jan 29, 2010
  2. Joey Zhou
    Replies:
    7
    Views:
    126
    John Carter
    Mar 14, 2011
  3. Johannes Fürnkranz

    Hash::Utils lock_keys

    Johannes Fürnkranz, Jun 27, 2003, in forum: Perl Misc
    Replies:
    5
    Views:
    112
    Tassilo v. Parseval
    Jun 28, 2003
  4. Kim Jonguk

    question about 'bless'

    Kim Jonguk, Sep 8, 2003, in forum: Perl Misc
    Replies:
    2
    Views:
    100
    Anno Siegel
    Sep 8, 2003
  5. Rud1ger Sch1erz
    Replies:
    1
    Views:
    272
Loading...

Share This Page