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

I've run into some strange behavior when passing objects around in Perl 5.6.1 I'm writing a class ("Emitter") that represents a hidden state in a hidden markov model. An Emitter instance contains a transition table, which contains other Emitter instances. The idea is to have a transition method so that calling $emitter->transition() returns the next Emitter in the Markov chain. The problem is that running :
$next_emitter = $current_emitter->transition(); print $next_emitter->emit() . "\n";
results in
Can't locate object method "emit" via package "Emitter=HASH(0x1016c9c0)" (perhaps you forgot to load "Emitter=HASH(0x1016c9c0)"?) at HMM/ODCRollGenerator.pm line 100.
Indeed,
ref($an_emitter->transition());
results in Emitter=HASH(0x1016c9c0) whereas
ref($an_emitter)
gives Emitter as expected.

Within an Emitter, the transition table is stored as a hash, with the other Emitter instances as the keys, and the transition probabilities as the values. i.e. the setter method looks like this:

sub transitions { my $self = shift; if (@_) { $self->{TRANSITIONS} = shift; &_build_prob_table($self); } return $self->{TRANSITIONS}; }
and it might be called like this:
$self->{START} = Emitter->new(); $self->{FAIR} = Emitter->new(); $self->{LOADED} = Emitter->new(); ... $self->{START}->transitions( { $self->{FAIR} => 0.5, $self->{LOADED} => 0.5 } );

Now, I can make things work by re-blessing the reference returned by transition(), but this seems awfully kludgy, and I suspect there is a better way to do this. Besides, as I understand it, it's the underlying thingy, not the reference, that is blessed. Anyone know what's going on here? Is there some magic I need to add to the class to keep the blessing attached to objects?

Replies are listed 'Best First'.
Re: objects becoming unblessed?
by jand (Friar) on Mar 17, 2003 at 16:50 UTC
    Hash keys in Perl are always strings. When you use the transition objects as keys, they are stringified (as "Emitter=HASH(0xDEADBEEF)"). When you retrieve the key, it is no longer a reference to the object, but just a plain string.
Re: objects becoming unblessed?
by dragonchild (Archbishop) on Mar 17, 2003 at 18:00 UTC
    jand has the solution to the problem you have (the blessing problem, not the Markov problem). If you want to continue with your data structure, you should modify what your transitions table looks like. You can stringify the reference and use that as the key (though there's better ways of doing it). However, instead of pointing to the values directly, you'll need to point to an array reference where the first value there is the values and the second is the Emitter object.

    Now, better would be to turn your problem around. From what I understand of Markov chaining, you need to calculate some value which is the next value in the chain. Then, based on that value, you want to return some emitter object. Why not just use the Markov values as the keys and the objects as the values in your transitions hash?

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      yes, jand is correct. To clear up the confusion, there are two methods: transitions() (with an s) is the getter/setter for the transitions table, and transition() (no s) picks an Emitter from the transitions table and returns it.

      I'm going to go back and just store these things in an array, rather than in a hash.

      As for the Markov model - I'm using this code to generate a sequence of states + emissions. So the algorithm is

      emit a value->transition to the next state-> if current state isn't the end state then repeat.
      Of course, the next step is to write the code that goes back and tries to figure out what the hidden states were based solely on the emissions.
Re: objects becoming unblessed?
by derby (Abbot) on Mar 17, 2003 at 17:09 UTC
    but the transition is never an Emitter object/instance to begin with, it's just an anonymous hash ref.

    sub transitions { my $self = shift; if (@_) { $self->{TRANSITIONS} = shift; ....

    Here you set the TRANSITION to the anonymous hash and here

    ... return $self->{TRANSITIONS};

    You just return it.

    -derby

    update Please disregard and follow jand's advice.

      You are overlooking that the original code has both a transition() and a transitions() method, where only the code for the later has been provided. I was assuming that the former would choose a random transition from the hash, based on the transition probabilities. Obviously a hash is not a good data structure for this. A sorted array of arrays would allow to retrieve the original Emitter objects, and also provide for optimization of the random selection function. See the recent Weighted random numbers generator topic.
        Jand,

        I did miss the transitions and I agree about the data structure; however, if transitions is used to populate the data structure, it's not populating it with Emitter objects, but anonymous hashes. The transition (no s) used to move through the data structure, will need to create the objects (either via an object constructor or an initial blessing of the anon hash into the Emitter class).

        From the snippets provided, it appears the objects have not become unblessed but were never blessed in the first place.

        -derby