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

Hi Monks,

This might be a 101 question, but someone has to ask the silly ones. I have a scipt that operates on a global as such...


use a_module; my $global = a_module->new(); sub func1 { $global->do_something1(); } sub func2 { $global->do_something2(); } $global->do_init; func1(); func2();

The problem with this setup is that it is not re-entrant so if I wanted a $global and $global2 i'd have to duplicate everything which is just not on. So I think ok how about rewriting it as follows...

use a_module; sub func1 { my $var = $_[0]; $var->do_something1(); } sub func2 { my $var = $_[0]; $var->do_something2(); } my $local = a_module->new(); $local->do_init; func1($local); func2($local);

The problem with the above code is that the variables $var in both func1 and func2 don't know that they are supposed to be an instance of type a_module and hence don't have clue what the member functions do_something1 and do_something2 are.

This leads to the obvious question, how do i tell the scalars in the subroutines that they in fact a certain type? Is the only way to do it to pass a reference to the variable such that when you operate on it, it then knows about the member functions. Something like...

use a_module; sub func1 { my $var = $_[0]; $var->do_something1(); } sub func2 { my $var = $_[0]; $var->do_something2(); } my $local = a_module->new(); $local->do_init; func1(\$local); func2(\$local);

Thanks in advance for any thoughts =).
Regards Paul.

Replies are listed 'Best First'.
Re: Typecasting a scalar to a module
by Mugatu (Monk) on Mar 03, 2005 at 18:09 UTC
    The problem with the above code is that the variables $var in both func1 and func2 don't know that they are supposed to be an instance of type a_module

    For one thing, yes, they do. References in Perl know what type of thing they reference to, and if that reference is blessed, they know what class they're blessed into. Furthermore, you don't have to do typecasting in Perl, nor does the compiler have to know what methods an object has at compile time. It is handled at runtime. Your 2nd snippet of code will work as is.

    Update: since there seems to be some confusion about what I meant when I said "2nd snippet," this is the one I was talking about:

    use a_module; sub func1 { my $var = $_[0]; $var->do_something1(); } sub func2 { my $var = $_[0]; $var->do_something2(); } my $local = a_module->new(); $local->do_init; func1($local); func2($local);

    That is, his post contains 3 snippets. The first stores the object in a package global, the 2nd stores the object in a lexical and passes it in, and the 3rd stores the object in a lexical but passes in a reference to it.

      Erm, no it won't work as is because he's passing a scalar reference to his object rather than the object ref itself.

      Update: Yup, confuzzlingness. I was reading "second snippet" as the second alternative, not the second code section as a whole.

        Huh? Where are the "scalar references" that are not "the object ref itself" in this code?

        my $local = a_module->new(); $local->do_init; func1($local); func2($local);

        Update: sorry for the confusion.

      Mugatu,
      I converted my script last night to the second method and it did actually complain about not knowing about the member functions (you'll have to excuse me if I'm mutilating the way you refer to each of these things), which prompted the question.
      After your comments I retried using the method I used in my second snippit as you suggested converted the entire program again and this time it worked. I'm not sure what I did wrong the first time, but it seems happy now and now I can initiate and manipulate multiple instances of everything. =)
      Thanks for clearing up how it all fit together.

      Regards Paul.
Re: Typecasting a scalar to a module
by Rhandom (Curate) on Mar 03, 2005 at 18:16 UTC
    Perl 6 signatures will let you write subroutines that only allow objects that have certain abilities or fulfill certain rolls. Until then you can check for yourself if the object "can" do what you want:

    sub func1 { my $var = $_[0]; if (! ref($var) || ! $var->can('do_something1')) { die "Cannot call do_something1 on passed Var ($var); } # But really this check is redundant # because perl will die with a similar error if you # don't check. The check is only useful if you # want to do something other than die. $var->do_something1(); }


    my @a=qw(random brilliant braindead); print $a[rand(@a)];
Re: Typecasting a scalar to a module
by jhourcle (Prior) on Mar 04, 2005 at 01:40 UTC

    I think the concept that you are looking for is 'Object inheritance'. (the exact term, to tell a scalar what package it belongs to is bless

    my $local1 = my_module->new(); $local1->func1(); $local1->func2(); my $local2 = my_module->new(); $local2->func1(); $local2->func2(); package my_module; use base qw(a_module); sub func1 { shift->do_something1() } sub func2 { shift->do_something2() }

    This will work so long as a_module is set up correctly for inheritance. If it isn't (you can tell because ref($local1) will be 'a_module' and not 'my_module'), it'll behave the same way you've been having problems with, and you'll need to add within your package:

    sub new { my $class = shift; return bless a_module->new(), ref($class) || $class; }
      Inheritance is not always the answer. It makes sense if there is an is-a relationship involved, but often times the relationship is really has-a. A has-a relationship is better served through composition. In the OP's case, he's implementing a kind of poor man's composition, in that his main code is the "object" that has-a copy of the sub object.