Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: I can see the forest…

by opqdonut (Acolyte)
on Oct 09, 2004 at 15:35 UTC ( [id://397875]=note: print w/replies, xml ) Need Help??


in reply to I can see the forest…

Nice one! Implicit evaluation of a used confusingly. Took me a little while to figure how you got the text inside $_ and the qw) trick is very ingenious too. A fine example of how beautiful perl can be :)

Tips for the hopeless:

  • qw) starts a string that terminates at the next ) so actually the whole script is stuff assigned into @j!
  • the definition of @j stops at the second comma on line 5, so the rest is evaluated but not assigned anywhere!
  • the s""@j," puts @j into $_ and then the 's (" )))g' (which is actually s/" //g in disguise!) eliminates some (non-existant?) quotes
  • Finally, we get a 'print' that spews out $_ beautiful!

J

Replies are listed 'Best First'.
The making of (was: I can see the forest…)
by Aristotle (Chancellor) on Oct 09, 2004 at 19:01 UTC

    Yep, though you missed a few bits. :-) I'll get to that eventually.

    This started with a much simpler idea. What I really wanted to do was:

    @j = "Just", @a = "another", @p = "Perl", @h = "hacker"; s//@j,/, prin +t

    I was hoping that @j would actually be assigned all the values the assignments to its right evalute to as well, so it would become ("Just", "another", "Perl", "hacker"), except a human reader would be caught off guard by the commas, wondering just for a second where all the other words came from when none of @a @p @h are actually ever used.

    Using s//$foo/ to assign $foo to $_ is actually standard fare in obfuscations. You'll see that a lot. I added it here to add a slight air of obfuscation that would keep people off balance for just a moment longer.

    Unfortunately, Perl DWIMs too well here. :-( Larry did a very good job. :-) To keep with the idea I had to introduce a pair of parens:

    @j = ( "Just", @a = "another", @p = "Perl", @h = "hacker" ); s//@j,/, +print

    Of course that's a dead give-away. So I had to find a way to hide the fact that there's a paren there; the easiest way to deceive humans is to lull them into complacence by feigning structure with repeating patterns, to make them misinterpret which parts belong together. Creative use of spacing and indentation is very helpful here — how often have you been mocked by a piece of misleadingly indented code whose problems became immediately obvious once you fixed the indentation? So I added a bunch of parens…

    @j = (( "Just" )), @a = (( "another" )), @p = (( "Perl", )), @h = (( "hacker" )),

    Now, I had to somehow eat one of the two closing parens on the first line. The easiest way is to use it as a delimiters for some quote-like operator; I chose qw// because it discards extraneous spacing, of which there'll be a bunch. Pay attention to where the sequence stretches to now:

    
    @j = (( qw) "Just"    )),
    @a = ((     "another" )),
    @p = ((     "Perl",   )),
    @h = ((     "hacker"  )),
    

    All that whitespace is part of the qw//, but it does not end up in the list generated by it. However, the quotes are part of the first element in that list — they'll need to be removed later. In effect, this is equivalent to

    @j = ( '"Just"', @a = 'another', @p = 'Perl', @h = 'hacker',

    Behold — one paren on the first line is without a partner now! :-)

    But there's this pesky qw// in the first line now that indicates an obvious difference. Lets put some of those in the other lines to give the appearance of regularity and structure again:

    @j = (( qw)"Just" )), @a = (( qw"another" )), @p = (( qw"Perl" )), @h = (( qw"hacker" )),

    Here, the quotes no longer indicate double quoted strings — they're actually delimiters for the qw// sequences. Since that one discards whitespace to return a list of whitespace separate words, we can add a little more space. And Perl will happily ignore whitespace between the qw and the first delimiter, so I lined up all the quotes to strengthen the appearance of structure:

    @j = ((qw)" Just " )), @a = ((qw " another" )), @p = ((qw " Perl " )), @h = ((qw " hacker " )),

    I removed the initial space as well so that for the first qw// because human readers are conditioned to instinctively match up pairs of delimiters as they read — so they promptly see (qw) when they look at it.

    Note that adding spaces on the first line where the quotes are part of qw// literal changes the result — the code is now equivalent to

    @j = ( '"', 'Just, '"', @a = 'another', @p = 'Perl', @h = 'hacker',

    If you print "@j" now (or, indeed, s//@j/, print) you will get

    " Just " another Perl hacker

    And that's the reason for that s/" //g you didn't figure out.

    Btw, you can cut a long story short on this obfu by deparsing it:

    $ perl -MO=Deparse japh.pl @j = (('"', 'Just', '"'), @a = 'another', @p = 'Perl', @h = 'hacker', +()), (s//@j,/, s/" //g), print($_); - syntax OK

    It is all about misleading the reader. The same tools that can be used to add cues and structure to code to make it readable can also be abused to add cues and structure that disagree with reality — plain old lies. I found myself wishing Perl wasn't quite designed so well though — I had hoped not to have to use any deception. Oh well. :-) It was still a fun diversion and is actually a JAPH I like, all the same.

    In hindsight, it would have been a little more effective yet to lay it out a little broader:

    @j = ((qw)" Just " )), @a = ((qw " another" )), @p = ((qw " Perl " )), @h = ((qw " hacker " )), (()),),(s""@j,",s (" )))g), print

    Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://397875]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (8)
As of 2024-03-28 09:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found