OO Perl : Struggling with hash data members in my Class

Discussion in 'Perl Misc' started by Brett.R.Davis@gmail.com, Aug 9, 2006.

  1. Guest

    I am writing my first Perl Class and have hit a brick wall.

    What I need to do is have a class method copy a hash into the data
    member %MY_HASH.

    I have coded a constructor and a method my_hash which is *supposed* to
    either:

    1. return the HASH reference or
    2. write a copy the contents of a hash into the MY_COLORS data member.

    Then I wanted a second data member that uppon being written to with a
    symbolic name, would use the MY_COLORS hash to provide the numberical
    code for that COLOR as shown:

    my $composite_colors={'green'=>1, 'blue'=>2, 'red'=>3 };
    my $color_set=Chash->new();
    $chash->my_colors($composite_colors);
    $chash->color_code('blue');
    print $chash{'color_code'};

    The output should be:

    2

    However, I am never able to get the object $chash to take in the
    $composite_colors reference, and copy it into the data member
    MY_COLORS. I get comments like "odd number of elements in anonymous
    hash". If I data dump the contents of the data member MY_COLORS it
    shows that the $composite_colors hash is being copied in as a key to
    the has instead of essentially becoming the MY_COLORS hash.

    Any assistance would be greatly appreciated!!!!

    Brett


    Here is the code.

    package Chash;

    sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
    $self->{MY_COLORS} = {};
    $self->{COLOR_CODE} = undef;
    bless($self, $class);
    return $self;
    }

    sub my_colors {
    my $self = shift;
    if (@_) { $self->{MY_COLORS} = $_[0] }
    return { $self->{MY_COLORS} };
    }


    sub color_code {
    my $self = shift;
    if (@_) {
    if (ref $self->{MY_COLORS} eq "HASH") {
    $self->{COLOR_CODE} = $self->{MY_COLORS}->{$_[0]};
    }
    else {
    $self->{COLOR_CODE} = shift;
    }
    }
    return $self->{COLOR_CODE};
    }
     
    , Aug 9, 2006
    #1
    1. Advertising

  2. Guest

    Thank you for your response.
    I think my simple color abstraction may have confused the issue.
    Let me try to rephrase the problem - given a hash :

    my %bar = { 'x'=>0xbeef, 'y'=>0xfeed };

    and assuming a class Foo with the constructor below,
    how do I put %bar into MY_HASH.

    And then how do I get the contents of MY_HASH?

    I can't seem to get this to work.

    =-=-=-=--=-=-=-=-=-=-=-=-=-

    Package My::Class::Foo;

    use strict;
    use warnings;
    use Carp;

    sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
    $self->{MY_HASH} = {};
    bless($self, $class);
    return $self;
    }

    =-=-=-=-=-=-=-=--=-==-=-=-=-=-
     
    , Aug 10, 2006
    #2
    1. Advertising

  3. Mumia W. Guest

    On 08/09/2006 05:36 PM, wrote:
    > I am writing my first Perl Class and have hit a brick wall.
    >
    > What I need to do is have a class method copy a hash into the data
    > member %MY_HASH.
    >
    > I have coded a constructor and a method my_hash which is *supposed* to
    > either:
    >
    > 1. return the HASH reference or
    > 2. write a copy the contents of a hash into the MY_COLORS data member.
    >
    > Then I wanted a second data member that uppon being written to with a
    > symbolic name, would use the MY_COLORS hash to provide the numberical
    > code for that COLOR as shown:
    >
    > my $composite_colors={'green'=>1, 'blue'=>2, 'red'=>3 };
    > my $color_set=Chash->new();


    I got your program to work, but I had to assign $color_set to
    $chash before the line below.

    > $chash->my_colors($composite_colors);
    > $chash->color_code('blue');
    > print $chash{'color_code'};
    >
    > The output should be:
    >
    > 2
    >
    > However, I am never able to get the object $chash to take in the
    > $composite_colors reference, and copy it into the data member
    > MY_COLORS.


    The code you posted pretty much should work so long as $chash
    is set to something meaningful. You have an annoying warning
    that I'll show you how to get rid of.

    > I get comments like "odd number of elements in anonymous
    > hash". If I data dump the contents of the data member MY_COLORS it
    > shows that the $composite_colors hash is being copied in as a key to
    > the has instead of essentially becoming the MY_COLORS hash.
    >
    > Any assistance would be greatly appreciated!!!!
    >
    > Brett
    >
    >
    > Here is the code.
    >
    > package Chash;
    >
    > sub new {
    > my $proto = shift;
    > my $class = ref($proto) || $proto;
    > my $self = {};
    > $self->{MY_COLORS} = {};
    > $self->{COLOR_CODE} = undef;
    > bless($self, $class);
    > return $self;
    > }
    >
    > sub my_colors {
    > my $self = shift;
    > if (@_) { $self->{MY_COLORS} = $_[0] }
    > return { $self->{MY_COLORS} };


    The line above produces an annoying warning; the line uses
    $self->{MY_COLORS}, which contains only *one* value, a scalar
    reference to a hash, as the data for an anonymous hash
    (denoted by { ... }); hashes with an uneven number of elements
    are usually messed up.

    I don't know why you're creating an anonymous hash then
    returning it; you already have a much better hash to return in
    $self->{MY_COLORS}, so why not just return it? Perhaps you
    were thinking of the {...} as a block. Anyway, change it:

    return $self->{MY_COLORS};


    > }
    >
    >
    > sub color_code {
    > my $self = shift;
    > if (@_) {
    > if (ref $self->{MY_COLORS} eq "HASH") {
    > $self->{COLOR_CODE} = $self->{MY_COLORS}->{$_[0]};
    > }
    > else {
    > $self->{COLOR_CODE} = shift;
    > }
    > }
    > return $self->{COLOR_CODE};
    > }
    >


    A. Sinan Unur showed you how to use some perl modules to do
    this differently, and I think I'll do that too:

    package My::Chash2;
    use Class::Struct;
    struct 'My::Chash2' => [ my_colors => '%' ];

    sub color_code {
    my $self = shift;
    $self->my_colors(shift());
    }

    package main;

    my $composite_colors={'green'=>1, 'blue'=>2, 'red'=>3 };
    my $chash = My::Chash2->new();
    $chash->my_colors($composite_colors);
    print $chash->color_code('blue'), "\n";



    __HTH__

    :)
     
    Mumia W., Aug 10, 2006
    #3
  4. >>>>> "Brett" == Brett R Davis <> writes:

    Brett> sub new {
    Brett> my $proto = shift;
    Brett> my $class = ref($proto) || $proto;

    Please don't do this. See
    <http://www.stonehenge.com/merlyn/UnixReview/col52.html> for a long discussion
    about constructors, including the last few paragraphs which describe why not
    to do that.

    print "Just another Perl hacker,"; # the original

    --
    Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
    <> <URL:http://www.stonehenge.com/merlyn/>
    Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
    See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

    --
    Posted via a free Usenet account from http://www.teranews.com
     
    Randal L. Schwartz, Aug 10, 2006
    #4
  5. Mumia W. Guest

    On 08/09/2006 08:08 PM, wrote:
    > Thank you for your response.
    > I think my simple color abstraction may have confused the issue.
    > Let me try to rephrase the problem - given a hash :
    >
    > my %bar = { 'x'=>0xbeef, 'y'=>0xfeed };
    >


    You have problems with Perl syntax. Curly braces are used to
    create blocks and anonymous hashes. Use parenthesis to create
    arrays and non-anonymous hashes, e.g.

    my %bar = ( 'x'=>0xbeef, 'y'=>0xfeed );


    > and assuming a class Foo with the constructor below,
    > how do I put %bar into MY_HASH.
    >
    > And then how do I get the contents of MY_HASH?
    >
    > I can't seem to get this to work.
    >
    > =-=-=-=--=-=-=-=-=-=-=-=-=-
    >
    > Package My::Class::Foo;
    >
    > use strict;
    > use warnings;
    > use Carp;
    >
    > sub new {
    > my $proto = shift;
    > my $class = ref($proto) || $proto;
    > my $self = {};
    > $self->{MY_HASH} = {};

    %{$self->{MY_HASH}} = @_ if (@_);

    > bless($self, $class);
    > return $self;
    > }
    >
    > =-=-=-=-=-=-=-=--=-==-=-=-=-=-
    >


    package main;

    my $chash = My::Class::Foo->new(%bar)

    However, I wouldn't bother writing a new() function for
    something this simple, because it's so much easier to cheat:

    use Class::Struct;
    struct My::Class::Foo => [ my_colors => '%' ];

    my %bar = ( 'x'=>0xbeef, 'y'=>0xfeed );
    my $chash = My::Class::Foo->new( my_colors => \%bar);

    =-=-=-=-=-=-=-=--=-==-=-=-=-=-
    UNTESTED CODE
     
    Mumia W., Aug 10, 2006
    #5
  6. Guest

    You said that you were able to get my original code to work.

    Can you tell me specifically what it was - or was it the items you
    specified in the message?

    The class I presented was just for academic reasons. The actual class
    I need to implement will be quite a bit more complicated.

    Does the struct class you showed me allow for member functions?

    Thanks

    Mumia W. wrote:
    > On 08/09/2006 05:36 PM, wrote:
    > > I am writing my first Perl Class and have hit a brick wall.
    > >
    > > What I need to do is have a class method copy a hash into the data
    > > member %MY_HASH.
    > >
    > > I have coded a constructor and a method my_hash which is *supposed* to
    > > either:
    > >
    > > 1. return the HASH reference or
    > > 2. write a copy the contents of a hash into the MY_COLORS data member.
    > >
    > > Then I wanted a second data member that uppon being written to with a
    > > symbolic name, would use the MY_COLORS hash to provide the numberical
    > > code for that COLOR as shown:
    > >
    > > my $composite_colors={'green'=>1, 'blue'=>2, 'red'=>3 };
    > > my $color_set=Chash->new();

    >
    > I got your program to work, but I had to assign $color_set to
    > $chash before the line below.
    >
    > > $chash->my_colors($composite_colors);
    > > $chash->color_code('blue');
    > > print $chash{'color_code'};
    > >
    > > The output should be:
    > >
    > > 2
    > >
    > > However, I am never able to get the object $chash to take in the
    > > $composite_colors reference, and copy it into the data member
    > > MY_COLORS.

    >
    > The code you posted pretty much should work so long as $chash
    > is set to something meaningful. You have an annoying warning
    > that I'll show you how to get rid of.
    >
    > > I get comments like "odd number of elements in anonymous
    > > hash". If I data dump the contents of the data member MY_COLORS it
    > > shows that the $composite_colors hash is being copied in as a key to
    > > the has instead of essentially becoming the MY_COLORS hash.
    > >
    > > Any assistance would be greatly appreciated!!!!
    > >
    > > Brett
    > >
    > >
    > > Here is the code.
    > >
    > > package Chash;
    > >
    > > sub new {
    > > my $proto = shift;
    > > my $class = ref($proto) || $proto;
    > > my $self = {};
    > > $self->{MY_COLORS} = {};
    > > $self->{COLOR_CODE} = undef;
    > > bless($self, $class);
    > > return $self;
    > > }
    > >
    > > sub my_colors {
    > > my $self = shift;
    > > if (@_) { $self->{MY_COLORS} = $_[0] }
    > > return { $self->{MY_COLORS} };

    >
    > The line above produces an annoying warning; the line uses
    > $self->{MY_COLORS}, which contains only *one* value, a scalar
    > reference to a hash, as the data for an anonymous hash
    > (denoted by { ... }); hashes with an uneven number of elements
    > are usually messed up.
    >
    > I don't know why you're creating an anonymous hash then
    > returning it; you already have a much better hash to return in
    > $self->{MY_COLORS}, so why not just return it? Perhaps you
    > were thinking of the {...} as a block. Anyway, change it:
    >
    > return $self->{MY_COLORS};
    >
    >
    > > }
    > >
    > >
    > > sub color_code {
    > > my $self = shift;
    > > if (@_) {
    > > if (ref $self->{MY_COLORS} eq "HASH") {
    > > $self->{COLOR_CODE} = $self->{MY_COLORS}->{$_[0]};
    > > }
    > > else {
    > > $self->{COLOR_CODE} = shift;
    > > }
    > > }
    > > return $self->{COLOR_CODE};
    > > }
    > >

    >
    > A. Sinan Unur showed you how to use some perl modules to do
    > this differently, and I think I'll do that too:
    >
    > package My::Chash2;
    > use Class::Struct;
    > struct 'My::Chash2' => [ my_colors => '%' ];
    >
    > sub color_code {
    > my $self = shift;
    > $self->my_colors(shift());
    > }
    >
    > package main;
    >
    > my $composite_colors={'green'=>1, 'blue'=>2, 'red'=>3 };
    > my $chash = My::Chash2->new();
    > $chash->my_colors($composite_colors);
    > print $chash->color_code('blue'), "\n";
    >
    >
    >
    > __HTH__
    >
    > :)
     
    , Aug 10, 2006
    #6
  7. Mumia W. Guest

    On 08/09/2006 10:49 PM, wrote:
    > You said that you were able to get my original code to work.
    >
    > Can you tell me specifically what it was - or was it the items you
    > specified in the message?
    > [...]


    Don't top post.

    Everything was in the message: I assigned $color_set to
    $chash, and I made my_colors() return $self->{MY_COLORS}.
     
    Mumia W., Aug 10, 2006
    #7
  8. Guest

    OK - it worked!

    I am a moron, and didn't have "-w" set in the script so I didn't notice
    that I had { } around a hash reference like you said in the above post.
    I originally had it as an anonymous hash.

    By changing the return statement and fixing my hash declaration (used (
    ) instead of { } ) - it works!

    Thank you

    Brett

    Mumia W. wrote:
    > On 08/09/2006 10:49 PM, wrote:
    > > You said that you were able to get my original code to work.
    > >
    > > Can you tell me specifically what it was - or was it the items you
    > > specified in the message?
    > > [...]

    >
    > Don't top post.
    >
    > Everything was in the message: I assigned $color_set to
    > $chash, and I made my_colors() return $self->{MY_COLORS}.
     
    , Aug 10, 2006
    #8
    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. CoolPint
    Replies:
    8
    Views:
    1,028
    Jeff Schwab
    Dec 14, 2003
  2. hdixon
    Replies:
    3
    Views:
    675
    hdixon
    Jul 9, 2006
  3. rp
    Replies:
    1
    Views:
    590
    red floyd
    Nov 10, 2011
  4. Depili
    Replies:
    5
    Views:
    160
    David Vallner
    Jan 13, 2006
  5. Srijayanth Sridhar
    Replies:
    19
    Views:
    674
    David A. Black
    Jul 2, 2008
Loading...

Share This Page