dgBP
dgBP

Reputation: 1691

Why do '::' and '->' work (sort of) interchangeably when calling methods from Perl modules?

I keep getting :: confused with -> when calling subroutines from modules. I know that :: is more related to paths and where the module/subroutine is and -> is used for objects, but I don't really understand why I can seemingly interchange both and it not come up with immediate errors. I have perl modules which are part of a larger package, e.g. FullProgram::Part1

I'm just about getting to grips with modules, but still am on wobbly grounds when it comes to Perl objects, but I've been accidentally doing this:

FullProgram::Part1::subroutine1();

instead of

FullProgram::Part1->subroutine1();

so when I've been passing a hash ref to subroutine1 and been careful about using $class/$self to deal with the object reference and accidentally use :: I end up pulling my hair out wondering why my hash ref seems to disappear. I have learnt my lesson, but would really like an explanation of the difference. I have read the perldocs and various websites on these but I haven't seen any comparisons between the two (quite hard to google...) All help appreciated - always good to understand what I'm doing!

Upvotes: 8

Views: 265

Answers (4)

memowe
memowe

Reputation: 2668

FullProgram::Part1::subroutine1();

calls the subroutine subroutine1 of the package FullProgram::Part1 with an empty parameter list while

FullProgram::Part1->subroutine1();

calls the same subroutine with the package name as the first argument (note that it gets a little bit more complex when you're subclassing). This syntax is used by constructor methods that need the class name for building objects of subclasses like

sub new {
    my ($class, @args) = @_;
    ...
    return bless $thing, $class;
}

FYI: in Perl OO you see $object->method(@args) which calls Class::method with the object (a blessed reference) as the first argument instead of the package/class name. In a method like this, the subroutine could work like this:

sub method {
    my ($self, $foo, $bar) = @_;
    $self->do_something_with($bar);
    # ...
}

which will call the subroutine do_something_with with the object as first argument again followed by the value of $bar which was the second list element you originally passed to method in @args. That way the object itself doesn't get lost.

For more informations about how the inheritance tree becomes important when calling methods, please see ikegami's answer!

Upvotes: 7

ysth
ysth

Reputation: 98388

Use both!

use Module::Two;

Module::Two::->class_method();

Note that this works but also protects you against an ambiguity there; the simple

Module::Two->class_method();

will be interpreted as:

Module::Two()->class_method();

(calling the subroutine Two in Module and trying to call class_method on its return value - likely resulting in a runtime error or calling a class or instance method in some completely different class) if there happens to be a sub Two in Module - something that you shouldn't depend on one way or the other, since it's not any of your code's business what is in Module.

Upvotes: 5

Galimov Albert
Galimov Albert

Reputation: 7357

Historically, Perl dont had any OO. And functions from packages called with FullProgram::Part1::subroutine1(); sytax. Or even before with FullProgram'Part1'subroutine1(); syntax(deprecated).

Later, they implemented OOP with -> sign, but dont changed too much actually. FullProgram::Part1->subroutine1(); calls subroutine1 and FullProgram::Part1 goes as 1st parameter. you can see usage of this when you create an object: my $cgi = CGI->new(). Now, when you call a method from this object, left part also goes as first parameter to function: $cgi->param(''). Thats how param gets object he called from (usually named $self). Thats it. -> is hack for OOP. So as a result Perl does not have classes(packages work as them) but does have objects("objects" hacks too - they are blessed scalars).

Offtop: Also you can call with my $cgi = new CGI; syntax. This is same as CGI->new. Same when you say print STDOUT "text\n";. Yeah, just just calling IOHandle::print().

Upvotes: 0

ikegami
ikegami

Reputation: 385655

There's no inherent difference between a vanilla sub and one's that's a method. It's all in how you call it.


Class::foo('a');

This will call Class::foo. If Class::foo doesn't exist, the inheritance tree will not be checked. Class::foo will be passed only the provided arguments ('a').

It's roughly the same as: my $sub = \&Class::foo; $sub->('a');


Class->foo('a');

This will call Class::foo, or foo in one of its base classes if Class::foo doesn't exist. The invocant (what's on the left of the ->) will be passed as an argument.

It's roughly the same as: my $sub = Class->can('foo'); $sub->('Class', 'a');

Upvotes: 9

Related Questions