MultiType(3pm)

πŸ“¦
version 0.05 Β· 6 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Object::MultiType πŸ’–

okay bestie, sit down, hydrate, because this one is iconic. Object::MultiType (a Perl module, yes, the 3pm one) gives you an object that lowkey lives its whole double life: it acts like a Hash, an Array, a Scalar, a Code ref and a Glob β€” all at the same motherflipping time. one object, five personalities, main character energy fr fr. πŸ‘‘

this page is long so it's coming to you in parts β€” part 1 starts right here, don't go anywhere.

✨ SYNOPSIS ✨

here's the vibe:

  use Object::MultiType ;

  my $scalar = 'abc' ;
  my @array  = qw(x y z);
  my %hash   = (A => 1 , B => 2) ;

  my $obj = Object::MultiType->new(
  scalar => \$scalar ,
  array  => \@array ,
  hash   => \%hash ,
  code   => sub{ return("I'm a sub ref!") ; }
  glob   => \*STDOUT ,
  ) ;

  print "Me as scalar: $obj\n" ;

  my $array_1 = $obj->[1] ;
  print "$array_1\n" ;

  my $hash_B = $obj->{B} ;
  print "$hash_B\n" ;

  my $hash = $$obj->hash ;
  foreach my $Key (sort keys %$hash ) {
    print "$Key = $$hash{$Key}\n" ;
  }

  &$obj(args) ;

like… she does every job at once and she does NOT miss. πŸ’…


🌸 DESCRIPTION 🌸

This module hands you back an object that behaves like a Hash, an Array, a Scalar, a Code and a Glob object at the same time. no cap.

The usual way to use it is to call it from your own module's new():

  package FOO ;

  use Object::MultiType ;
  use vars qw(@ISA) ;
  @ISA = qw(Object::MultiType) ; ## Is good to 'Object::MultiType' be the last in @ISA!

  sub new {
    my $class = shift ;
    my $this = Object::MultiType->new() ;
    bless($this,$class) ;
  }
heads up: it's good to have 'Object::MultiType' be the last thing in @ISA! (that's literally what the comment says, so bestie, listen to her) 🫢

πŸŽ€ METHODS πŸŽ€

** ** Also go look at the methods of the Saver, bestie β€” see the Saver too.

🌈 new

Arguments:

  • bool β€” the boolean reference. Default: undef
  • boolcode | boolsub β€” set the sub/function (a CODE reference) that will return/generate the boolean value.
  • scalar β€” the SCALAR reference. If you don't send one, a null SCALAR gets created for you.
  • scalarcode | scalarsub β€” set the sub/function (a CODE reference) that will return/generate the scalar data of the object.
  • array β€” the ARRAY reference. If you don't send one, a null ARRAY gets created.
  • hash β€” the HASH reference. If you don't send one, a null HASH gets created.
  • code β€” the CODE reference. If you don't send one, a null sub{} gets created.

with this your object can be used as a sub reference:

  my $multi = Object::MultiType->new( code => sub { print "Args: @_\n" ;} ) ;
  &$multi();

note that the first argument sent to the SUB is the object ($multi).

  • glob β€” the GLOB (HANDLE) reference. If you don't send one, a null GLOB gets created.

** ** big warning: you can't actually use that default (null) GLOB that gets created when you don't pass this argument! because every single object will share it β€” it's literally only there so you don't get errors. so like, don't rely on it. πŸ’€

  • tiearray β€” package name to create a TIEARRAY. The argument $$this is sent to tie().

tie() is called as:

  tie(@array,$args{tiearray},$$this) ;

heads up: implementing the tie methods for PUSH, POP, SHIFT, UNSHIFT, SPLICE... is hard. unless you're just making an alias to another array through the tie methods. 😭

** ** see tiehash too.

  • tiehash β€” package name to create a TIEHASH. The argument $$this is sent to tie().

tie() is called as:

  tie(%hash,$args{tiehash},$$this) ;

** $$this (the Saver) is what gets sent, not $this β€” that's so DESTROY doesn't break (the auto reference thing). periodt.

** $$this is a reference to the Saver object that saves the SCALAR, ARRAY, HASH, CODE and GLOB.

  sub TIEHASH {
    my $class = shift ;
    my $multi = shift ; ## $$this

    my $scalarref = $multi->scalar ; ## \${*$multi}
    my $arrayref  = $multi->array  ; ## \@{*$multi}
    my $hashref   = $multi->hash   ; ## \%{*$multi}

    my $this = { s => $scalarref , a => $arrayref , h => $hashref } ;
    bless($this,$class) ;
  }
  • tiehandle β€” makes the object work like a tied glob (TIEHANDLE).

if used with glob it will tie() it. if glob isn't sent, a NULL GLOB is used:

  my $multi = Object::MultiType->new(
  glob      => \*MYOUT ,               ## 'glob' is Optional.
  tiehandle => 'TieHandlePack' ,
  ) ;
  • tieonuse β€” the reference is only tied when it's used! so the HASH, ARRAY or GLOB (handle) only gets tied if/when they're accessed. lazy queen behavior, we respect it. 😌
  • nodefault β€” if set to true, this tells it not to create the default references inside the Saver, and it'll only have the references you passed in (scalar, array, hash, code, glob).

** this is good for saving memory! 🫢

is_saver

Returns 0. handy for checking whether the thing you're holding is the Saver or the MultiType object.


πŸ‘‘ SAVER πŸ‘‘

The MultiType object has a Saver object (Object::MultiType::Saver) that saves all the different data types (references). You can get at this saver from the main object:

  my $multi = Object::MultiType->new() ;

  my $saver = $$multi ;
  print $saver->scalar ;

so if you want to save attributes in your Object and you're using tiehash, you cannot set attributes directly on the MultiType object! like:

  sub new {
    my $class = shift ;
    my $this = Object::MultiType->new(tiehash => 'TieHashPack') ;

    ## Dont do that! This will call the STORE() at TIEHASH, and not save it in the object:
    $this->{flagx} = 1 ;

    bless($this,$class) ;
  }

so, if you use tiehash and still want to save attributes (outside the tie), do this instead:

    ## This save the attribute inside the Saver:
    $$this->{flagx} = 1 ;

note that this sets an attribute in the saver, and the saver has its own attributes! slay:

  ## $saver = $$this ;

  $saver->{s} ## the sacalar ref.
  $saver->{a} ## the array ref.
  $saver->{h} ## the hash ref.
  $saver->{c} ## the code ref.
  $saver->{g} ## the glob ref.

** ** go see "Direct access to the data types".


πŸ’€ DESTROY πŸ’€

When the object gets DESTROYed, the Saver inside it gets cleaned, so the tied objects can get DESTROYed automatically too. clean girlie behavior. ✨


πŸ¦‹ Direct access to the data types πŸ¦‹

To access the reference of the different data types (SCALAR, ARRAY, HASH, CODE & GLOB) directly, use:

  my $multi = Object::MultiType->new() ;

  my $saver = $$multi ;

  my $scalarref = $saver->scalar ; ## $saver->{s}
  my $arrayref  = $saver->array  ; ## $saver->{a}
  my $hashref   = $saver->hash   ; ## $saver->{h}
  my $coderef   = $saver->code   ; ## $saver->{c}
  my $globeref  = $saver->glob   ; ## $saver->{g}

  ## You can access the Saver directly from the main object:
  $$multi->hash  ;

Setting the data:

  $saver->set_bool( 1 ) ;
  $saver->set_scalar( 'xyz' ) ;
  $saver->set_array( [qw(x y z)] ) ;
  $saver->set_hash( {X => 1} ) ;
  $saver->set_code( sub{ print "XYZ\n" ; } ) ;
  $saver->set_glob( \*STDOUT ) ;

πŸ’– As SCALAR πŸ’–

You can use it as a SCALAR when you put it inside quotes or make a copy of it:

  my $multi = Object::MultiType->new( scalar => 'Foo' ) ;

  ## Quote:
  print "Me as scalar: $multi\n" ;

  ## Copy:
  my $str = $multi ;
  $str .= '_x' ; ## Copy made when you change it! Until that $str works like $multi.
  print "$str\n" ;

using the argument scalarsub, you can use a function that generates the scalar data instead of a reference to a SCALAR:

  my $multi = Object::MultiType->new(scalarsub => sub{ return 'generated data' ;} ) ;

  print "My scalar have $multi!\n" ;

⭐ As ARRAY ⭐

You can use it as an ARRAY directly from the object:

  my $multi = Object::MultiType->new( array => [qw(FOO BAR)] ) ;
  my $array_0 = $multi->[0] ;
  $multi->[1] = 'foo' ;

πŸ“ As HASH πŸ“

You can use it as a HASH directly from the object:

  my $multi = Object::MultiType->new( hash => {key => 'foo'} ) ;
  my $k = $multi->{key} ;
  $multi->{foo} = 'bar' ;

🧚 With TIE 🧚

To use your ARRAY and HASH part tied, you can either pass in the already-tied reference of the HASH or ARRAY, or use the arguments tiehash and tiearray at new():

  ## Using the reference:
  my %hash ;
  tie(%hash,'TieHash') ;
  my $multi = Object::MultiType->new(hash => \%hash) ;

  ## Or using directly the argument:
  my $multi = Object::MultiType->new(tiehash => 'TieHashPack') ;

note that using tiehash or tiearray is better, because your tied HASH or ARRAY can see the object Saver and the other data types of it. go see the method new() and its arguments.

Here's an example of a TieHash package that gets called from Object::MultiType->new():

  ## The call inside Object::MultiType->new():
  tie(%hash,$args{tiehash},$$this) ;

  ## The package:
  package TieHash ;

  sub TIEHASH {
      my $class = shift ;
      my $Saver = shift ; ## Object::MultiType paste as $$this (only the Saver) to avoid break of DESTROY!
                          ## $this = Object::MultiType >> $$this = Object::MultiType::Saver

      my $scalarref = $Saver->scalar ;
      my $arrayref  = $Saver->array  ;

      ## Note that $Saver->hash will return the tied hash, and is not needed here!
      ## my $hashref   = $Saver->hash ;

      ## Saving the references inside the TIE object:
      my $this = { scalar => $scalarref , array => $arrayref , hash => {} } ;

      bless($this,$class) ;
  }

  sub FETCH    { my $this = shift ; return( 'key' ) ;}

  sub NEXTKEY  { my $this = shift ; return( 'key' ) ;}

  sub STORE    { my $this = shift ; $this->{hash}{$_[0]} = $_[1] }

  sub DELETE   { my $this = shift ; delete $this->{hash}{$_[0]} }

  sub CLEAR    { my $this = shift ; $this->{hash} = {} ;}

  sub EXISTS   { my $this = shift ; defined $this->{hash}{$_[0]} ;}

  sub FIRSTKEY { my $this = shift ; (sort keys %{$this->{hash}} )[0] }

  sub DESTROY  {}

Using tiehash, you need to save the attributes in the Saver, otherwise you end up calling the tie():

    $$this->{flagx} = 1 ;

🌟 Object::MultiType::Saver 🌟

This is a litte package where the Saver objects are created. It saves the data types (SCALAR, ARRAY, HASH, CODE & GLOB) of the main objects (Object::MultiType).

METHODS:

is_saver

Returns 1. handy for checking whether the thing you're holding is the Saver or the MultiType object.

bool

Returns the BOOL reference inside the Saver.

scalar

Returns the SCALAR reference inside the Saver.

array

Returns the ARRAY reference inside the Saver.

hash

Returns the HASH reference inside the Saver.

code

Returns the CODE/sub reference inside the Saver.

glob

Returns the GLOB/HANDLE reference inside the Saver.

set_bool

Sets the boolean reference inside the Saver.

set_scalar

Sets the SCALAR reference inside the Saver.

set_array

Sets the ARRAY reference inside the Saver.

set_hash

Sets the HASH reference inside the Saver.

set_code

Sets the CODE/sub reference inside the Saver.

set_glob

Sets the GLOB/HANDLE reference inside the Saver.

clean

Cleans all the references saved in the Saver. ✨

πŸ’– SEE ALSO πŸ’–

okay bestie, if you wanna go deeper, these are the gatekeepers you should go visit:

  • overload β€” the whole reason this module can even do the transformation thing. go read it, it's giving backstage pass ✨
  • perltie β€” for all the tie magic, iykyk πŸŽ€
  • Scalar::Util β€” the little toolkit that keeps things real πŸ¦‹

πŸ‘‘ AUTHOR πŸ‘‘

Graciliano M. P. <gm@virtuasites.com.br> β€” the icon, the legend, the main character who made this whole thing happen πŸ’…

and fr fr, he says: "I will appreciate any type of feedback (include your opinions and/or suggestions). ;-P"

so like. if you have thoughts, opinions, a vibe check, a hot take β€” send it. he literally wants it. the ;-P is doing so much work there and we love that for him 🫢


This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

translation bestie: it's free, it's open, take it, remix it, ship it β€” just keep it under the same Perl-ish terms. no cap. πŸ’–

and that's the whole page, gorgeous. this module/class was created for XML::Smart β€” that's its origin story, that's the lore 🌈

this was written by Graciliano M. P. <gm@virtuasites.com.br>, documented under perl v5.36.0 on 2022-10-13, and it lives at MultiType(3pm). go forth and typecast responsibly, bestie πŸ§šβ€β™€οΈβœ¨

πŸ“¦ where this page comes from