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

Greetings o great monkos,

I have an OO question. Is there anyway I can access a subroutine inside a program from a class? For example.

Say I have:

use Blah; use Foobar; $b = Blah->new(); $f = Foobar->new(); $x->doSomething;
and inside the Blah module:
sub new { ... } sub doSomething { I want to access $f->some foobar method here }

So the question is: is there a way I can access a method $f from package Blah? I would guess you can rephrase that as... can I access something in the main program from the package???

Replies are listed 'Best First'.
Re: accessing subs/methods from the module
by BrowserUk (Patriarch) on Feb 06, 2003 at 18:10 UTC

    I'd say that you were looking at the problem from the wrong end. In order that any code within your Blah module is run, you have to call it from the main program (unless it has a BEGIN{} INIT{} END{} etc. blocks, but thats a special case.).

    So the way to tackle your problem is to pass the vars that you need to access in main into the code in Blah when you call it. Eg.

    use Blah; sub new{...} sub doSomething{ my $foobar = shift; $foobar->someMethod(); ... } ...

    main

    use Blah; use FooBar; my $f = FooBar->new(); my $b = Blah->new(); $b->doSomthing( $f );

    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

Re: accessing subs/methods from the module
by steves (Curate) on Feb 06, 2003 at 18:10 UTC

    You can access anything you want by fully qualifying it with a package name; e.g. in Blah:

    use Foobar; sub doSomething { Foobar::some_method(); }
    The danger here is that Foobar is acting like an instance method and wants an object reference as its first argument. You don't have one just calling it as shown above. To do that you need to create a Foobar object first, in which case access is as you'd expect:
    my $f = Foobar->new(); $f->some_method();

    Make sure you understand the difference between class and instance methods before digging in too far here. Perl also lets you write methods that do either if you want, as much as that pisses off some OO purists:

    sub class_or_instance { my $invocant = shift; if (ref($invocant)) { # got an instance (i.e., a "self" reference) } else { # got a class name (hopefully anyway ... 8-) } } ... Foobar->class_or_instance() # passes class name "Foobar" in as @_[0] my $f = Foobar->new(); $f->class_or_instance(); # passes object $f in as @_[0]
    I say "hopefully" in the comment because you could trip yourself up by doing this:
    Foobar::class_or_instance('blech');
    Tighter error checking is left as an exercise for the reader. 8-)
Re: accessing subs/methods from the module
by pfaut (Priest) on Feb 06, 2003 at 18:10 UTC

    $f is not a method. It' an object. If you want to access it from Blah's new() method, pass it as an argument. But in your example, $f hasn't even been created yet when you invoke Blah->new() so what do you expect to do with it?

    It is sometimes possible to access something in another package but it is usually bad form.

    --- print map { my ($m)=1<<hex($_)&11?' ':''; $m.=substr('AHJPacehklnorstu',hex($_),1) } split //,'2fde0abe76c36c914586c';
Re: accessing subs/methods from the module
by bronto (Priest) on Feb 06, 2003 at 18:14 UTC

    I am not sure I understood your question, if you simply need to call another class' method, or another package subroutine, or it makes sense to create a Foobar instance just to call another class' method...

    Anyway, if you just want to know if it is possible to call another class' method without instanciating it, or another package's subroutine, the reply is:

    # Access a Foobar's method Foobar->method(@parameters) ; # Access a Foobar subroutine Foobar::subroutine(@parameters) ;

    Be warned that in Perl subroutines and methods are the same thing, but calling Foobar->method(@parameters) is not the same as calling &Foobar::subroutine(@parameters).

    Ciao!
    --bronto

    Update: (after shrubbery's explaination): ok, I understand now:

    steves & C. already replied: it is possible, but you should use package or global variables, which should be avoided if possible.


    The very nature of Perl to be like natural language--inconsistant and full of dwim and special cases--makes it impossible to know it all without simply memorizing the documentation (which is not complete or totally correct anyway).
    --John M. Dlugosz
      Right sorry if my thing is a bit convoluted. Let me try again. I have two objects using 2 different classes. One is say called $f thats an instance of class "Foobar." The other is $b of class "Blah." They're both modules.

      My question would be, can I inside the module for "Blah" access a variable in the main program? That variable also happens to be $f, an instance of "Foobar."

      Let me fix my example too.

      main code:

      use Blah; use Foobar; $b = Blah->new(); $f = Foobar->new(); $b->doSomething;

      and inside the Blah module:

      sub new { ... } sub doSomething { $f->methodX(); }

      And inside the Foobar module:

      sub new { ... } sub methodX { does some fun things here }

      So basically, method "doSomething" is invoked. I want to be able for "doSomething" to access variable in the main program $f. $f just happens to be an instance of "Foobar."

      Thanks!

        I think it's very simple:

        if you change in the main program,

        $b->doSomething;
        to
        $b->doSomething($f);
        and
        package Blah; sub doSomething { my $self = shift; my $f = shift; $f->methodX; } ...
        That should work for you.

        artist

        It's bad style, but yes:

        package Blah; sub doSomething { $main::f->whatever(); }
        As long as $f is a package variable in main -- i.e., not declared with my, my preference being:
        our $f = Foobar->new();
        ... and as long as I don't have to maintain your code. You have factoring issues here that should be keeping you awake at night.

        $b->doSomething($f); package Blah; sub doSomething { my $self = shift; my ($f) = @_; $f->methodX(); }
        The real question is how do I use a variable in one scope within another scope. The answer is you pass it. This isn't an OO question, it's a scoping question. It's also a pretty basic question.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.