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

hi, again I am hitting a wall at dereferencing stuff ..., I use this stuff too little to grasp it properly. I have this structure:
$VAR1 = [ bless( { 'identifierType' => bless( { 'summary' => 'Asset ta +g of the system', 'label' => 'Asset Tag' +, 'key' => 'AssetTag' }, 'ElementDescription' +), 'identifierValue' => ' unknown' }, 'HostSystemIdentificationInfo' ), bless( { 'identifierType' => bless( { 'summary' => 'OEM spec +ific string', 'label' => 'OEM specif +ic string', 'key' => 'OemSpecificS +tring' }, 'ElementDescription' +), 'identifierValue' => 'Dell System' }, 'HostSystemIdentificationInfo' ), bless( { 'identifierType' => bless( { 'summary' => 'OEM spec +ific string', 'label' => 'OEM specif +ic string', 'key' => 'OemSpecificS +tring' }, 'ElementDescription' +), 'identifierValue' => '5[0000]' }, 'HostSystemIdentificationInfo' ), bless( { 'identifierType' => bless( { 'summary' => 'Service +tag of the system', 'label' => 'Service ta +g', 'key' => 'ServiceTag' }, 'ElementDescription' +), 'identifierValue' => 'XXXXXXXX' }, 'HostSystemIdentificationInfo' ) ];
I need to get the 'identifierValue' => 'XXXXXX' with IdentifierType key 'ServiceTag'

$VAR1 in Data::Dumper is an anonymous array

my $add_info = $host_view->summary->hardware->otherIdentifyingInfo;
I tried this (among other stuff:
foreach (@$add_info) { if ( $_->identifierType->key eq "ServiceTag" ) { print $_->_identifierValue , "\n" ; } }
But I get "Undefined subroutine &HostSystemIdentificationInfo::_identifierValue called at script line 24" so I am failing miserably. Any help greatly appreciated.

Replies are listed 'Best First'.
Re: dereferencing ... again
by davido (Cardinal) on Nov 01, 2013 at 20:32 UTC

    We don't know what accessors your objects provide. Is _identifierValue even a legitimate method? You could break encapsulation like this:

    print $_->{identifierValue}, "\n";

    But I would expect that there's probably a more reliable accessor method if that value is intended to be obtained by the object's user.


    Dave

      hi, Sorry, my programming fu is too limited so I cannot answer your question. This is a part of the VMware API, so it is accessible. I got it to work assigning it like this:
      foreach (@$add_info) { if ( $_->identifierType->key eq "ServiceTag" ) { my $test = $_->identifierValue; print $test, "\n" ; } }
      I dit try printing
      print $_->{identifierValue}, "\n";
      And got this error:
      HostSystemIdentificationInfo=HASH(0xaf5bd70)->identifierValue
      But if I assign that to a variable, it works. O well.

      Update: your suggestion works, I missed the curly braces (blush), so I can skip one step (no need to assign anything).

      Thanks! I have no points to give today, will give tomorrow

        So "identifierValue()" is an attribute accessor for your object. Using $_->{identifierValue} is a kludgy hack, which I proposed in the absence of more information about the object's interface. Now that we know that $_->identifierValue works, where $_->_identifierValue didn't, you can do away with my fragile hack.

        print $_->identifierValue(), "\n";

        ...should work just fine. The reason that we don't want to use $_->{identifierValue} if we can help it is because it's probably not part of the public interface for the object. The author of the class could change its internal implementation and break your code, because you're mucking with the object's internals. I assume that identifierValue() is part of its public interface, and is less likely to change without warning.


        Dave

Re: dereferencing ... again
by AnomalousMonk (Archbishop) on Nov 02, 2013 at 12:01 UTC

    Sometimes "too much is as bad as too little" applies to information as well as other things. In this case, the info supplied by Data::Dumper::Dumper (or whomever you're using to dump your structure) may be confusing: all those  bless({ ... }, 'SomeThing') thingamabobs, what's that about? That's just the way your dumper utility represents a bless-ed reference; in fact, an object reference in this case.

    A Perl object is simply a reference blessed into a package/class (see perlobj, perltoot, among others.). The reference is usually to a hash, but can be any kind of reference.

    Shorn of its blessedness, the dumped data structure can be viewed as an array of anonymous hashes, with each hash harboring an anonymous sub-hash:

    $VAR1 = [ { 'identifierType' => { 'summary' => 'Asset tag of the system', 'label' => 'Asset Tag', 'key' => 'AssetTag', }, 'identifierValue' => 'unknown', }, { 'identifierType' => { 'summary' => 'OEM specific string', 'label' => 'OEM specific string', 'key' => 'OemSpecificString', }, 'identifierValue' => 'Dell System', }, { 'identifierType' => { ..., 'key' => 'OemSpecificString', }, 'identifierValue' => '5[0000]', }, { 'identifierType' => { ..., 'key' => 'ServiceTag', }, 'identifierValue' => 'XXXXXXXX', }, ];
    In fact, it's an array of objects, as shown by the  bless({ ... }, 'PackageName') wrapper of each anonymous hash, with each object containing, along with whatever else, a sub-object.

    As has been pointed out, the blessedness of a reference does not prevent it from being accessed as an ordinary reference using the standard arrow operator:
        $VAR->[1]{identifierType}{label} = 'whatever';
        if ($VAR->[2]{identifierValue} eq ...) { ... }
    However, Don't Do That! As davido has wisely advised, use the accessor/mutator (get/set) methods that are or should have been provided with the class. If such a method does not exist for the data you want to access, this may be telling you that you should not be accessing this data and should think again about what you want to do. (OTOH, lack of such a method may simply mean that the class is badly designed!)