Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re: Secret Perl Operators: the boolean list squash operator, x!!

by Tanktalus (Canon)
on Jul 31, 2006 at 20:37 UTC ( #564865=note: print w/replies, xml ) Need Help??

in reply to Secret Perl Operators: the boolean list squash operator, x!!

I've said this once before. Using boolean algebra in numerical context relies on obscure implementation details while using the ternary operator relies on well-defined (and documented), designed-that-way implementation details. For that reason alone, I would not want to see this construct (not operator) in code I'd have to maintain later.

By declaring this an operator, you're making an analogy that it has some sort of precedence that can be used to avoid parenthesis - in fact, this looks more like a function in reverse (the parentheses come before the "name" of the function, which is "x!!"). So that makes it the first awkward operator we've got, even given all the extras (e.g., goatse operator, etc.).

I would instead suggest that a clearer, more maintainable version might be ($string) x ($cond ? 1 : 0). Definitely longer than your operator, but I'm not only not claiming this to be an operator (more of an idiom or pattern), but it'll be way more obvious to anyone reading it what I'm trying to do. Sure, there's still some duplication (the ?1:0 part), but not a lot more than the duplication your operator has (the x!! part).

That said, I don't find either of your original "problem" examples to be particularly onerous, and thus I may not be really appreciative of the elegance gained with some slightly obfuscated code.

Replies are listed 'Best First'.
Re^2: Secret Perl Operators: the boolean list squash operator, x!!
by Aristotle (Chancellor) on Jul 31, 2006 at 20:55 UTC

    obscure implementation details

    Disagree. The shape of booleans in Perl 5 is specified behaviour, and is only going to become more explicit in Perl 6.

    I would instead suggest that a clearer, more maintainable version might be ($string) x ($cond ? 1 : 0)

    If you’re using a ternary anyway, why would you want to throw in an x op? All that does is lose the shortcircuiting, make the code longer, and force some extraneous parens. Just do all the work using the ternary: $cond ? $string : ()

    I don’t find either of your original “problem” examples to be particularly onerous

    I’d never use the push version. The one with ternaries doesn’t look onerous because there are so many conditional bits that you have no hope of putting it all on a single line anyway, and the lists are simpler than the conditionals, and it’s highly regular, and all. I was trying to come up with an example that can’t be simplified using grep.

    I can’t recall the exact code that led me to post the thread on perl6-users which led Larry to nudge me in this direction, but it was a case of injecting a single list into the arguments of a one-liner join, where precedence forced me to parenthesise things, so the version using the ternary absolutely was more ornery than it should have been. With such a short list, it’s more annoying than the example I gave in the root node, because nothing really helps – putting it on a single line makes it unwieldy, breaking it into multiple lines makes it breathlessly verbose, using an extra temporary looks hackish. Sticking an x!! wouldn’t have been ideal, but would certainly read better than all the alternatives.

    Makeshifts last the longest.

      That !0 == 1 is not "well-defined" that I've noticed - perhaps someone could point out precisely where this is stated in a way that is not only definitive, but unambivalent (e.g., I don't want to see docs saying "It works this way, but don't trust it.").

      I have found referenced in perlsyn that ! $true_value returns something special. But it says nothing about ! $false_value.

      As for perl6, that's not part of the current conversation. As in, if they explicitly document that this is how the not operator works, great, it's explicit. Perl 5 doesn't document it, though, as tye pointed out in Re: One out of three ain't bad (order), perl 5 can't change it now.

      Even then, what really is a boolean in numeric context? What is a list, multiplied by "true" times? Or by "false" times? These are conceptually wrong. Just as adding "true + true" to try and get "2" (you don't - you get "true"). You may as well be trying to multiply $string x 'banana' - it makes as much sense.

      Except that computer programmers seem to think that 0 == false and 1 == true. Which is a horrible habit to be in (especially when someone gets the brilliant idea to compare if ($var == true)). Let's not expand on that disservice by promoting its further abuse. Instead, let's promote using booleans as booleans, numbers as numbers, and strings as strings. Now, before someone chews my head off ("That's not the perl way! We luvs our automatic type-changes!"), I do think that Larry got it right in Perl6. These automatic changes aren't actually so automatic. They use deep amounts of context to figure it out. And, if we continue with the warnings of perl5 (where things are allowed, but you're probably not doing it right - turn off warnings if you are), some automatic changes will continue to get warnings, even though they work. I hope that booleans in numeric context will be one of them. Unless, of course, you manually set something to say you want a specific boolean (or booleans in general) to have certain values in numeric (or even string) context. For example, setting:

      Bool.context(:numeric(true => 1, false => -1)); Bool.context(:string(true => Locale.gettext("true"), false => Locale +.gettext("false"));
      Or something like that (my perl6-fu is weak - that was intended to be something approaching a global setting). After all, what is the stringification of a boolean value? Shouldn't that be language-specific? Perhaps one variable should be "true" and "false" - but another variable should be "enabled" and "disabled". Of course, then another could use "male"/"female" (unless you need to keep track of 'other'), or "cowabunga dude!"/"to infinity and beyond!" or ... whatever you want. Of course, that would be more like $bool_var.context(...) or something

      Anyway, my point is that booleans != numbers. Anymore than strings are numbers. Using computers, we just have to store them as numbers, because we don't have anything else to store them with. We have boolean operators, numeric operators, and string operators. Use the right operators for the type of data you're using. If you want numbers, convert from boolean to numeric. Make it explicit. The next guy to take care fo the code will thank you.

        I don't want to chew your head off, but I don't want to loose wantarray either. Strings are numbers, and numbers are strings, all of them are sequences of bits, utf-8 strings are binary and a file is a sequence of bytes or a set of records, which are sets of fields. It depends all of how you look at them, and that's called context. That's why IV and SV exist, and that's why a number is stored internally as a string as well, if it was used in string context; and both representations are strung together.

        perl's context awareness may seem a swamp of pitfalls, but that's only until you understand it (by which statement I don't want to insinuate that you don't understand it.) But once you can speak perl it is just handy. In the long run? I don't know. Maybe we should just stick to C.


        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
          That !0 == 1 is not "well-defined" that I've noticed - perhaps someone could point out precisely where this is stated in a way that is not only definitive, but unambivalent (e.g., I don't want to see docs saying "It works this way, but don't trust it.").

        I can still remember Drew Sullivan, currently GTALUG President, pointing out years ago that !!!0 == 1 works, even if !0 == 1 is not necessarily accurate.

        Alex / talexb / Toronto

        "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

Re^2: Secret Perl Operators: the boolean list squash operator, x!!
by shmem (Chancellor) on Jul 31, 2006 at 23:20 UTC
    The x!! "operator" is a composite operator as the (babycart | supermarket trolley | pram) "operator" @{[]}, which isn't an operator either.

    It's called an operator here just for fun.

    Next, for cleanliness, it should be written as x !! EXPR. Ok, you could write this as x (!(!(EXPR))) if you don't trust precedence not verbosely stated by parens. Oh wait... list context? ;-)

    Then, LIST x NUMBER is a well-defined construct (see perlop). And !! as a double negation isn't that hard to grasp, either.

    Obscure implementation details? I can't see them here more than in any other perl construct. Perl is a langage with many obscure implementation details, many if not most of them are about context.

    One strength of perl (which I love) is the possibility to use idiomatic constructs which rely on well defined features of the language, which, of course, must be understood to use and -- to understand them. Once you have grokked double negation and list repitition via x, the construct () x !! EXPR is cheesecake to grasp at a glance.

    That said, I find the LIST x DOUBLE_NEGATION EXPR much more readable than the ternary operator in the context given by the OP, because it comprises less noise, that is, less chars necessary to grok to form a picture of what is meant in my mind. Another major benefit of it is that the construct () x !! EXPR keeps you aware of what x does to a list, and what unary ! is about (and that, if as a maintainer you don't grok them, you look up the docs).

    update: read Re^5: One out of three ain't bad (order). While you are correct in that addition, subtraction, multiplication, division make no sense in boolean algebra, perl doesn't care, because the scope of bolean algebra just ends after evaluating !!. Would you prefer a typecast instead?


    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://564865]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2018-03-19 05:47 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (232 votes). Check out past polls.