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

I was looking for a way to have a Perl Object that works in the same time as a Hash, Array and Scalar object (blessed references).

To do that I have used 3 resources/modules: Symbol, overload and tie(Hash).

Update:
See Object::MultiType - Perl Objects as Hash, Array & Scalar in the same time!
Source at: http://www.inf.ufsc.br/~gmpassos/Object-MultiType-0.01.tar.gz

Here's a code to show how to implement that (without tie):

#!/usr/bin/perl my $obj = Multi->new() ; my $string = $obj ; $string .= '_x' ; print "*** $string\n" ; my $hash_a = $obj->{A} ; print "$hash_a\n" ; my $array_0 = $obj->[0] ; print "$array_0\n" ; $obj->method(qw(z y z)) ; print "Me as scalar: $obj\n" ; ######### # MULTI # ######### package Multi ; use Symbol ; use overload ( '""' => 'string' , '=' => 'copy' , '0+' => 'copy' , '@{}' => 'get_array' , '%{}' => 'get_hash' , 'fallback' => 1 , ) ; sub new { my $class = shift ; my $this = gensym ; bless($this,$class) ; my $scalar = 'Foo' ; *$this = \$scalar ; *$this = [qw(a b c)] ; *$this = {A => 10 , B => 20 , C => 30} ; return( $this ) ; } sub method { my $this = shift ; print "METHOD>> @_\n" ; } sub string { my $this = shift ; return( ${*$this} ) ; } sub copy { my $this = shift ; return( substr(${*$this} , 0 ) ) ; } sub get_array { my $this = shift ; return( \@{*$this} ) ; } sub get_hash { my $this = shift ; return( \%{*$this} ) ; } 1;
To use the Hash reference with tie, in the new() just make:
my %hash ; tie(%hash, 'TieHash' , $this) ; *$this = \%hash ; ## In the place of: ## *$this = {A => 10 , B => 20 , C => 30} ;
So now you can make:
$obj->{key} ; $obj->[0] ; print "Scalar: $obj" ;
For me this works. I want to know if already exist some Perl module with that, or other way to do!

If doesn't exit a module for that yet will make one... Maybe Object::MultiType. ;-p

Graciliano M. P.
"The creativity is the expression of the liberty".

Replies are listed 'Best First'.
Re: Perl Object as Hash, Array & Scalar in the same time! ( $O->{k} | $O->[0] | $O )
by Abigail-II (Bishop) on May 09, 2003 at 21:32 UTC
    I don't know any module that uses this, but I've seen globs as objects before (IIRC, some Net:: modules use globs too, but then to be able to use them as handles). I've done some proof of concept coding using globs as references to be able to do multi-inheritance where one class uses an arrayref, and another class uses a hashref. But that wasn't at all pretty.

    And of course, one could always use pseudo-hashes.... ;-)

    Abigail

      ... Again (see my reply to PodMaster). You really need to access the data using GLOB, since you overload the normal acces for HASH, ARRAY and SCALAR in the same time!

      "some Net:: modules use globs too, but then to be able to use them as handles"

      Yes, I saw that, and was from there that I got the GLOB idea to fix the overload problem! ;-P

      Graciliano M. P.
      "The creativity is the expression of the liberty".

Re: Perl Object as Hash, Array & Scalar in the same time! ( $O->{k} | $O->[0] | $O )
by theorbtwo (Prior) on May 10, 2003 at 02:30 UTC

    You might want to take a look at Dominus' ArrayHashMonster.


    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

Re: Perl Object as Hash, Array & Scalar in the same time! ( $O->{k} | $O->[0] | $O )
by djantzen (Priest) on May 09, 2003 at 21:34 UTC

    A question, why doesn't $this get overwritten in the symbol table?

    *$this = \$scalar ; *$this = [qw(a b c)] ; *$this = {A => 10 , B => 20 , C => 30} ;
    I guess the prepending of '*' is causing a separate entry to be written out for each data type?

    Also, what is this for? Typically in OOP you really don't want other code accessing data members directly, but rather through methods. It is neat though :^)


    "The dead do not recognize context" -- Kai, Lexx
      read `perldoc perldata' (the "Typeglobs and Filehandles" section), and `perldoc perlmod' (the "Symbol Tables" section).


      MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
      I run a Win32 PPM repository for perl 5.6x+5.8x. I take requests.
      ** The Third rule of perl club is a statement of fact: pod is sexy.

      $this is a GLOB ref (see Symbol::gensym). Inside it the 3 types are saved for future access.

      Why I need this?! Well, I need to have the 3 types for a new way to access XML/HTML data. Scalar for the content, Array to index tags with the same name and in the same sub-tree, Hash to return an argument or other tree object. Is hard to explain all here, but I will announce here the module when it's done.

      Graciliano M. P.
      "The creativity is the expression of the liberty".

Re: Perl Object as Hash, Array & Scalar in the same time! ( $O->{k} | $O->[0] | $O )
by PodMaster (Abbot) on May 09, 2003 at 22:25 UTC
    Don't do it, at least not like that.

    Global variables under the guise of being lexicals just so you can have the benefit of globs?

    I say get perlxs involved, that way a lexical remains really a lexical, and not *Symbol::GEN0.

    update: Hey, that'd make a good module, Lexical::Typeglob, right up there with Lexical::Alias.


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    I run a Win32 PPM repository for perl 5.6x+5.8x. I take requests.
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      Well, I know that Symbol::gensym keep a reference to an global GLOB at Symbol::GENx. What is not very good at POO. But for GLOB you need to keep it in some point!

      To fix that the code need a DESTROY that destroy the GLOB too.

      Note that you really need to put the different types inside the GLOB! You can't use a hash ref, since you want to do: $this->{key}, and this will go to get_hash(), and inside it you can't use $this->{key} or $this->[0], or you make an infinity loop of nothing. So, if you bless a hash, but make the access of it using overload you can't access again the hash, specially if you want to use overload for ARRAY access too!!! This is why I use GLOB, since is the only way that I found to access data inside the object wihtout use ways that are overloaded.

      If you can find a way to make the same thing without Symbol::gensym (GLOB), please send! ;-P

      Update:
      From POD: "Symbol::gensym creates an anonymous glob and returns a reference to it"!
      The GLOB is already anonymous! Test to creat multiples GLOB from gensym(), you can see that is always *Symbol::GEN0.

      Graciliano M. P.
      "The creativity is the expression of the liberty".

        No, clearly every gensym object occupies a new GEN# slot in the Symbol package. Also - DESTROY is completely innappropriate here. You cannot call ->DESTROY on an object and have it actually free the object. The ->DESTROY method is called by perl when the object is being destroyed - you can't provoke it by calling it yourself.

        perl -MB -MSymbol -e '$,=$\="\n";push @A,gensym for 0 .. 10;@B=map B::svref_2object($_), @A; print $_->STASH->NAME."::".$_->NAME for @B'