user6734995
user6734995

Reputation:

Access object created in another function

My program creates an object, which, in turn, creates another object

MainScript.pm

use module::FirstModule qw ($hFirstModule);

$hFirstModule->new(parametres);
$hFirstModule->function();

FirstModule.pm

use Exporter   ();
@EXPORT = qw($hFirstModule);
use module::SecondModule qw ($hSecondModule);

sub new {
    my $className = shift;
    my $self = { key => 'val' };
    bless $self, $classname;

    return $self;
}

sub function{
    $hSecondModule->new(parametres);
    #some other code here
}

I want to acces $hSecondModule from MainScript.pm.

Upvotes: 3

Views: 85

Answers (2)

simbabque
simbabque

Reputation: 54323

Here is a very hacky approach that takes your updated code into consideration. It uses Sub::Override to grab the return value of the constructor call to your SecondModule thingy. This is something that you'd usually maybe do in a unit test, but not in production code. However, it should work. Here's an example.

Foo.pm

package Foo;
use Bar;

sub new {
    return bless {}, $_[0];
}

sub frobnicate {
    Bar->new;
    return;
}

Bar.pm

package Bar;

sub new {
    return bless {}, $_[0];
}

sub drink {
    return 42;    # because.
}

script.pl

package main;
use Foo; # this will load Bar at compile time
use Sub::Override;

my $foo = Foo->new;

my $bar;          # this is lexical to the main script, so we can use it inside
my $orig = \&Bar::new;           # grab the original function
my $sub  = Sub::Override->new(
    "Bar::new" => sub {
        my $self = shift;

        # call the constructor of $hSecondModule, grab the RV and assign
        # it to our var from the main script
        $bar = $self->$orig(@_);
        return $bar;
    }
);

$foo->frobnicate;

# restore the original sub
$sub->restore;

# $bar is now assigend
print $bar->drink;

Again, I would not do this in production code.

Let's take a look at the main function. It first creates a new Foo object. Then it grabs a reference to the Bar::new function. We need that as the original, so we can call it to create the object. Then we use Sub::Override to temporarily replace the Bar::new with our sub that calls the original, but takes the return value (which is the object) and assigns it to our variable that's lexical to the main script. Then we return it.

This function will now be called when $foo->frobnicate calls Bar->new. After that call, $bar is populated in our main script. Then we restore Bar::new so we don't accidentally overwrite our $bar in case that gets called again from somewhere else.

Afterwards, we can use $bar.

Note that this is advanced. I'll say again that I would not use this kind of hack in production code. There is probably a better way to do what you want. There might be an x/y problem here and you need to better explain why you need to do this so we can find a less crazy solution.

Upvotes: 3

simbabque
simbabque

Reputation: 54323

It depends.

We would have to see the actual code. What you've shown is a bit ambiguous. However, there are two scenarios.

  1. You can't

    If your code is not exactly like what you have shown as pseudo-code, then there is no chance to do that. Consider this code in &module1::function.

    sub function {
        my $obj = Module2->new;
        # ... more stuff
        return;
    }
    

    In this case, you are not returning anything, and the $obj is lexically scoped. A lexical scope means that it only exists inside of the closest {} block (and all blocks inside that). That's the block of the function sub. Once the program returns out of that sub, the variable goes out of scope and the object is destroyed. There is no way to get to it afterwards. It's gone.

    Even if it was not destroyed, you cannot reach into a different scope.

  2. You can

    If you however return the object from the function, then you'd have to assign it in your script, and then you can access it later. If the code is exactly what you've shown above, this works.

    sub function {
        my $obj = Module2->new;
        # nothing here
    }
    

    In Perl, subs always return the last true statement. If you don't have a return and the last statement is the Module2->new call, then the result of that statement, which is the object, is returned. Of course it also works if you actually return explicitly.

    sub function {
        return Module2->new;
    }
    

    So if you assign that to a variable in your script, you can access it in the script.

    my $obj = module1->function();
    

    This is similar to the factory pattern.

This is vague, but without more information it's impossible to answer the question more precicely.

Upvotes: 4

Related Questions