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

Hello, Monks ...

I'm trying to turn my previous question into a learning exercise, but I'm not getting far. My goal is to create two modules: "Tie::Time::Scalar" and "Tie::Time::Array". You'll see from the code below, that I've been partway successful, but I've hit a couple of walls (not the larry kind).

(note that, when everything is working, I'll do the proper "h2xs" thing, and all of the proper module packaging and stuff, but for now, I just want to understand things.)
#!/usr/bin/perl -w use strict; package TieTimeScalar; sub TIESCALAR { bless {}, shift } sub FETCH { scalar localtime } package main; my $now; tie ($now, "TieTimeScalar"); while (1) { print "$now\n"; sleep 1 }
The above code works perfectly (and is basically no more than what merlyn spoon-fed me.)

However, when I try to do the same thing but tying the 9-element list output of localtime to an array with the following code ...
#!/usr/bin/perl -w use strict; package TieTimeArray; sub TIEARRAY { bless {}, shift } sub FETCH { my @self = localtime ; return @self } sub FETCHSIZE { my $self = shift ; return scalar @{$self->{@self}} } package main; my @now; tie (@now, "TieTimeArray"); while (1) { print "@now\n"; sleep 1 }
... I get the error ...
Can't use an undefined value as an ARRAY reference at ./TieTimeArray l +ine 8.
Obviously, I'm missing something fundamental to the concept of tying arrays (and probably just tying in general.)

Would someone like to try to explain to me what I'm doing wrong here (maybe in small words, so my little brain can understand)?

Also, man perltie talks about implementing the STORE, UNTIE and DESTROY methods (for scalars) and also STORESIZE for arrays. Are these needed in every class that implements tying? What would those methods do? And why would I want to do them?

Thanks, --Sandy (who is drowning in an ocean of camel poop)

Replies are listed 'Best First'.
Re: more on tying localtime
by stefp (Vicar) on Sep 28, 2001 at 05:40 UTC
    I would (not) do:
    #!/usr/bin/perl -w use strict; package TieTimeArray; sub TIEARRAY { bless [], shift } sub FETCH { (localtime)[$_[1]] } sub FETCHSIZE { 9 } package main; my @now; tie (@now, "TieTimeArray"); while (1) { local $"=' '; print "@now\n"; sleep 1; }

    It compile and works (sort of). Indeed we hit a problem with the array tie design. you can't ask array content as a whole, so we ask local time for each element of the array. We hit the problem that gray codes are designed to avoid (pointer pending) Suppose that thru one defererence of @now, we ask time at 3:00 59.99999 sec to get the seconds, than again a jiffy later at 3:01 0 sec to get the minutes. We will give as a result 3:01 59 sec. Not good when it is instead 3:01 0 sec

    So this is not really a good approach. So consider it only as a rather silly example of array tie code. If you want to tie here, tie to scalar.

    -- stefp

      wow. ok, you've gone a bit beyond my comprehension, but I think I understand the problem, as you explain it, and see why this might be difficult.

      thanks for the info; I'll try to digest it into my brain. :-)

      --sandy
Re: more on tying localtime
by jryan (Vicar) on Sep 28, 2001 at 05:44 UTC

    This'll work for ya:

    #!/usr/bin/perl -w use strict; package TieTimeArray; sub TIEARRAY { my $class = shift; my $self; $self->{ltime} = [localtime]; bless($self, $class); } sub FETCH { my ($self, $index) = @_; $self->{ltime}= [localtime]; +return $self->{ltime}->[$index] } sub FETCHSIZE { my $self = shift; return scalar @{$self->{ltime}} } package main; my @now; tie (@now, "TieTimeArray"); while (1) { print "@now\n"; sleep 1 }

    The reason yours wasnt working before was because you didn't intitialize localtime in the constructor. However, your FETCH wouldnt work anyways because you were trying to return an array when a scalar was expected. FETCH returns the next element of the array, not the entire thing. Also, I stored your data in the object itself, which is handy just in case you need to reference it later. Finally, I threw in the 2 argument form of bless just in case that the class might need to be subclassed later. Its good practice to do anyways :)

      This suffers of the very problem I described. It is evil to bind to an array when it is in effect a (here multibase) counter because it can wrap under you.

      -- stefp

        Yes, of course. That's why no one uses tied arrays :) He just wanted to know how to do one, so I gave him one way to solve the problem. I'm pretty confident that he won't be using it in regular practice, but its still a good way to learn about tied variables and classes.