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

For the last while, I've been writing some pretty complex Object Oriented modules, where the class gathers up objects of different types, and stuffs them into itself.

Instead of using the object like this:

$obj->{other_obj}->method;

I've taken to writing accessors so I can use them like this:

$obj->other_obj()->method;

However, using the bareword method names works all the same:

$obj->other_obj->method;

My question is, is which way do you prefer? I like the reduction of noise (the parens in this case) as much as possible, but on the other hand, it makes it really, really easy to see what is happening when the parens are in place. To further, I may not be the only one whoever looks at my code, so I'm trying to come up with my own best practices syntax muscle memory for doing things like this.

Here's a full blown example that demonstrates this (while using only chained calls from a single class, not with an object within one of the class methods; the principles are the same):

use warnings; use strict; package Blah; { sub new { return bless {}, $_[0]; }; sub one { $_[0]->{num}++; return $_[0]; }; sub say { print "$_[0]->{num}\n"; }; } package main; { my $obj = Blah->new; $obj->one()->say; # or $obj->one->say; }

Given a complex module with chained method calls that could go four+ wide, is eliminating the parens noise something you'd still get at a glance, or would you leave the empty parens in, for clarification?

Replies are listed 'Best First'.
Re: To parens or not parens in chained method calls
by Athanasius (Archbishop) on Feb 16, 2017 at 06:42 UTC

    Hello stevieb,

    I agree with Your Mother, remove all parens that are unnecessary for the compiler, and I think this brings up an interesting point.

    I first came to Perl from C++, and one of the strengths of Perl is that it lets programmers who are familiar with C and its derivatives come up to speed slowly. We can begin by writing Perl as though it were C, only gradually learning Perl as a separate language. So, my first scripts had C-style (3-argument) for loops, and when I came to learn the Perl foreach construct I of course spelt it foreach to make clear to me that I was using a different syntax. But over time the new syntax became familiar, and now I follow standard practice in (a) preferring foreach-style loops to C-style loops wherever possible, and (b) using the for keyword for either construct.

    In a similar vein, I used to write length($string) but now more usually omit the parentheses: length $string. It took me a while to become comfortable with the more idiomatic Perl syntax, but now I prefer it: simpler is better. As a rule, I use statement modifiers where feasible and prefer the default variable ($_):

    /^$/ or print for @strings;

    is simpler and better than

    for my $s (@strings) { print $s unless $s =~ /^$/; }

    But this raises the interesting point: Is my code now more or less readable? More or less self-documenting? And the answer is: It depends on who is reading it. If an experienced programmer who was familiar with C but new to Perl were my code’s intended audience, he would find the more C-like constructs easier to follow. But for an experienced Perl programmer, the more idiomatic code is easier to read, not only because it is more concise (which is a big plus), but because it is what he expects to see. He isn’t continually asking “Why did he do it the roundabout way?” as he wades through my code. If my code is well-written, its rationale should be obvious.

    So, should one write code for the novice or the experienced Perl programmer? I suppose that depends in part on the sort of workplace one has; but in general it seems common sense to me that one should write code idiomatically, to be comprehended easily by Perlistas rather than by newbies. And the reason is this: by writing Perl idiomatically, we automatically benefit from those features of the language which constitute Perl’s strengths. Further, Perl is a language, so mastering Perl means not only understanding its syntax — to communicate effectively with the compiler/interpreter — but also communicating effectively with one’s fellow Perl programmers. And in communication, simpler is better.

    So, as Your Mother implies, if a construct is unambiguous to the compiler, it’s a good rule of thumb that it will be likewise unambiguous to experienced Perl programmers — and they should be the code’s intended audience. (The one exception to this rule is the use of parentheses to clarify order of precedence in complex logical or mathematical constructs. I prefer to use parentheses here even when they’re not strictly necessary. I’m not sure if that’s a good or a bad thing.)

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: To parens or not parens in chained method calls
by Your Mother (Archbishop) on Feb 16, 2017 at 04:25 UTC

    I personally prefer to remove all parens that are unnecessary for the compiler. Something else I tend to do with chained methods–

    $obj->other_obj ->method; # /* I do it in JS too :P */ $.ajax({blah blah}) .done() .fail();
      I've even met style where the indentation changed when a different object was returned:
      $object->color('red') ->width(3.7) ->child ->color('green') # etc.
      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: To parens or not parens in chained method calls
by hippo (Archbishop) on Feb 16, 2017 at 08:36 UTC

    I agree with my fellow monks and would tend to omit the brackets. However, I was interested to see what perlcritic might say so I tried it on this:

    #!/usr/bin/env perl use strict; use warnings; use Quux; my $foo = Quux->new; $foo->bar->baz; $foo->bar()->baz; exit;

    Even with --brutal it only complained about 2 items:

    Code is not tidy at line 1, column 1. See page 33 of PBP. (Severity: + 1) No package-scoped "$VERSION" variable found at line 1, column 1. See +page 404 of PBP. (Severity: 2)

    We can ignore the $VERSION issue. However, the complaint about tidiness is the oddity because in order to alleviate that we would have to insert whitespace before the brackets so that the line becomes

    $foo->bar ()->baz;

    which to me looks worse, although it's clearly subjective. It doesn't moan at all about the bracketless line. Just something to bear in mind if your code has to pass perlcritic for some policy reason.

Re: To parens or not parens in chained method calls
by BillKSmith (Monsignor) on Feb 16, 2017 at 15:03 UTC
    I agree with you that both styles have advantages. In this case, I disagree with my fellow monks. Perl code should be as clear as possible for the human reader. What is important is consistency. Make your own choice, and then always do it the same way.
    Bill

      Completely agree that consistency might be most important and that every dev is free to choose her own style (unless a house style is enforced, etc).

      I argue that omitting parens, and breaking across lines into semantic chunks, does make the code more clear to a human reader; less content is less cognitive load. Athanasius's examples of the same operation in two styles shows this; where the single line idiom is, to a Perl-centric dev, much easier to read. There is less you have to load into your brain and fewer chances to read something wrong. I'm aware the longer version will likely be easier to follow for a non-Perl hacker. Just as a book written with 3rd grade vocabulary will be easier to the average reader or an ESL student. I gravitate away from the LCD because it ultimately saves time and raises my own game. It's more fun too. When I see an idiom in code that I don't know, I am generally more excited to learn it than I am irritated I don't understand it immediately.

        yet you don't write unit tests ... go figure
Re: To parens or not parens in chained method calls
by GrandFather (Saint) on Feb 16, 2017 at 22:57 UTC

    Interesting question. The compelling criteria for me is consistency. A function/method call is a function/method call regardless of the number of parameters passed. So I include the () even if no parameters are passed in the call.

    However, like Athanasius I use the Perl built in functions like length without parens. If pressed for a justification for the inconsistency I'd suggest functions like length are more like operators.

    Very likely my long C++ experience biases what "looks right" to my eye in this case. My path to my current Perl style almost exactly mimics Athanasius's tale. I would make pretty much the same arguments, except in this small case where I'd apply the "make things that are the same look the same" rule - a call is a call regardless of the number of parameters.

    Premature optimization is the root of all job security

      My main reason for considering not using empty parens (beyond doing it for built-ins), is I never thought about it before. I've always loved Perl, but because there's enough noise, if I could reduce some, I would (it took several years before I came up with a 'standard'). Before Perl, I didn't have much devel experience less some at-home C++ Windows fun I was having when I bought (yep, bought) Borland C++ Builder, and a book to learn from.

      That doesn't count though. Perl is where I learned how to program, now I can understand (in some cases at a basic level) several languages. I'm very proficient in Perl and Python, I believe I'm starting to understand C to the point I can compile relatively reasonable complex code and know when the compiler will barf, and I can finagle and mingle with C# and some C++, and can just get by in JS/JQuery.

      My objective, thanks to what Your Mother said, is now relevant across all languages I frequent, which I didn't think of when I wrote my OP. Now, with the way that things are explained here (in your reply) and other parts of this thread, I may need to step back, consider everything outlined in this thread, and consider the ramifications in all langs, *then* come up with a favoured method.

      Funny how such a simple question could have such far-reaching potential ramifications.

Re: To parens or not parens in chained method calls
by stevieb (Canon) on Feb 16, 2017 at 15:29 UTC

    Thanks for all the great feedback!

    Since I already omit parens everywhere else I can, for example(s):

    print "blah\n"; length ...; push @a, ...; my $obj = Package->new;

    ...I am going to do the same thing with method calls. I forgot about breaking the chain across multiple lines, but I often do that as well (however without omitting parens):

    my @files = File::Find::Rule->file() ->name(...) ->in(...);

    So in the end, I'm going to keep with my previous way of omitting parens, and apply that to chained calls. For long chains, I'll break it into separate lines. For short call chains, eg $obj->db->fetch(...);, I'll keep it on one line unless for some reason more clarity is needed in specific cases, then I'll break that up too.

    update: Your Mother, I don't do much JS at all, but I have done some, and just had a look at a piece of some of my code:

    $(this).children('ul').stop(true, false, true).slideToggle(300);

    Looking at your example, it is much, much clearer as to what's happening when the chain is broken across lines. From now on when I have to write JS, I'll be applying your principle.