Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

All in one

by duff (Parson)
on Jan 12, 2004 at 19:33 UTC ( [id://320735]=perlmeditation: print w/replies, xml ) Need Help??

Why are people always trying to accomplish things "all in one statement" or "all in one regular expression"? Usually when I see these questions it gives me the impression that the asker can think of a way to do it, but it would take two statements/expressions (and that would just be too many!). And often times it's on IRC where by the time they've asked the question and gotten an answer (which probably consists of "why don't you just use two statements?"), they could have already coded something that would have worked but not taken only one statement/expression.

Is this an instance of premature optimization? Do they believe in the false economy that "less text" equates to "more efficient code"? Or perhaps as delirium's meditation seems to imply, they think that "less text" equates to "more elegant code"? Granted, there are some instances where it would make the code read better if there were a way to get some complex functionality into one expression, but you know what? We already have a way to do that; they're called subroutines. I think people need to realize that clarity trumps cleverness always (okay, except when your goal is cleverness like with golf or obfuscations)

Or is that it right there? Perl has a reputation of being clever, so users always want to do something clever in their code.

Where do you guys think this pervasive meme comes from? And are current methods of education stemming the tide of ignorance?

Replies are listed 'Best First'.
Re: All in one
by Roy Johnson (Monsignor) on Jan 12, 2004 at 19:48 UTC
    I think that those who are asking such questions have had a lot of experiences where they've seen things that they'd code in a clunky way in some other language done in one simple step in Perl. They're hoping to expand their knowledge of the tools available in Perl (and who among us isn't?), thinking that there's got to be a less clunky way than what they're trying. Using multiple statements to do something that is, in one's mind, atomic, is clunky.

    There is a tendency among less experienced coders -- those who haven't had to go back and rework their programs months later -- to value "coolness" over clarity. That's a viewpoint that is usually self-correcting in time.

    Good points about clarity and subroutines.


    The PerlMonk tr/// Advocate
Re: All in one
by hardburn (Abbot) on Jan 12, 2004 at 20:03 UTC

    In many cases, the second statement will require the programmer to assign a value to a temp variable. This can be avoided by merging two statements into a single one. This may or may not save memory or speed, depending on a number of details (like if they're returning an array vs. an arrayref). It may look particularly good for large list processing, such as with the Schwarzian Transform.

    I am not completely convinced if this is a bad thing to strive for or not. If anything, the programmer may learn something about the expressiveness of the languge in question, which carries its own reward.

    As an example, I've started using this idiom for filling HTML::Template loops based on Class::DBI objects:

    # $tmpl and @search_results defined elsewhere $tmpl->param( loop => [ map {{ col1 => $_->col1, col2 => $_->col2, col3 => $_->col3, }} @search_results ]);

    Very expressive, and I think the double-curly looks sexy :)

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

Re: All in one
by BrowserUk (Patriarch) on Jan 12, 2004 at 22:40 UTC

    Personally, I think that there are several benefits of concise code -- as contrasted with either obfuscated code or "long-hand" code.

    They are same benefits that a VHLL has over a HLL. Doing the same thing, with fewer lines -- within sensible constraints of clarity -- mean that:

    • there are less lines to have (or aquire) bugs.

      Provided combined line represents a single logical step of the algorithm, then making it 'indivisible' can be highly beneficial. It means that extra lines cannot be easily inserted at inappropriate places between two parts of that logical step by accident. This avoids one of the classic sources of errors induced during maintenance.

      Of course, it can mean that it becomes necessary to later break the line up when requirements change. But this isn't necesarially a bad thng as the very fact that it muct be broken up, forces the programmer to attempt to understand why it was combined in the first place.

    • it is easier to get an overview of the structure of each logical piece of code, if each subroutine, method or logically self-contained block within the algorithm, is viewable within your editor on a single screen.

      Personally, this is of great importance to me as a programmer. I am always uncomfortable with monolithic lumps of code that wander off the bottom of my screen leaving me in a position of having to scroll up and down to view the complete algorithm.

      It's one reason that almost the first thing I do when I encounter code that has large volumes of embedded comments is to remove them. If the comments are (IMO) accurate and valuable to understanding the code, I may chose to move them into a single block preceding the block(s) of code to which they relate. But generally, I find that I don't trust them enough to rely upon them, prefering to derive my understanding from the code itself rather than the comments, which are often out of date, inaccurate or couched in terms that made sense to the programmer who wrote them, when he already had a good understanding of the code, but not to me coming along afterwards trying to aquire that understanding.

      There are occasional exceptions:)

    • Often the process of combination also has the side-effect of reducing the opcode count, and the need for temporary variables, which can lead to improvements in either or both; performnce and reduced memory allocation. If this is achieved without recourse to obfuscation, or a reduction in clarity, then it certainly doesn't harm.

      I get kind of crinkly when I see the phrase "premature optimisation". Especially if code is destined to be re-used, writing it to be as memory and cycles efficient as is commensurate with clarity is (IMO) worthy of making the effort.

      The authors of modules have no way of knowing the runtime demands of the applications that will use their code, so their optimisation efforts are either 'always premature' or 'always beneficial'.

      The idea that modules should be written without regard to the runtime costs and optimisation left to the modules users as and when their applications run up againsts limits, severly restricts and negates the purpose of modularisation.

      We all benefit from the efforts that perls maintainers put into optimisations, though we may occasionally be bitten by them when thing are taken a step to far. I for one wouldn't want to loose the benefits of their many successful optimisations in order to avoid the occasional bug that results from them.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Timing (and a little luck) are everything!

Re: All in one
by ysth (Canon) on Jan 12, 2004 at 19:46 UTC
    Where do you guys think this pervasive meme comes from?
    Perhaps from the expressiveness of the language. I think it attracts programmers who enjoy the process of translating what's in their head to what's on the screen. Then they find the process so enjoyable, they can't help playing with it.
    And are current methods of education stemming the tide of ignorance?
    No.
Re: All in one
by l2kashe (Deacon) on Jan 12, 2004 at 21:01 UTC

    Others have already commented on Perl's allowance for expressiveness, and I think that is a direct factor. Also there is the statement of 'less code equals less bug opportunities'.

    Personally I have found myself doing the same thing, and at some point I step away and simply leave a #TODO: blah on the lines preceeding and move on. Other times I have fought the battle and won or lost. Every time I have found myself in this situation though, I end up in the docs. Just about everytime I'm in the docs poking around I tend to remember something I wanted to look up, or happen to read an entry I haven't seen before. I seem to always learn/refresh something during these times, which is always a good thing.

    Is the behaviour right or wrong? Depends on the situation. There is a reason the terms 'magic' and 'deep magic' exist. Someone spent the time, somewhere, to figure out exactly how to get the best performance out of a given piece of code. What happens if someone spends the time now, wrestling with a few different problems along this line? Next time they encounter the same situation, they can pull from past experience and apply the knowledge now. Read be more efficient. Whether that be with less code, or less time spent due to already having an answer. Now look at the flip side. Eh.. it's good enough as is. Probably can't/shouldn't do anything else with it. Then something isn't fast/efficient enough and the crunch is on. Bad time to start attempting to streamline code.

    Hacking code is, or should be in my opinion, fun. It's gratifying to be able to take something x lines long and reduce by y, while possibly adding functionality and/or abstraction at the same time. Someone's sig around here is something to the effect of 'I know I'm on the right path, when by deleting I'm adding functionality'.

    </ramble>
    Personally I think the behaviour should be encouraged. I don't think that answers should necessarily always be given to questions of this type, but rather general pointers about technique, and references to relevant docs/modules.

    use perl;
    Everyone should spend some time pounding nails with their forehead for a while before they graduate to complicated stuff like hammers. - Dominus

      Every time I have found myself in this situation though, I end up in the docs. Just about everytime I'm in the docs poking around I tend to remember something I wanted to look up, or happen to read an entry I haven't seen before. I seem to always learn/refresh something during these times, which is always a good thing.
      I think professional programmers should expect to spend %x percent of their time on improving their knowlege of their tools and %y percent of their time improving the tools themselves. Even under deadline. Insert x and y as appropriate for your situation; I like 10.
Re: All in one
by Art_XIV (Hermit) on Jan 12, 2004 at 19:56 UTC

    I don't think that the more experienced monks always try for the shortest/cleverest code that they can manage, but that they do often try for the most idiomatic code that they can, which will tend to produce short/clever code as a side-effect.

    Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"
Re: All in one
by Abigail-II (Bishop) on Jan 13, 2004 at 10:29 UTC
    Is this an instance of premature optimization? Do they believe in the false economy that "less text" equates to "more efficient code"? Or perhaps as delirium's meditation seems to imply, they think that "less text" equates to "more elegant code"? Granted, there are some instances where it would make the code read better if there were a way to get some complex functionality into one expression, but you know what? We already have a way to do that; they're called subroutines. I think people need to realize that clarity trumps cleverness always (okay, except when your goal is cleverness like with golf or obfuscations)

    Part of writing good programs involves making trade-offs, and to balance resources. There are many resources to deal with, and "screen estate" is one of them. A window can only display a limited amount of lines at a time - and a persons view usually even less. Tersity means a person going through the code needs to scroll less/move less with their eyes. (This is also one of the reasons I don't like to mix code with POD, and that I am not liberal with comments). Subroutines don't always make it easier to grok code. A program that can be read top to bottom is sometimes easier to figure out than a program where you have to jump all over the file to follow a programs logic (OO makes it even worse).

    Abigail

      Part of writing good programs involves making trade-offs, and to balance resources. There are many resources to deal with, and "screen estate" is one of them

      Aye, and "conceptual density" is another factor that often balances against screen realestate. I guess that, IMHO, most people try to accomplish things in one statement gratuitously (at the expense of clarity).

Re: All in one
by insensate (Hermit) on Jan 12, 2004 at 21:27 UTC
    The educational value of condensing code shouldn't be overlooked. My understanding of $_, references, range and conditional operators, and loop control has benefited from trying to make my code more concise. I certainly won't leave idiomatic or obfuscated techniques in anything I code for work. Golfing can be a learning exercise apart from solving a problem programmatically. If there's more than one way to do it... why not see if you can try them all?
Re: All in one
by delirium (Chaplain) on Jan 12, 2004 at 21:38 UTC
    For me it's always been the Rubik's Cube factor. Try to outwit yourself. Try to solve it faster, in fewer turns. Spend an hour to try to remove a couple lines from a script. What have you accomplished when you're done? The toy is still a cube with colored stickers, and you don't make any more money. Your code might actually run slower, and is probably harder to read.

    The achievement is solving the problem you picked. I want to see if I can be even more obtusely clever. On the other hand, your mind is being excercised just as though you were solving a practical problem. As a diversion, it certainly has more value than other monitor-based activities (TV watching, video games).

    But as a previous poster said, you remember some of the tricks you pick up on the way, and they might turn out to be truly useful some day.

    And are current methods of education stemming the tide of ignorance?

    People usually make it through life with their ignorance intact, education or no.

Re: All in one
by Abigail-II (Bishop) on Jan 13, 2004 at 10:18 UTC
    Why are people always trying to accomplish things "all in one statement" or "all in one regular expression"?
    For trying to do it all in one regular expression, there could be valid reasons. Regular expression can be found in configuration files, web forms (search pages), or as arguments to programs (grep) or functions (split), where you don't always have the luxury of adding code.

    Abigail

Re: All in one
by flyingmoose (Priest) on Jan 13, 2004 at 14:04 UTC

    I'm going to agree with duff here, something like the map with double curly braces or a scary combination of a regex and multiple if's &&'s ||'s or's and various other operators has a downside. Maybe it's fast, maybe it was fun for the programmer to invent and maybe it makes him/her happy, but it's a maintainance problem. Every time a user runs into this new idiom, they have to try to grok it, and that takes time.

    Furthermore, simple statements rather than complex ones can be extended more easily to do other things -- which is usually what needs to be done from a maintainance perspective. Another problem is that the idioms that rely on niche corners of the language make porting between different versions of the language, or (more so) different languages

    This goes back to the earlier meditation on "elegance", where some one posted that one-liners are more elegant, and that clear and elegant were two different things.

    IMHO - first a program should be accurate and up to performance specs - then it should be easily extensible - then it should be readable - then it should be short - then it should be clever (in that order, and hopefully the top three goals are always met)

    There is zero room for obscurity in my book. I find it to be rather unprofessional, and detrimental to the inclusion of Perl in non-Perl-elite circles. There is a lot of bias against Perl, and while these statements are cool, when used in excess, they are to the detriment of the language in foreign camps. Just read any of the anti-Perl bias for the Python and Ruby folks. These languages are a lot alike, and really, they percieve Perl as an evil. Think about that, next time one decides to ponder one-liners and whether clarity and brevity are one in the same. I'll say they are not.

    I'll also agree with Abigail here that OO-jumping (especially Java-esque OO) over 15 subroutines and 15 files is a horrible way to do things. I'm not trying to steer people here. Simple maintainability is about transparency. Whatever is a barrier to groking the code should be removed. Sometimes this involves consolidation, sometimes expansion.

    Perl elegance? It's a Zen thing. Consider the pebble.

      I'll also agree with Abigail here that OO-jumping (especially Java-esque OO) over 15 subroutines and 15 files is a horrible way to do things.

      This is one reason why a good design layout is important, probably with UML. You can view the complete design at once and immediately see how each class relates to the others, all in one diagram. No need to jump between a bunch of files.

      I remember first looking at the Freenet Project (external link), which has a reference implementation that is an excelent OO design. However, there isn't any sort of design document for how all these objects interact (at least, there wasn't back then--this might have changed). Figuring out this beast meant wading through a huge directory structure of Java classes, which may have little or no documentation on their own. I can get through a Perl obfu easier than I could work my way through that.

      ----
      I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
      -- Schemer

      : () { :|:& };:

      Note: All code is untested, unless otherwise stated

        This is one reason why a good design layout is important, probably with UML. You can view the complete design at once and immediately see how each class relates to the others, all in one diagram. No need to jump between a bunch of files.
        I wasn't talking about the situation where you proudly show your design in a conference room using a spiffy powerpoint presentation. I was more thinking of a situation where it's 11:45 PM, the bug needs to be fixed at 9 AM or the customer (who's 6 timezones ahead of you) will have to be paid damages and you are trying to figure out what piece of code is mangling your data incorrectly.

        I've yet to see a UML diagram that indicates where the bugs are.

        Abigail

        This is one reason why a good design layout is important, probably with UML. You can view the complete design at once and immediately see how each class relates to the others, all in one diagram. No need to jump between a bunch of files.

        You are partially right. UML does provide a nifty design file, but it does not proclude the creation of architectures that have dependencies on thousands of objects, evil beasts that require jumping through 15 methods to achieve reality.

        Note about UML -- Many times, though, UML is generated after-the-fact (from code using Rational's software) and in absense of actual design, planning, and API/design documentation. And this is encouraged in the industry. So when design is no longer a seperate step, it ceases to be design. Personally, I do design on whiteboards and with pencils, translate later, and if you start with UML you have already started too low-level. I like to work down from modular components that each have seperate purposes. The insides of those modules can be designed once their behavior and interfaces are defined, but mainly I care first about how the system acts, and what it is. Is it primarly an event loop, etc? I don't care if there is a SuperConductingEventLoopManagerDelegate, for instance. That's way too low level for the design phase.

        All of these processes (well, maybe not UML) are important everywhere, regardless of programming language, when projects rise about simple-helper-script level. I see a lot of UML thrown together at random, essentially boxes and arrows, and folks tend to call that a design. Well, no, a design is only such when you have a *good* configuration of boxes and arrows.

        As a final point, it's wise to note that Sun itself is guilty of the file-jumping I speak of. See how many pages of the J2SDK documentations you have to read to fully understand a particular method call. The calls and dependancies fly absolutely all over the place.

        If anything, if neglect of Perl side leads to obfuscation through compaction, Java leads to obfuscation through expansion and objects will multiply like rabbits. Is there a moral here? Nope. Just watch out for dragons.

        When was in college, I wanted to be a Software Architect. Java, in fact, was something I liked. Then, somehow, it scared me...I still love software design, and I'd do it all day if I could...but I am aware of the dragons of every approach, and even what the industry embraces hardest (Java, UML, XML/SOAP, etc) are only suitable if they can be employed well by those who know they have limitations. Zealots of any particular one-sided approach are the most dangerous foe to good programming. XML everywhere, SOAP everywhere, OO everywhere. Got to pick the best of both worlds...and design should not presume to pick certain tools above others until they can be weighed fairly.

        Again, Programming is looked upon as an Engineering Process. That's good, but the rules aren't nearly hard and fast as the physics of bridge design. There is a lot of art there, and a lot of gray areas. Hard and fast rules are often the enemy of innovation, but so are lack of any sort of rules. Yeah, it's a Zen thing.

        Ok, I guess I forgot what I was talking about :)

Re: All in one
by jonadab (Parson) on Jan 13, 2004 at 01:32 UTC
    Why are people always trying to accomplish things "all in one statement"

    I find myself doing this with some frequency, though usually I don't go so far as to ask someone else for help doing it. I think one of the main reasons I like to reduce multiple statements into one is, well, because I can. It's a diversion, something to do while you figure out how that next function (or whatever) is going to work. It's a little like playing Perl golf, but it's less work.

    Sometimes readability is enhanced by reducing the number of statements, especially in cases where it lets you cut out some temporary variables. Other times, you can go too far and actively harm readability, at which point sensible people should back off and leave it as two or more statements, unless what you're coding is an obfu or japh.


    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
Re: All in one
by tilly (Archbishop) on Jan 13, 2004 at 19:07 UTC
    My thought is that it results from a misunderstanding of what sets experts apart. See The path to mastery for my thoughts in more detail.
Re: All in one
by rkg (Hermit) on Jan 15, 2004 at 03:25 UTC
    I think some of the reason coders sometimes seek get things done in a single line is the resemblance of perl to natural language. Larry's roots as a linguist are reflected in the language he built.

    Constructs like

    open(F, ">foo.txt") or die "hey, couldn't open foo.txt";
    resemble how we talk, rather than the more formal
    if (!open(F, ">foo.txt")) { die "hey, couldn't open foo.txt"; }
    Somehow, opening and closing a block seems... burdensome.

    Burdensome not due to typing an extra character or two, but burdensome because the block and whitespace seem to make too big of a deal about something small, which at a subconscious level causes mild dissonance and slows down the brain.

    My two cents.

    LATER UPDATE

    I find myself trying to write code like this

    # does not work die "missing arg $_" unless $args{$_} for (qw(foo bar baz boop));
    which feels more natural than opening a block (my dissonance theory)
    # untested for (qw(foo bar baz boop)) { die "missing arg $_" unless $args{$_}; }
    Similar is the use of $_ to mean "this" or "that" in natural language.

    All of these shortcut constructs are quicker and more like natural language -- and more difficult for someone entering the conversation late.

Re: All in one
by pboin (Deacon) on Jan 13, 2004 at 17:15 UTC
    What we're really talking about here is 'wisdom' -- an attribute that is entirely different than 'intelligence'.

    I admire routines (by others, and by myself) that are elegant taken as a whole. Many comments on this particular thread seem to be about the micro-logic of combining one or more statements into an impressive one-stroker.

    I suggest that the real wisdom, the real 'efficiency of code' comes from a macro level. Looking at a routine and realizing that we don't need to re-write sort again, that we don't need to re-write another find, etc.

    Great thoughts to be ponder, thanks.

Re: All in one
by hessef (Monk) on Jan 13, 2004 at 16:42 UTC
    I agree with the "cool factor" (guilty, too).

    Also, I have a personal dislike for 3-or-more nested if statements. Sometimes having one regular expression lets me eliminate an if statement without having to put used-one-time-only code in a function.
Re: All in one
by sfink (Deacon) on Jan 22, 2004 at 18:21 UTC
    Another good reason to code something all in one line is to learn why not to.

    I often have the situation where a chunk of code "feels wrong" -- something seems a little clunky about it. I will attack those chunks by condensing them to the minimum possible amount of code. Often this will reveal a slightly more streamlined way of thinking about what the code is doing, and I will be able to recode it differently to more directly express that simpler mental understanding. (The new version may or may not be the maximally trimmed-down version; it may just be informed by it.)

    And at least as often, I will be immediately revolted by the hypercondensed version, and it will make me realize why things need to be expanded out. Once again, I will probably rewrite the code, but this time targeting the extra verbosity at the portion where it is really needed. The result won't be much shorter or longer than the original, but it will "feel" better.

    A typical example is when you have written a sequence of transformation steps using one or more temporary variables that don't really mean anything; they are merely intermediate data structures. If you eliminated all of them and just had one transformation feed directly into the next, then the result would be an opaque glob of scary code. But from that, you can choose what temporary values do mean something real, and break up the computation at those spots. (Good rule of thumb: if your temporary variable is named '@tmp' or '$x', there's a good chance you should get rid of it. If it has a meaningful name, it will probably help a reader figure out what is going on. If it has a meaningful name that doesn't match its meaning, you will need to avoid traveling to certain countries where you could be tried and hanged for Willful Codeslaughter.)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://320735]
Approved by coreolyn
Front-paged by delirium
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2024-04-19 21:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found