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

Hello Monks

I am looking over some code from a project I inherited. I am a little confused with a certain code block. Its OO and in a certain function the following simple line is written

$self->do_it("99")

Now, in my limited perl experience I thought that this line would call a class method called "do_it", passing it $self as the first argument and "99" as the second. However, there is no mention of said method anywhere in the code (or on the system as a recursive grep shows)

With this in mind; am I missing something obvious? Is this line doing something different than what I am expecting?

Replies are listed 'Best First'.
Re: $self->do_it("now") question
by choroba (Cardinal) on Jul 21, 2015 at 13:50 UTC
    You are right, it is a method call. The method might be defined somewhere else, though:
    • Your class could have inherited it from one of its parents ancestors (and in Perl, we have multiple inheritance);
    • If the class (or its ancestor) uses a modern framework like Moose, the method could have been generated (as a clearer, reader, writer or whatever);
    • If the method is not found, it could still be autoloaded (see Autoloading).
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: $self->do_it("now") question
by stevieb (Canon) on Jul 21, 2015 at 13:54 UTC

    Use the debugger... put a breakpoint on the line before the call $DB::single = 1;:

    $DB::single = 1; $des->all();

    Then run it from the command line with the -d param: perl -d script.pl. You'll be dropped into the debugger. Simply type c to 'continue' all the way to your breakpoint, then s to 'step' into the next line of code which should give you some insight:

    main::(test.pl:6): my $des = Devel::Examine::Subs->new({file => 'sh +ift.pl'}); DB<1> c main::(test.pl:9): $des->all(); DB<1> s Devel::Examine::Subs::all(/usr/lib/perl5/site_perl/5.22.0/Devel/Examin +e/Subs.pm:382): 382: my $self = shift;

    -stevieb

Re: $self->do_it("now") question
by Laurent_R (Canon) on Jul 21, 2015 at 14:05 UTC
    Check the OO modules that are being loaded with the use ...; statement.

    One of them should have a do_it method or should inherit it from a parent or ancestor class.

      Yeah, I did! It really doesn't exist. I've even searched the whole system for that text and got no hits apart from the pm file it's called from - very strange

      grep "do_it" ./ -ir
        very strange

        Not really; it's fairly normal in a dynamic language like Perl. Like choroba already said, sub names can be autoloaded or dynamically created. Note how in the following two examples, there is no obvious (greppable) place that do_it is defined.

        sub AUTOLOAD { print "Hello!\n" } do_it(); __END__ Hello!
        my $x = "do_"; my $y = "it"; { no strict 'refs'; *{"$x$y"} = sub { print "Hello!\n" }; } do_it(); __END__ Hello!

        It very well could be that a module is doing some strange symbol table hackery with the call and transforming it into something that doesn't even remotely resemble the name 'do_it'. Your best bet is the debugger...

        Besides the possibility, mentioned by other monks, of dynamically created method names and other symbol table hacking or some other form of black magic, I do not think that your grep is sufficient even for straight forward OO modules, because it looks only into the current directory and its sub-directory tree. Perl modules can be installed in other places. You should also look into the directories listed in the @INC array and their subdirectories.
Re: $self->do_it("now") question
by clueless newbie (Curate) on Jul 21, 2015 at 18:54 UTC
    You can use can to get the coderef of the method then Data::Dumper (and $Data::Dumper::Deparse) to dump the coderef. This should give you enough to determine where and how the method get defined.
    #!/usr/bin/env perl use Data::Dumper; use strict; use warnings; my $yada=Yada->new(); my $ref=$yada->can('yada'); $Data::Dumper::Deparse=1; warn Data::Dumper->Dump([\$ref],[qw(*ref)]),' '; package Yada; use strict; use warnings; sub new { my ($class,@args)=@_; return bless {},$class; }; sub yada { my $self=shift; warn Data::Dumper->Dump([\$self],[qw(*self)]),' '; };
    which when run returns
    c:\Users\Clueless>perl can.pl $ref = \sub { package Yada; use warnings; use strict; my $self = shift(); warn 'Data::Dumper'->Dump([\$self], ['*self']), ' '; }; at can.pl line 10.
A reply falls below the community's threshold of quality. You may see it by logging in.