Yoda_Oz has asked for the wisdom of the Perl Monks concerning the following question:

i cant seem to get the right output from a hash...
#!/usr/bin/perl package Vehicle; sub new { my($class) = shift; my(%params) = @_; bless { "Engine" => $params{"Engine"}, "Doors" => $params{"Doors"} }, $class; } package Car; our @ISA = (Vehicle); sub new { my($class) = shift; my(%params) = @_; my($self) = Vehicle->new(@_); $self->{"Colour"} = $params{"Colour"}; return(bless($self, $class)); } package main; my $car = Car->new( "Engine" => "1800cc", "Doors" => "4", "Colour" => "blue"); print("I have an " . %{$car}->{'Engine'} . "\n"); print("I have " . %{$car}->{'Doors'} . "\n"); print("The color is " . %{$car}->{'Colour'} . "\n");
the output of this is:
I have an 1800cc I have 4 The color is blue
how can i change this code so that the output is this:
I have an Engine 1800cc I have 4 Doors The color is Colour blue
Obviously the inserted words (Engine, Doors and Colour) are within the hash on the left-hand-side. how do i get them to display as well as the ones on the right-hand-side, which already appear???

Considered: rinceWind: "Dupe of 592857" Vote was Keep: 11, Edit: 0, Reap: 17
Unconsidered: davido: Sufficient keep votes and positive node reputation prevent reaping. Please don't reconsider.

Replies are listed 'Best First'.
Re: Hash from package
by jbert (Priest) on Jan 04, 2007 at 09:31 UTC
    Hi. First things first. You really always want to have:
    use strict; use warnings;
    as the first lines of your script. It'll help eliminate false alarms when looking for problems like this, and it is much easier to always start with it in then try and add it in later.

    If you do that, you'll see that perl wants you to write the hash accesses as $foo->{'bar'}, not %{$foo}->{'bar'}. You'll also see that you want to have our @ISA = ('Vehicle'); I think those are the only things it throws up.

    As for your question, $hash_ref->{$key} is an expression for the value you get when looking up the key in the hash. It doesn't return the key itself, but then again, you don't need that since you've just used the key to look up in the hash, so you'll always have it to hand.

    If you want to print keys and values, do you'll need to do it explicitly:

    foreach my $key (keys %$hash_ref) { print "I have $key $hash_ref->{$key}\n"; }
    Lastly, if you're doing OO in perl, you might want to use one of the (too many) helper modules, such as Class::Accessor or Moose. Also, rather than setting @ISA directly, I find use base qw(Vehicle); a nicer way to express inheritance in perl.

    Good luck.

      aha! thanks a lot champ! worked it out!
Re: Hash from package
by GrandFather (Saint) on Jan 04, 2007 at 10:36 UTC

    This and your previous question are both really about OO design. Think about what should be part of the interface for the base class and provide support for that. For example, if you want to have an object describe itself you could do something like:

    use strict; use warnings; package Vehicle; sub new { my $class = shift; # Provide some defaults my $self = {wheels => 4, engine => 1800, doors => 4}; return bless $self, $class; } sub describe { my $self = shift; return <<"desc"; My engine is $self->{engine}cc. I have $self->{wheels} wheels and $self->{doors} doors. desc } package Car; our @ISA = ('Vehicle'); sub new { my $class = shift; my $self = new Vehicle ($class); $self->{colour} = 'blue'; return bless $self, $class; } sub describe { my $self = shift; my $str = $self->SUPER::describe (); return $str . <<"desc"; My colour is $self->{colour}. desc } package main; my $car = new Car; print $car->describe ();

    Prints:

    My engine is 1800cc. I have 4 wheels and 4 doors. My colour is blue.

    Although actually that is still pretty nasty. Consider what would happen if you needed a bike: no engine and no doors, or even worse a monocycle with only one wheel ("I have 1 wheels and 0 doors.").

    A good starting point for some of this stuff is perlboot, but take a look around the Tutorials area too.


    DWIM is Perl's answer to Gödel
Re: Hash from package
by wfsp (Abbot) on Jan 04, 2007 at 09:28 UTC
    within the hash on the left-hand-side
    Those are called keys

    my %hash = qw(Engine 1800cc Doors 4 Color blue); for my $key (keys %hash){ print "$key -> $hash{$key}\n"; }
    updated: straightened out the syntax
      so how can i use that with my original post?:
      my %hash = qw(Engine 1800cc Doors 4 Color blue); for my $key (keys %hash){ print "$key -> $hash{$key}\n"; }
        for my $key (keys %{$car}){ print "$key -> $car->{$key}\n"; }
        Directly accessing the attributes of an object like that would likely be considered poor form.

        Have a look through the docs and look out for 'getters' and 'setters'.

        Object-Oriented Tutorial specifically discusses getters and setters.

        updated: added link to tutorial

Re: Hash from package
by Sagacity (Monk) on Jan 04, 2007 at 09:01 UTC
    This is my first post -- I hope it helps! Looking at your code, modify it as follows: print("I have an Engine " . %{$car}->{'Engine'} . "\n"); print("I have " . %{$car}->{'Doors'} . " Doors\n"); print("The color is Colour " . %{$car}->{'Colour'} . "\n"); Don't forget the spaces as needed in the print command. Good Luck, Sagacity

      Erm, %{$hashref}->{'key'} has some extra line noise in it. You'd really want either $car->{'key'}, or alternately ${ $car }{ 'key' }. You don't use the hash sigil when accessing a single element, just like you don't use @array[$idx] to access a single element from an array.</nit>

      thanks for the post mate. however thats not quite what im after. that's cheating what you've suggested.
      i want those words you added in to come from the hash, not from adding to the print statement.

      ie.
      %hash => (Engine, 1800cc, Doors, 4, Color, blue)
      print %hash
      output is:
      Engine 1800cc
      Doors 4
      Color blue

      do you see where im coming from?
        I wouldn't call it cheating. You've already hardcoded some text and the hash key. Sagacity's suggestion is perfectly reasonable.

        You're probably asking the wrong question. "How do I get key values from a hash?" is more likely what you're after.

        foreach my $key (keys %$car) { print "$key = $car->{$key}\n"; }
        ---
        my name's not Keith, and I'm not reasonable.
Re: Hash from package
by bart (Canon) on Jan 04, 2007 at 12:03 UTC
    And just how do you suppose the program would know you want "Engine" on the left, and "Doors" on the right?

    Apart from that, you could write a generic method that returns a string containing both property name and value, in one string. Not that I see much use in it.