in reply to Re: open and list context (?)
in thread open and list context (?)

Always use parens on you function calls...

I've given that advice too, but what makes open a function call and die not?

Replies are listed 'Best First'.
Re^3: open and list context (?)
by tchrist (Pilgrim) on Jun 17, 2011 at 06:50 UTC

    Opinions Considered Harmful

    Cᴀᴠᴇᴀᴛ Lᴇᴄᴛᴏʀ:
    If by chance you’re one to be easily bothered by strong opinions, especially those against which you have an irrational, emotional reaction, please do us all a favor and skip reading this posting. 🙈 🙉 🙊

    On Monday, 13 June 2011 at 10:28 ㏂ ᴍᴅᴛ, chromatic in quoting yours truly has done me the honor to write:

    › Always use parens on you[r] function calls…

    I’ve given that advice too, but what makes open a function call and die not?

    Quite so! Rem acū tetigistī!

    Not merely a just question, it would also seem a perfectly straightfoward question as well. The operative term there is seem, as your seemingly simple question comes accompanied by seriously subobvious traps to trouble both the unwary and the hypervigilant alike.

    Sorry it took me so long to answer … 💬

    🚭  Ceci n’est pas une fonction

    Regarding your question about die, I regret to note that you’ve (knowingly — or otherwise?) picked a pessimal example for use with this particular question. So I’ll first briefly answer the question you asked, and then at greater elaboration I’ll answer the question I shall assume you actually meant. 😜

    The reason that die is neither a function call nor a subroutine, method, procedure, or anything else of that ilk is because of what subroutines at their machine‐level foundation really are. When you factor out matters of register allocation and arugment transmission, they all of then do one key thing: they push on the (per‐thread, per‐intepreter) sᴘ the address of the next ᴘᴄ to be executed after the intended subroutine call eventually returns.

    This would work a bit like -(SP) = PC; PC = FUNCNAME. Then at the end of the “call”, the subprogram pops the return address off the stack and hies itself thither with PC = (SP)+. There exist simpler solutions involving fancier instructions like JSR and RTS, but you must get the central idea here. And die just doesn’t work that way — at all. Functions that return fewer times than they’re called, and in some cases, even return more times than they’re called, are sneaky little buggers that strain any reasonable definition of what a function call really is.

    Other functions that break the function model outlined above and therefore give call‐graph analysis programs serious conniptions include not just exit but even moreso longjmp and setjmp. That’s because setjmp returns more times than it’s called (as so too can open!), while longjump, like exit and die, never bothers to return at all.

    Interesting though all that may be, I suspect that wasn’t what you were really asking. I recognize that I may be wrong, though, and so it is just barely conceivable that you really were asking the subtler question, not the simpler one.

    👾  Begone all yᵉ hobgoblins of little minds!

    Even though code I’ve written ever since v1.0 of Perl for the most part looks pretty much as it always has, my own coding practices have changed a little over the years. I like to think they’ve converged on a degree of stylistic consistency that facilitates not just the reading of my code, but also its predictability.

    Yes, that does mean that today’s code does not always quite match up exactly with yesteryear’s in all possible regards, so please do not go digging up prehistoric Perl code of mine to tout as though it were someone an examplar of cavalier inconsistency. It wouldn’t be. More importantly, it just doesn’t bear discussing.

    🐪  Predictable parsing of argument lists

    Nevertheless, I believe that if you examine any of my recent code, such as the many examples found in my Unicode Tool Chest, you will quickly see a clear and consistent style used not religiously, but consistently in all of that code.

    In fact, I would even go so far as to say that if ever you find exceptions to larger stylistic patterns in that code, you have either discovered a more specific rule than the general rule you had believed you had been previously operating under, or as is more likely, you have discovered a style bug that I myself would prefer to see updated for consistency’s sake.

    🐪   paren() || !paren

    I use parentheses much more consistently and rigorously now than I ever used to. This is closer to Damian’s style and further from Larry’s. I even use them on function calls of no arguments, although I confess to some vascillation with method calls of the corresonding signature.

    I am not fond of using parentheses for functions and methods whose dative (or ablative (or instrumental)) slot is occupied, because the result looks disconcertingly Lispish. That means I avoid parens for things like print, printf, map, grep, and sort — just to name a few. Additionally and for precisely the same reason (although somewhat moderated by pipelined, left‐to‐right listop stacking and on certain perlocentric syntactosemantic exceptions discussed below), I also tend to avoid parentheses on methods‐qua‐listops.

    I recognize this runs somewhat counter to the bashfulᵃʰᵉᵐConventional Wisdom that spooks up an intensely aversive reaction in many novice Perl programmers who just don’t know any better. But since I actually do know where their peculiar ambiguities lurk in stealthful ambuscade, I simply do not write them in an ambiguous fashion, and the payoff is improved readability. It really is a nonissue for me, and I have never once been gotchaed as so many others report having befallen them.

    It is also a tiny niche in one little corner of the language, one which for me does not even arise with any great frequency. Given that, it generates a level of controversy I feel wholly unreasonable and disproportionately larger than it has any business doing. This is itself distressing. Why do that? Let’s not and say we didn’t. Just let it go, ok please?

    ⚠ Where parens really do matter, and why

    One place not to “let go” is when the precence or absence of parentheses meaningfully changes something other than precedence. Just off the top of my head, these are
    1. eof vs eof() — the first is for all of <ARGV>; the second just on the last file read from, so can occur multiple times in an <ARGV> sequence
    2. Whether to include empty parens ( ) on a use statement — if you do include them, no ->import() is invoked, (all but) guaranteeing that your caller’s namespace won’t be polluted with unasked‐for imports. If you don’t include them nor any other import list, then the module is free to plaster your namespace with whatever aliases it pleases, and may even change this list from one revision to the next, thus changing your code’s syntax (protototypes) and semantics (what gets called). Very bad idea.

    👀  My eye→brain processor craves parens

    I know that many others, including even Larry, are different from me. I wrote 100,000 lines of C code before I even started grad school. Larry, on the other hand, seems to have been tortured by a Lisp interpreter as a small child. We each have our own unique cross to bear. We should be a lot more forgiving of people who were victims of (programming) abuse and torture than as a community I feel we for the most part often are.

    For me, the parens are needed to tell my brain where the argument list stops. A semicolon or a close round/square/curly bracket will all do this. But if you expect the argument list to stop for any other reason, I get nervous. I am far too aware of the ways that prototypes change the parse to trust any funny business there. I do not like trailing English words changing the parse, either, since the function likely started as a leading English word. That’s why I’ll write:

    pod2usage(0) if $Opt{help}; pod2usage(-exitstatus => 0, -verbose => 2) if $Opt{man}; @ARGV = (1) unless @ARGV; pod2usage("$0: missing arguments") if @ARGV == 0;
    As in the point that you yourself have raied, there are times I relax that, and indeed it’s usually on things like print or die. As should be immmediately obvious from the code fragment cited above, one thing that’s especially important to me is interlineal vertical alignment. That isn’t quite properly stated, but the idea is that if the code that looks the same should be in the same column despite being on different lines so that the eye can quickly pick out the parts that are different. We’re very good at that as humans.


    🐪  Exemplary Code  🐪

    My basic principle is that only if there are no other operators or function calls to the right, then I may sometimes elide the parens; otherwise they go in, every time. One‐shot command‐line work may be different, because I’m as lazy a typist as the next, but that’s different. Look at my code to see what I mean.

    That’s just one of the many reasons I always use the more readable form of the vexing Logical-ᴏʀ, although there are other reasons for that, too. Please note very very carefully, that even without the alternate, hard‐to‐parse newfangled construct anywhere to be seen or unseen, my own code — mirabile visu! — is simultaneously safe, clear, and unconfusing. “They” tell this can’t be done, but “there” are demonstrably wrong, considering how I never, never, never make the pernicious and pervasive operator precedence errors that seem to plague most Perl programmers, especially those who put too much stock into contemptible mindless cargo‐cult pseudo‐rules instead of in actual thought.

    Do things for reasons other than because you were told to: learn the whys and wherefores, not the rules. But if there is one rule to follow without giving it further thought, please make it this one:



    Please, please, please think of those who’ll come after you — preferably before they do so — and use parentheses to delimit the arguments to your functions calls.




    To get a feel for how my current Perl coding style lays out on the page, including in particular my use of parentheses on function calls, I encourage you to look through my recent work in my evergrowing Unicode Tool Chest. Whatever style that that code evinces, and I am absolutely certain that it somehow does so, it is not something I have ever managed to explain coherently, and least not well enough to get something like perltidy to come close to reproducing.

    Nevertheless, I do believe that taken as a whole, my personal style is consistent, predictable, readable, and pedagogically useful. I should’t be surprised if it were found to be so idiosyncratically mine that it would prove readily identifiable as tchrist–code by one of those clever machine‐learning program trying to identify plagiarism.

    The fiftyish programs in my Unicode Tool Chest are often a lot more useful, or can be used in many clever ways other than are immediately apparent. Some of those that I use daily or more include:

    There are around 50 programs, modules, and libraries in that directory, almost all having to do with Unicode. Some are one‐shots, some are well‐documented standard tools I use daily, and all I believe have something to say about Perl (and sometimes C and sometimes Java) programming. Some delightful little simpletons are genuine lifesavers, but you’d never know it without playing around with them a bit. And some are just downright hilarious in the extreme.

    You’ll see.

    💩  The Good, the Bad, and the Ugly

    One negative thing that the tools in the Unicode Tool Chest is that there exists far, far too much of the absolutely worst possible kind of code reuse imaginable: good ol’ murine snarf’ɴ’barf, so to speak.

    I recognize this and abhor it, and I profoundly apologize. But please understand that these grew organically over a period of a few months, and so it wasn’t at all clear just what should be factored out, what the ᴀᴘɪ needed to be, or how it all fit together as the whole that it has increasingly become. Too much was under constant development to try to do that a priori before having written it. That’s because premature optimization, while perhaps not quite up to the standard of Rᴀᴅɪx Mᴀʟᴏʀᴠᴍ Cᴠᴘɪᴅɪᴛᴀs Esᴛ 😈, is definitely one of my idea of the Seven Deadly Sins of Programming, and so I beg of you if not your forgivenness, at least then your forebearance, in this unintended wickedness. It will get fixed.

    Too much framework and too little code is just pointless over‐engineering and needless conplication. I despise those things, but learning to discern what the right time and place for what level of abstraction is, isn’t something that always comes immediately. Sometimes you have to build working prototypes first, then look ack at them to figure out how to refactor for the good of all.

    In short, there’s a queasy measure of duplication across programs that should and almost must be factored out and placed into a set of common modules. I am painfully aware of that, and very much hope to someday find the time to do so.

    📖 Learning by Example

    Meanwhile, take a look at some of that code. There really is a lot to learn from it — mostly, I hope, good things to learn, not bad things. You may see some things that surprise you, stuff that gives the infernal Perl::Critic the fatal heart‐attack it so desperately deserves.

    And you will also see certain things that are not there. There are elements that someone or other may have told you that you should include in order for your code to pass muster. Sometimes it’s unjustly beating someone over the head with Damian’s Perl Best Practices, and sometimes the supercilious bashing comes from other sources. But it is all bogus and unnecessary, and I believe that in the balance it has now done more harm than good. Tʜᴇʀᴇ’s ᴍᴏʀᴇ ᴛʜᴀɴ ᴏɴᴇ ᴡᴀʏ ᴛᴏ ᴅᴏ ɪᴛ, and don’t you dare forget it.

    ¡ʞʍɐ uᴉ əpoɔ ɹnoλ əʇᴉɹʍəɹ noλ əʞɐɯ puɐ uʍop noλ ʞɔɐɹʇ ⁎llᴉʍ⁎ I əƨlə ɹO

    Looking over my recent code, I guarantee that you will learn a whole lot about my notions of good coding style, including but hardly limited to the proper use and placement of parentheses, much better than I could ever here put into short, simple words. Osmosis works a lot better.

    Sure, I certainly have my rules and ideas, but I am not sure I’m ready to explain them in English. And I especially never want to imply that you must code your Perl as I do mine.

    I just want you to see what I do, understand why due to its consistency it works as a coherent, reliable, safe, and predictable style (perltidy and Perl::Critic be damned!), and only then consider making your own decisions about what you do or do not fancy. I don’t expect everyone to agree with everything. In fact, I would be disappointed if it turned out that way.

    The single overarching point about my code is that it has a distinctive and readily identifiable style running throughout, which has therefore extreme inherent virtue, no matter whether you agree with certain of its particulars or not.

    ☞ What’s the point?

    The point is all about internal self‐consistency. Period.

    The point is not following other people’s rules, howsoever well‐meaning those rules might have originally been. This point is almost always lost these days, and it is a crying shame.

    My Perl code itself should be crystal clear. If it isn’t, then I’m not doing something right. Anything in there that isn’t aeons old (of which there are only two) should also be wholly neoteric, completely self‐consistent, and in places even a pleasure to read.

    ℹ⃝  Ask me, Ask me, Ask me!

    Lastly, I’m happy to entertain questions both public and private about the code.