Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl calling methods with and without parentheses

Some Perl books advise using parentheses when calling class methods, saying this helps to keep the parser from having to guess the intent of the code. However almost all Perl code I have seen (including modules on cpan) very rarely uses the parentheses when calling methods without arguments.

Is it normal to leave off those parentheses or should I always type them.

I wrote a small test code to measure the difference between calling a method with and without parentheses and it really shows a small difference between 1% and 2% for a class with two methods only. I imagine this could raise up if the class is large.

here is the test script I used to benchmark:

#!/usr/bin/perl

use Benchmark qw(:all);

{
    package Messages;

    sub new {
        my ($self) = @_;
        return bless {}, $self;
    }

    sub message {
        my ($self) = @_;
        return "Hello world";
    }

    sub another {
        my ($self) = @_;
        return "Another Hello world";
    }
}

my $class = Messages->new();

cmpthese(10_000_000, {
    'with   ()  ' => sub { $class->message() },
    'without    ()  ' => sub { $class->message },
});

and this is the results of the benchmark:

                 Rate       without ()       with ()    
without ()      3320053/s          --         -1%
with    ()      3338898/s          1%          --

I imagine if the application uses hundreds of modules and each module has hundreds of methods called without parentheses, should this adds up a lot of speed difference?

If so, why everyone is coding without parentheses?.

like image 778
daliaessam Avatar asked Aug 27 '14 09:08

daliaessam


People also ask

What happens when you call a function without parentheses?

When we call a function with parentheses, the function gets execute and returns the result to the callable. In another case, when we call a function without parentheses, a function reference is sent to the callable rather than executing the function itself.

Why do some methods not have parentheses?

Attributes (e.g. imag) are like variables inside the object so you don't use parentheses to access them. Methods (e.g. islower()) are like functions inside the object so they do require parentheses to accept zero or more parameters and perform some work.

What is the difference between calling function with parentheses and without in Javascript?

With parenthesis the method is invoked because of the parenthesis, the result of that invocation will be stored in before_add. Without the parenthesis you store a reference (or "pointer" if you will) to the function in the variable. edit: Added as answer which should be more appropriate. Does this answer your question?

Which method does not require the use of parentheses in Javascript?

A function name without the parentheses is a reference to the function. We don't use the parentheses in that code because we don't want the function to be called at the point where that code is encountered.


3 Answers

The 1% difference is system noise. Both version compile to exactly the same bytecode, so there can't be a systematic difference between them. Use whichever variant makes your code easier to read.

If you want to see what it compiles to, you can do that like this:

perl -MO=Concise -E '$foo->bar()'
like image 188
Calle Dybedahl Avatar answered Sep 23 '22 23:09

Calle Dybedahl


I'm not sure the 1% time difference is all that meaningful, and I doubt you'd be able to measure any difference in a real program.

Some people think it looks neater without () at the end of a method-call. That's enough justification. You'll see it with functions too.

For me, I try to do so when I want to imply "no parameters required here". Mostly just with attribute getters and such.

If a method can take optional parameters and they're just being defaulted then I prefer not to, so I can distinguish between "no parameters required" and "I haven't supplied parameters, but could have".

like image 30
Richard Huxton Avatar answered Sep 23 '22 23:09

Richard Huxton


There's some history here. If you don't want to read it all, know that the () resolve a particular parsing thing that lets Perl know that you're using a subroutine and not a bareword. I tend to always use () for empty argument lists. I'm curious which Perl books you think make that advice though.

What am I?

Perl uses sigils to denote namespaces (and access, but put that aside). Scalar have $, arrays have @, and so on. Before Perl 5, subroutines had & (and along the had a crypto context). There's a difference

&uses_current_stack;  # subroutine uses the current @_
&no_arguments();      # subroutine with no arguments

Perl 5 did away with the explicit & before subroutine calls. That allows for two more possibilities, one of which is now ambiguous:

&uses_current_stack;  # subroutine uses the current @_
&no_arguments();      # subroutine with no arguments
bareword;             # maybe a subroutine?
subroutine();         # subroutine with no arguments

That bareword might be a subroutine, but maybe it isn't. It depends on things that may have happened far away from its use.

This program compiles just fine, but as you see in the decompilation, Perl doesn't quite know what foo is:

$ perl -MO=Deparse -e 'foo'
'???';
-e syntax OK

This is the same problem even if the subroutine definition shows up later:

$ perl -MO=Deparse -e 'foo; sub foo { print 1 }'
'???';
sub foo {
    print(1);
}
-e syntax OK

If you forward declare that foo will be a subroutine name. Now the parser has a hint about what to do even though you never actually define the subroutine. A subroutine doesn't need a definition until you call it, and Perl is a dynamic language so that definition may show up later. You can also forward declare the subroutine but having its definition show up before its use (although most people put the subroutine definitions at the bottom of a program, out of the way):

$ perl -MO=Deparse -e 'use subs qw(foo); foo'
use subs ('foo');
foo();
-e syntax OK

$ perl -MO=Deparse -e 'sub foo { print 1 }  foo'
sub foo {
    print(1);
}
foo();
-e syntax OK

Arity

There's another thing to know about Perl. You can leave off the parentheses on subroutine calls, and Perl will try to figure out if the next tokens are arguments for that.

Consider a print, which takes a list of arguments. So, all of these become arguments to print:

print 1, 2, 3, 4, 5;   # 12345

But some things take a set number of arguments, rand knows it takes one argument. Where there was 4, there's now the result of rand. The 5 still comes from the 5 argument:

print 1, 2, 3, rand 4, 5; # 1232.764206311960175

It's easier for many people to read to use parens to denote the the reader what Perl already knows:

print 1, 2, 3, rand(4), 5; # 1232.764206311960175

Now consider functions that take a range of arguments, such as split. There's the pattern to use, the target string, and a maximum number of items. All of those arguments are optional though.

split;                # split on whitespace on $_, unlimited
split /\h+/;          # split on horizontal whitespace on $_, unlimited
split /\h+/, $var;    # same, with $var
split /\h+/, $var, 2; # split into limited number of items
split /\h+/, $var, 2; # split into limited number of items
split /\h+/, $var, 2, $arg; # oops

So now, looking at this, what do we intend for split? Turns out this is a trick because split complains about too many arguments:

print 1, 2, split /\./, '1.2.3.4', 4, 5;  # error

Parentheses resolve that:

print 1, 2, split( /\./, '1.2.3.4' ), 4, 5;

Or maybe you wanted to work on $_:

print 1, 2, split( /\./ ), '1.2.3.4', 4, 5;

It seems like a silly case, but more complicated examples boil down to the same thing.

On to methods

Perl methods always require parentheses around a non-zero list of arguments:

$invocant->method( 1, 2, 3 );

As an aside, Raku has the method colon to grab everything after it as arguments. I didn't like this at first, but now I miss it in Perl 5:

$invocant->method: 1, 2, 3;  # Raku

Perl does not require parens around zero arguments to a method, so either of these are fine:

$invocant->method();
$invocant->method;

But, the thing after the -> is the method, and arguments go in parentheses. There's no guessing there.

Wrapping up

But, you know that Perl 4 had this & going on and not using parens did the weird default argument thing, so you used () to make the empty argument list. And, you remember that there's the long range effects. So some people use () to denote what they want. Others are more comfortable knowing what Perl's going to do.

From that, some people like to do things the same everywhere. So even though one case might not need it, since they are doing that somewhere else, they do even when it's not needed. Other don't don't care as much.

In something like Learning Perl, we know you're going to see a lot of different things so we show a lot of different things. There's the code you write, but there's also the code you didn't write but have to read.

like image 22
brian d foy Avatar answered Sep 21 '22 23:09

brian d foy