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

I saw something in "Re: Re: Re: I don't use printf enough" that didn't make sense to me.

While I understand the @{[....]} and ${\....} constructs, I don't understand ${\~~....}.

Consider the following snippet:

use strict; use warnings; sub context { print wantarray ? "List\n" : "Scalar\n"; } my $string; $string = "Test @{[context()]} string"; $string = "Test ${\context()} string"; $string = "Test ${\~~context()} string"; __OUTPUT__ List List Scalar

I've seen the first two constructs before, but the third is a new one to me. How is ~~ forcing scalar context?

I've looked in perlop and find no mention of ~~. A single ~ is the bitwise negation operator. But I don't think that has anything to do with ~~. The only place I find mention of '~~' is under perlform, where it's mentioned as a "repeat the previous format character until the line is filled" format operator. But again that doesn't seem to make sense in the context of interpolating code into a string.

Of course all three of the above constructs are not terribly pretty, and should probably be avoided when it's convenient to do so. But that doesn't stop my wondering. If anyone can shed some light on what ~~ is doing, I'd love to hear.


Dave


"If I had my life to live over again, I'd be a plumber." -- Albert Einstein

Replies are listed 'Best First'.
Re: How does ~~ force string interpolation of code into scalar context?
by sauoq (Abbot) on Oct 25, 2003 at 09:27 UTC
    I've looked in perlop and find no mention of ~~. A single ~ is the bitwise negation operator. But I don't think that has anything to do with ~~.

    Actually, that's exactly what it has to do with. The ~~ is two bitwise negations. The first one forces its argument to be evaluated in scalar context and negates it. The second one undoes the first's negation.

    Note that it won't work on references.

    Update: It won't work with floating point numbers either, as bart rightfully points out.

    -sauoq
    "My two cents aren't worth a dime.";
    
      Note that it won't work on references.
      Or floating point numbers.
      sub PI { 4 * atan2 1, 1 } print "The value of PI is ${\~~PI}\n";
      Result:
      The value of PI is 3
      
      Ouch. That's a bit coarse.

      The truth is: bitwise not only works on strings, and on integers. It works differently on both, though the net result of double not is pretty the same: restoration of the original string, or the original integer.

      Hmm, stacking unary operators. I hadn't considered that as even being a possibility except for things like $$ and \\ for multiple levels of referencing/dereferencing.

      Thanks for pointing out a new idiom for me (which may not be all that necessary but is definately interesting to understand).

      In the spirit of exploration I found that the following will also at least compile and force scalar context. Some of them will mangle return values though. ;)

      sub context { print wantarray ? "List\n" : "Scalar\n"; } my $string; $string = "Test ${\~~context()} string"; $string = "Test ${\!!context()} string"; $string = "Test ${\+-+context()} string"; $string = "Test ${\-+-context()} string"; $string = "Test ${\&\&context()} string";

      Thanks again...


      Dave


      "If I had my life to live over again, I'd be a plumber." -- Albert Einstein
        I found that the following will also at least compile and force scalar context. Some of them will mangle return values though. ;)

        Actually, of the four additional combinations you tried, only -+- would be at all useful. It avoids mangling integers and floats. The three others mangle everything.¹ Also, with 5.6.1 and 5.8.0 at least, using this will cause warnings about ambiguity unless warnings are explicitly disabled.

        Still, it may have some golf merit in being a short way to impose scalar context on functions that return floating point numbers. For strings or ints, though, I think ~~ is still preferable. For golf or obfuscation that is. Of course, scalar() is far better for "real" code.

        By the way, -+- might also be written as - -, the plus or space only being necessary to differentiate it from a decrement.

        1. In fact, &\& will, I think, always fail under strict checking.

        -sauoq
        "My two cents aren't worth a dime.";
        

        I think these CAN be useful ... for decorative purposes ...

        $arg1 = "arg1"; $arg2 = "arg2"; $arg3 = "arg3"; sub f1 { return "1"; } sub f2 { return "0"; } sub f3 { return "3"; } print "${\-+- f1( $arg1 )}"; print "${\+-+ f2( $arg2 )}"; print "${\-+- f3( $arg3 )}"; print "\n"

        isn't that far better than the undecorated print statements? ( Same f1(), f2(), f3(), $arg1, $arg2, $arg3. )

        print f1( $arg1 ); print f2( $arg2 ); print f3( $arg3 );

        And FAR superior to the boring and mundane:

        print "103\n";

        --
        TTTATCGGTCGTTATATAGATGTTTGCA

Re: How does ~~ force string interpolation of code into scalar context?
by pg (Canon) on Oct 25, 2003 at 16:21 UTC

    So sometime human being confuse themselves. As sauoq pointed out, ~~ is nothing more than ~ and ~ again.

    However I disagree with one point bart mentioned in his post, in which he said that ~ works differently agasinst integer and string. In fact, it works in exactly the same way against integer and string. This becomes crystal clear if you understand this at the bit level (0=>1, 1=>0), not the human interpretation of those bits:

    use strict; use warnings; #integer 32 bit { my $a = 1; print "a = $a\n"; #a: 00000001, ~ - fffffffe print 0xfffffffe, "\n"; print "~a = ", ~$a, "\n"; } #string { my $a = "abcd"; (my $a_ord = $a) =~ s/(.)/sprintf "%02x", ord $1/ge; print "a = $a\n"; print "a_ord = $a_ord\n"; #a: 97, hex - 61, ~ - 9e #b: 98, hex - 62, ~ - 9d #c: 99, hex - 63, ~ - 9c #d: 100, hex - 64, ~ - 9b my $b = ~$a; (my $b_ord = $b) =~ s/(.)/sprintf "%02x", ord $1/ge; print "b_ord = $b_ord\n"; }
      In fact, it works in exactly the same way against integer and string.
      Does not. Try this:
      $\ = "\n"; print ~3; print ~"3";
      Result:
      4294967292
      Ì
      
      Now, if it worked exactly the same way for integers and for strings, how come the intermediate result is different?

      I stand by my point: even though they work differently (as shown here), the net result of the double not is exactly the same for both: the original value. That means that an integer produces the original integer, and that a string produces the original string.

      Perhaps you mean something other than I do?

        Perhaps you mean something other than I do?

        If I had to guess — and I do — I think he does mean something different than you do. I understand the points both of you are trying to make.

        Your two examples "work differently" only because you are, in reality, providing different data and interpretting the answer differently. It'll come as no surprise to you that they work the same if you make other things equal...

        print ~"3"; print pack("c",~ord("3")); # Or... print ~3 print unpack("L", ~"\x00\x00\x00\x03");
        and I think that's pg's point.

        Your point, however, is really that Perl does treat strings and integers differently. And it's a good point. Another example that clears things up a bit:

        $x = "3"; print ~$x; # This is... $x = 3; print ~$x; # Not the same as this... $x .= ""; print ~$x; # But, after stringification, it is.
        So, you're both right. :-)

        -sauoq
        "My two cents aren't worth a dime.";