http://qs321.pair.com?node_id=198854

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

Hello,

I have a class called 'Datum' that implements the tied scalar interface. This class's constructor returns a tied scalar ref at present. This means that in my code, the returned scalar object must be dereferenced as '$$scalar'.

The $$ dereferencing is the problem.

I would like to write a method, module, C extension, or whatever it takes to have the class's new method return an object that may be used exactly as if it were a scalar, but this new magic variable also accepts method invocation and and supports running my code on STORE FETCH etc. I guess this might even be considered a new variable type, based on scalar.

I know that I can tie the scalar to my Datum class all over my code, but that's very tedious as there are hundreds of them in my programs

eg.

use Datum; my $d = Datum->new(-type => date); $d = "Nov 25, 1971"; print STDOUT "\$d contains $d"; # "Nov 25, 1971" print STDOUT "\$d as unixtime:", $d->to_unixtime, "\n"; exit 0;

Is this possible in perl5? Would I have to write an XS module instead?

Thanks!

rr

  • Comment on How might I return tied scalar that does not have to be dereferenced as $$scalar?
  • Download Code

Replies are listed 'Best First'.
Re: How might I return tied scalar that does not have to be dereferenced as $$scalar?
by chromatic (Archbishop) on Sep 18, 2002 at 15:59 UTC

    Seems to me you can just throw a tie call in new -- and don't call bless. If you provide a FETCH method along with your other methods, you should be okay.

    Of course, if all you want to do is to provide a sane value for $d when it's stringified, you can use the overload pragma to overload the stringification operator. That may be even simpler.

(tye)Re: How might I return tied scalar that does not have to be dereferenced as $$scalar?
by tye (Sage) on Sep 18, 2002 at 16:14 UTC
    Datum->tieVar( (my $d), -type=>'date' ); ... package Datum; sub tieVar { my $class= shift @_; my $toTie= \$_[0]; shift @_; tie $$toTie, $class, @_; }
            - tye
Re: How might I return tied scalar that does not have to be dereferenced as $$scalar?
by fglock (Vicar) on Sep 18, 2002 at 16:22 UTC
Re: How might I return tied scalar that does not have to be dereferenced as $$scalar?
by dada (Chaplain) on Sep 20, 2002 at 12:12 UTC
    this isn't completely possible. no matter what you do with tie, bless, etc. the following lines won't work as you expect:
    $d = "Nov 25, 1971"; print "\$d contains $d\n"; # "Nov 25, 1971" print "\$d as unixtime:", $d->to_unixtime, "\n";

    with a tie, you can't directly do $d->to_unixtime, it has to be tied($d)->to_unixtime. otherwise you'll get the message: Can't locate object method "to_unixtime" via package "Nov 25, 1971" (perhaps you forgot to load "Nov 25, 1971"?)

    with a regular object, you can't of course do $d = "Nov 25, 1971" because this would destroy the object previously assigned to $d.

    the most functional hack I could come up with is the use of tie AND overload AND tye's suggestion, as in:

    Datum->tieVar( (my $d), -type=>'date' ); $d = "Nov 25, 1971"; print STDOUT "\$d contains $d\n"; # "Nov 25, 1971" print STDOUT "\$d as unixtime:", $d->to_unixtime, "\n"; package Datum; use overload '""' => \&to_string; sub tieVar { my $class= shift @_; my $toTie= \$_[0]; shift @_; tie $$toTie, $class, @_; } sub TIESCALAR { my $class = shift; my $instance = shift || undef; return bless \$instance => $class; } sub STORE { ${$_[0]} = $_[1]; } sub FETCH { # this just returns "self" # (won't be good in some cases) return $_[0]; } sub to_string { # this is the "real" FETCH method return ${$_[0]}; } sub to_unixtime { return "foobar"; }
    this prints what you expect:
    $d contains Nov 25, 1971 $d as unixtime:foobar
    ...but this is a hack, as it works correctly only when fetching $d in a string context. it has the implicit advantage, however, that $d could return something different (perhaps $d->to_unixtime) in numeric context.

    cheers,
    Aldo

    King of Laziness, Wizard of Impatience, Lord of Hubris

      Hello Aldo

      I guess that what I want to do is not possible without creating new basic variable types. This project is for an OSS database abstraction layer that I wrote that automatically scavenges the db for meta information, creates classes to represent rows in tables. Each class then uses a collection of the Datum instances. This Datum class does type checking based on it's SQL type in the DB, and formats things correctly. You can provide additional type checking by configuration file (like dbname.table.colum Datum's must be all CAPS).

      My purpose in posting was to find a way to make coding with these objects faster by getting rid of using methods to update/get the values of the Datum instances. Using the overload+tie kinks above give me most of what I need. Too bad you cannot overload the assignment operator.

      Again, thanks to all all for your input.

      rr