Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

How's your Perl? (II)

by xmath (Hermit)
on Jul 21, 2004 at 19:38 UTC ( [id://376362]=perlmeditation: print w/replies, xml ) Need Help??

After the success of last year's edition, #perlhelp (EFnet) is proud to present... insaner than ever... the second round of How's your Perl? ! :-)

There are thirteen exercises this year. Each exercise consists of a predicate to be made true by a short snippet of code preceding the test. (For example, a simple way of checking your solution for an exercise is: perl -e '<solution>; <exercise> and print "ok!\n"')

  1. Don't reuse the method of solution of one exercise for any other.
  2. Don't make use of any external files (including modules).
  3. No tie() and no bless().

All exercises have been tested with perl 5.8.*, and solutions do not necessarily have to work with any other version. Don't hesitate to use deprecated or experimental features, or depend on implementation details or even bugs, but avoid platform dependencies.

When posting comments, please protect spoilers and solutions from accidental viewing, for example using a black-box (<table bgcolor="#000000"><tr><td><font color="#000000">Text goes here</font></table>)

Have fun!


(not in order of difficulty)

Exercise 1: \$foo =~ /^[A-G]/ Exercise 2: \$foo =~ /^[H-N]/ Exercise 3: \$foo =~ /^\0/ Exercise 4: \$foo =~ /IO::Handle/ Exercise 5: \$foo =~ /IO::/ && $foo Exercise 6: \$foo[$[] == \$foo[$[+1]
Exercise 6 Update: \$foo[0] == \$foo[1] && !$[
Exercise 7: !eval { ($foo) = $foo } Exercise 8: !eval { [ @foo ] } Exercise 9: $foo && $foo =~ /^0\z/ Exercise 10: $foo =~ /^0\z/ && $foo Exercise 11: "$|" == 2 && $| == 0 Exercise 12: ($| = 1) == 2 Exercise 13: undef

Special thanks to mauke and woggle.

UPDATE: Apparently the notion of taking advantage of a yet-to-be-fixed bug is controversial. I therefore note that only 8, 11, and 12 are fishy in this regard, the other exercises are definitely solvable without exploiting bugs.

UPDATE: Minor rephrase of instructions for clarity.

UPDATE: Cool! ambrus and wog found an innovative way of solving 8 without exploiting a bug! :-D

UPDATE: Official solutions will be posted on monday. Until then there are hints below.

UPDATE: Official solutions have been posted.

Replies are listed 'Best First'.
Re: How's your Perl? (II)
by tilly (Archbishop) on Jul 21, 2004 at 22:59 UTC
    I have a magic solution that solves ALL of these at once according to your simple test!
    print "ok!\n"; #
    ;-)

      I thought that, by convention, such solutions were expected to be too long to fit in the margins of one's post.

      --
      F o x t r o t U n i f o r m
      Found a typo in this node? /msg me
      % man 3 strfry

        So call me unconventional. It wouldn't be the first time. :-)
      Yes, that would solve any one of the problems, but not all, as the rules explicitly forbid you from using the same solution on more than one problem.


      Believe nothing, no matter where you read it, or who said it - even if I have said it - unless it agrees with your own reason and your own common sense. -- Buddha
        Since the simple test doesn't test for "using the same solution on more than one problem", what I said remains entirely true. ;-)
Re: How's your Perl? (II)
by ccn (Vicar) on Jul 21, 2004 at 21:42 UTC

    13-th (xmath says that this is a cheat)
    use subs 'and';sub and :lvalue {$_};

    9-th
    $foo="\n0";$*++;

    7-th
    *foo = \1;

    6-th
    sub f{\@_}; *foo = f($_,$_);

    2-d
    *foo=\pos;

    1-st
    $foo = *_;

    Update: 2-nd and 9-th added

    Update: 10-th REMOVED, because it use the same method as 9-th

      13-th: Heh, clever, but it doesn't actually make the predicate true, it just makes the example method of checking your solution work.

      Update: and subs.pm is a module ;-)

Re: How's your Perl? (II)
by BrowserUk (Patriarch) on Jul 22, 2004 at 04:14 UTC

    2 & 7
    *foo = \substr '...', 1, 1;


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon
Re: How's your Perl? (II)
by itub (Priest) on Jul 22, 2004 at 00:32 UTC
    1:
    $foo=*a;
Re: How's your Perl? (II)
by Errto (Vicar) on Jul 22, 2004 at 03:59 UTC

    Update:modified slightly.

    6:
    my @foo = (0); $[ = -1;

      That doesn't seem to work here.


      ___________
      Eric Hodges
        I modified it slightly. I'm running: This is perl, v5.8.3 built for i386-linux-thread-multi

      Confirmed on 5.6.1, 5.8.0, 5.8.1, 5.8.3. Doesn't work on 5.8.4 and 5.8.5.
      And I think it should not work, because $foo[$[] is the first element and $foo[$[+1] is the second; I don't see how $[ and $[+1 can refer to the same element.

      All exercises have been tested with perl 5.8.*, and solutions do not necessarily have to work with any other version.

      I take this to imply that solutions should work with all 5.8.* perls.

        Hm, strange.. I actually wrote $foo[$[] in the assuption this would prevent any $[-fiddling and force the real solution, but it seems $[ really doesn't work properly in perl: perl -le '$[ = -1; @x = (42); $y = 0; print $x[$y]' prints 42 for me on 5.8.3 and 5.8.4...

        I'll add a note to the exercise that the intention is to solve it without diddling $[

        Fair enough. My only excuse is that 5.8.3 is the only version I have, and that the other way seemed too similar to one of the solutions from last time around so I wanted to try something different :) I was trying to use the fact that $foo[-1] is the last element in the array, so if the array only has one element ...
Re: How's your Perl? (II)
by ambrus (Abbot) on Jul 22, 2004 at 13:55 UTC

    Spoilers:

    1:

    $foo = *bar; \$foo =~ /^[A-G]/ and print "Ok!\n";

    7:

    *foo = *1; !eval { ($foo) = $foo } and print "Ok\n";

    6: I don't know weather this is cheating or not, but it does make the (updated) expression true:

    *foo = *_; sub { \$foo[0] == \$foo[1] && !$[ and print "Ok\n"; } -> ($ +x, $x);

    Update: a clean solution for 6:

    sub{*foo=\@_}->($x,$x); \$foo[0] == \$foo[1] && !$[ and print "Ok!\n";

    Update again: 2:

    *foo = \substr(1,0,1); \$foo =~ /^[H-N]/ and print "Ok!\n";

    Update: a wildcard solution for 3:

    BEGIN{$^H{"qr"}=sub{""};$^H|=3<<16}; \$foo =~ /^\0/ and print "Ok!\n";

    Update: I finally realized that I should have known 12 from the start: it was in last year's quiz.

    $[ = 2; *| = *[; ($| = 1) == 2 and print "Ok!\n"; warn 0+$|;

    Update: and here's an answer for 8, although you might take it as cheating as it requires an adittional option on the command line to be set.

    perl -wde 'sub DB::DB { ++$foo==2 and die "break out the eval"; }; !ev +al { [ @foo ] } and print "Ok!\n"; '

    Note that I'm not just executing the print Ok statement with some trick. The expression !eval { [ @foo ] } actually gets evaluated, but somehow an exception gets generated inside the eval, thus eval returns false.

    Update: you can give the switch in the shebang line too. If you write this to a file and execute it with perl, it works.

    #!perl -d sub DB::DB { ++$foo==2 and die "break out the eval"; }; !eval { [ @foo + ] } and print "Ok!\n";
      You don't need any switches!

      BEGIN{$^P=0x22;sub DB::DB{++$foo==2 and die}}

      (I am pretty sure that is not the official solution, by the way, and it means that 8 does not need to exploit actual bugs.)

      updated: Oops, copied a wrong version initially. One character difference.

Re: How's your Perl? (II)
by xmath (Hermit) on Jul 22, 2004 at 14:14 UTC

    Official hints:

    [all]There are two "wildcard solutions" that each can be used to solve nearly all of the exercises. Due to the no-reuse rule you can use each of them only once, and they're officially used for exercises 3 and 13.
    [1-5]Just explore all kind of scalar references. If you're really desperate you can plow through Perl_sv_2pv_flags() in sv.c in the perl source code to see exactly how references get stringified.
    [3]Good candidate for wildcard one: Find a way to override the meaning of the regex.
    [4,8]The pattern of exercise 4 is misleading, but the search down this incorrect path may reveal the solution to exercise 8. Exercise 4 is actually simpler than you'd think.
    [5]A fairly recent and unknown class of built-in objects.
    [6]Alias. (Last year there was a similar one which could be solved by manipulating $[. I tried to prevent that this year, though initially without success)
    [7]Make modification fail.
    [8]Find something that fails to get assigned anywhere. See also hint about 4 and 8 above. The ability to acquire this thing at all is most likely a bug.
    [9]Subtly perturb the meaning of the regex.
    [10]Have $foo change as a result of the first part of the predicate test.
    [11]Find a way to scribble onto $| so rudely it never gets properly turned into 0 or 1. This mechanism is most likely a bug.
    [12]Find a variable that ignores being assigned to. This behaviour is most likely a bug.
    [13]The best spot for wildcard two: A feature was added in 5.8 with which you can modify constants.
Re: How's your Perl? (II)
by diotalevi (Canon) on Jul 22, 2004 at 17:25 UTC

    1. $foo = *_;
    2. *foo = \ substr "", 0, 1;
    3. BEGIN { $^H = 0x30000; $^H{"qr"} = sub{""}; }
    4. sub { *foo = \@_ }->( $foo, $foo )
    5. *foo = \ "constant"
    6. I didn't know this one until I saw ccp's answer and I don't know of a second way.
    7. *foo = *`; $* = 1; "true\n0"=~/\z/;
    8. *| = \$foo;
    9. 2 =~ /(2)/; *| = *^N;
    10. xmath gave this one to me because it contradicted the documentation and it isn't supposed to be possible. There is a loophole but it requires reading an obscure bit from Changes5.8.

Re: How's your Perl? (II)
by xmath (Hermit) on Jul 26, 2004 at 13:26 UTC

    Solutions:

    Note that for a few exercises multiple solutions are given.

    [1] $foo = *x;
    [2] *foo = \substr $x, 0;
    *foo = \vec $x, 0, 8;
    [3] BEGIN { $^H |= 0x30000; $^H{qr} = sub{""} }
    [4] *foo = qr/IO::Handle/;
    [5] *foo = find PerlIO::Layer "raw";
    [6] *foo = sub{\@_}->($x, $x);
    [7] *foo = \42;
    [8] *foo = sub{\@_}->(${*STDIN{IO}});
    sub DB::DB { die if ++$x==2 } BEGIN { $^P |= 0x22 }
    [9] $foo = "\n0"; $* = 1;
    [10] //; *foo = \$+[0];
    [11] *@ = *|; eval { die "2" };
    [12] 2 =~ /(2)/; *| = \local $1;
    2 =~ /(2)/; *| = *^N;
    $[ = 2; *| = *[;
    [13] &Internals::SvREADONLY(\undef, 0); undef = 42;

Re: How's your Perl? (II)
by roju (Friar) on Jul 22, 2004 at 15:54 UTC
    1.
    $foo=*STDOUT

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://376362]
Approved by ysth
Front-paged by ysth
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-03-29 06:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found