Given the recent discussions about cosmic rays and their influence on this site, I was tempted to make the obvious reference and name this "Fantastic For", but I resisted it due to it's utter sillyness. It wasn't all that true either, for that matter. :)

Anyhow, the goal is once again to find out: what is really happening?

#!/usr/bin/perl -w use strict; for(;$_?$,:(${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.chr ord);) { for(s .. Just another perl hacker.){ } for(;s;.;;;print){ } }
Also, since I didn't have room for an eval, I hope the chr and ord will fill it's place this time. :)


You have moved into a dark place.
It is pitch black. You are likely to be eaten by a grue.

Replies are listed 'Best First'.
Re: foreach(silly..japh)
by domm (Chaplain) on Mar 06, 2002 at 10:17 UTC
    Just a reminder:

    Syntax of for:

    for (init something;test;do something) {
        stuff
    }
    
    In the first for, you don't init anything, have a long test, and do nothing, so you could also write the first line as a while-loop:
    
    while ($_?$,:(${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.chr ord)) {
    
    Here you first check if $_ is defined. If it is, you return $, which defaults to undef, thus ending the loop. If $_ is not defined (the default), we enter this statement:
    ${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.chr ord
    
    Now, lets de-obfuscate:

    ${_} is the same as $_, the curly braces beeing used like in @{$arrayref}

    q.. . q,., . qq,S=, ^ q.$. . $= => $_=q,., . chr ord
    
    looks like
     '' . '.'  .   "$=" ^  '$' . $= ,  $_= '.' . chr ord
    
    when using normal quotes.

    This is a list consisting of two items:

    '' . '.'  .   "$=" ^  '$' . $=
    and
    $_= '.' . chr ord
    Lets look at the first part:

    '' . '.' . "$=" ^ '$' . $=

    This uses ^ as XOR, which somehow means (i'm not tha good at bitwise stuff)

    that each bit on the left of ^ gets XOR'ed with each bit on the right, so:

    '.$=' ^ '$60'
    (where is the 60 coming from? $= or $FORMAT_LINES_PER_PAGE defaults to 60) which yields the linebrake used in the cascade.

    Now, the second part:

    $_= '.' . chr ord
    This is very intuitive way to write
    $_= '.'.$_
    ord converts the contents of $_ into the numeric ascii value. Those values then get passed to chr, wich converts numeric asscii values to the corresponding character.

    Adding the two parts together, we now have:

    ($_="\n",$_='.'.$_;)
    Which can be further simplified to:
    ($_=".\n")

    So the whole first line looks now like

    for(;$_ ? undef : ($_=",\n") {
    
    for(s .. Just another perl hacker.) {
    
    Here you use a . as a regex-separator, so this looks like
    for(s//Just another perl hacker/) {
    
    which substitutes the first empty string in $_ with 'Just another perl hacker' and therefor is the same as
    s//Just another perl hacker/;
    
    
    for(;s;.;;;print){ }
    
    remebering the for-syntax, you here again intialise nothing.
    The continuination-test looks de-obfuscated like s/.//
    which a) removes the first char of $_ (thus causing the cascading effect) and b) returns undef if $_ is empty, stopping the for-loop and instead of incrementing a counter (which is usually done here), you just print $_.
    The loop itself does nothing;

    So:

    while (s/.//) {
          print $_;
    }
    
    We end up with:
    while($_ ? undef : ($_=".\n")) {
        s//Just another perl hacker/;
        while (s/.//) {
            print;
        }
    }
    
    Now lets de-obfuscate the algorithm

    The stuff inside the main for-loop is quite easey:

    Put "Just another perl hacker" into $_, chop of the first char and print it.

    The interesting stuff happens in the definintion of the first while loop

    If $_ is defined, return undef. As $_ is not defined by default, in the first run, do the other part if the ? : statement, which sets $_ to "\n."

    Now we enter the code in the while-loop, that adds "Just another perl hacker" in front of $_ and than prints the cascade.

    That's it (I think ...)

      Very nice. :) You almost got it all. However,

      $_= '.' . chr ord
      is not exactly the same thing as
      $_= '.'.$_
      Consider this:
      ${_} = q...q,.,.qq,$=,^q.$..$=; print ord() . "," foreach(split//);
      and then try to replace like this:
      
      for(;$_?$,:(${_} = q...q,.,.qq,$=,^q.$..$= => $_=q,.,.$_ );) {
      
      It destroys the output (or should, at least). This is because ord returns the value of the first character in the string it is fed. There is a difference. If you replace all the way down to $_="\n" then it works again, of course. :)

      For more clarity,

      for(s//Just another perl hacker/) {
      is really
      
      foreach(s//Just another perl hacker/) {
      
      - although they are interchangeable syntax-wise in perl.

      I don't know if you used it, but sadly deparsing gives a lot away. What I do think is funny is that deparsing translates one for to while, one to foreach and leaves the last as a for:

      while ($_ ? $, : ($_ = '.' . "$=" ^ '$' . $=, $_ = '.' . chr(ord $_))) + { foreach $_ (s// Just another perl hacker/) { (); } for (; s/.//; print $_) { (); } }
      Then again, I guess I am easily amused.

      I like your initial reminder too - that was exactly what this was "about" - abusing the for construct, which is also a bit special in perl. :)

      And oh, there is one more stripping possible to do - to get to approximately where I started (using your example):

      $_=".\n"; s//Just another perl hacker/; while (s/.//) { print; }
      Neither of the for loops has any real reason to be nested into any other - it is really just three separate lines of code.

      Thank you for taking the time - it is appreciated. :)


      You have moved into a dark place.
      It is pitch black. You are likely to be eaten by a grue.
        Well, even if i didn't get right 100%, really trying to understand what is happing in some obfuscated code is at least as amusing as writing it.

        And a lot more fun than just copy-and-past'ing the code to a file and letting it run ...