in reply to Re: Perl style: Arguing against three-argument join() (++join '')
in thread Perl style: Arguing against three-argument join()

You start out with "you have $count left" and then some refactoring leads to $count being replaced by $new+$old and you have too much sense to do something bizarre like "you have ${\($new+$old)} left" (which doesn't scale well anyway when the strings and expressions grow to the point that more than one line is called for) so the next obvious choice is "you have " . $new+$old . " left" which is, unfortunately, quite wrong. Fixing it starts to give you a hint of how concatenation can suck, "you have " . ($new+$old) . " left".
Lessee, in Perl 6 we fixed the precedence of concatenation with respect to + (at your suggestion), so that part's okay...

If you want to keep your current style you can write:

$html ~= [~] createLink( $USER, "you" ), " have ", $new + $old, " message", 1 == $new+$old ?? "" !! "s", " left";
but you can also say:
$html ~= createLink( $USER, "you" ) ~ " have " ~ $new + $old ~ " message" ~ (1 == $new+$old ? "" : "s") ~ " left";
or you can interpolate with closures:
$html ~= "{createLink $USER, "you"} have { $new + $old } message{" +s" x ($new+$old == 1)} left";
or spread it out blockishly:
$html ~= "{ createLink $USER, "you" } have { $new + $old } message{ "s" x ($new+$old == 1) } left";
or you can use methods and subs:
$html ~= "$USER.createLink("you") have &pl($new+$old,"message") le +ft";
or some combination of those...
I've also come to dislike sprintf for such concatenations. I don't like the out-of-order nature between non-format-specifier parts of the first argument and the other items being concatenated into the result. And I don't like the separation between the format specs and the values being formatted. I've also seen too many mistakes like sprintf "bleh $foo%s bar", complex($expr) where $foo might contain a % character. In most cases I find that the majority of the parts are simply being concatenated so if any of the items need 'printf' formatting, then I use sprintf to format just that item:
$html .= join '',
    createLink( $USER, "you" ),
    " have a ",
    sprintf( "%+.2f", $rating ),
    " rating";
that would now look more like:
$html ~= [~] createLink( $USER, "you" ), " have a ", $rating.fmt("%+.2f"), " rating";
or maybe just:
$html ~= "{createLink $USER, "you"} have a $rating.fmt("%+.2f") ra +ting";
Which might lead to the suggestion of here-docs, which I really dislike since they can't be indented and can fail very confusingly in the face of invisible trailing whitespace.
Well, we fixed the indent part at least, though you're still on your own with trailing whitespace.
I hope that leads to some to think of suggesting a "real" templating system. That's often an excellent suggestion. Of course it isn't an appropriate replacement for tons of cases of concatenation. (:
Indeed. Though with enough Ways To Do It you almost don't need a templating system... :)

Replies are listed 'Best First'.
Re^3: Perl style: Arguing against three-argument join() (Perl 6)
by tye (Sage) on Jan 25, 2008 at 03:12 UTC
    we fixed the precedence of concatenation with respect to + (at your suggestion)

    Thanks! And you're welcome. ;)

    I like your first example. It is nice to have a "concat this list" option so compactly.

    One of the things that I really learned to like about join '', ... is how low the precedence of comma is, so I don't have to put parens around even 'the ternary'. I agree that ?? :: should bind looser than concatenation but that also means I probably won't be doing direct concatenation of long lists of expressions. (Which is not a problem since there are better options.)

    And the rest of the options are lovely.

    Well, we fixed the indent part at least, though you're still on your own with trailing whitespace.

    I'll have to review the lastest proposal on handling of indenting as I wasn't sold on some of the previous versions. But why don't you ignore trailing whitespace after the delimiter? I've decided that it is almost always better to do s/\s+$// over chomp because trailing whitespace is invisible and really deserves to be ignored. Tell me which line has the extra leading space and which one has the extra trailing space:

    LINE LINE LINE LINE LINE

    Sure, you can do it, if you know to look specifically for it, but it just sucks to have things that break due to such. At the very least, Perl 6 should shout "I noticed you had trailing whitespace after what would have otherwise ended your here-doc, but I didn't ignore it and that is probably why I couldn't find the end of your string". (:

    Is there some value to allowing trailing whitespace to make the delimiter not the delimiter? The only value I come up with is a way to include something that looks like the delimiter in the output. I'd much prefer that be done in a much more visible way. Using such a subtle trick deserves a comment pointing out what is going on. But it is worse because (having worked even in a small company where my editor actually shows me trailing whitespace) I know that lots of editing situations don't give trailing whitespace much respect. Lots of things strip it or add it with little justification.

    Surely, several of the above interpolation techniques would be better methods for including a line equal to the delimiter in the here-doc:

    my $string= <<END; You end your here-doc with a line like: {''}END but be sure to prevent any trailing whitespace from sneaking in! END

    What purpose am I missing?

    - tye        

      But why don't you ignore trailing whitespace after the delimiter?
      We do. I was talking about trailing whitespace within the string.

        Oh, I agree with that decision (at least most days; simple enough to do that yourself, too). Cool.

        - tye        

      my editor actually shows me trailing whitespace

      I have my editor set to strip trailing whitespace on save for most filetypes and all 17 language filetypes I have it configured for.

      Are there any languages where trailing whitespace can be significant? (Other than the above example.)


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re^3: Perl style: Arguing against three-argument join() (++join '')
by dragonchild (Archbishop) on Jan 25, 2008 at 00:10 UTC
    $html ~= [~] createLink( $USER, "you" ), " have a ", $rating.fmt("%+.2f"), " rating";
    Couldn't that be written as:
    [~=] $html, createLink( $USER, "you" ), " have a ", $rating.fmt("%+.2f +"), " rating";

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      Nope, because that would come out to A ~= B ~= C ~= D, which would only work if assignment were left associative.
        If attempts to modify a constant item instead created a temporary variable to put it in should it be the RHS, then that would work regardless of associativity.

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?