sartak's Journal http://use.perl.org/~sartak/journal/ sartak's use Perl Journal en-us use Perl; is Copyright 1998-2006, Chris Nandor. Stories, comments, journals, and other submissions posted on use Perl; are Copyright their respective owners. 2012-01-25T02:46:21+00:00 pudge pudge@perl.org Technology hourly 1 1970-01-01T00:00+00:00 sartak's Journal http://use.perl.org/images/topics/useperl.gif http://use.perl.org/~sartak/journal/ bye http://use.perl.org/~sartak/journal/38839?from=rss <a href="http://sartak.blogspot.com/">I moved to blogspot</a> sartak 2009-04-22T00:24:34+00:00 journal Warnings are good, damnit! http://use.perl.org/~sartak/journal/38810?from=rss <p>Warnings highlight <em>possible</em> bugs. The presence of a warning does not necessarily indicate a bug.</p><p>Only valid constructs will generate warnings! If a construct were invalid, then the system would have issued an error.</p><p>Warnings are not only for new learners. Warnings are also useful to experts, especially in the context of an evolving system. Delegating vigilance to the environment alleviates the burden of maintenance.</p><p>Changing code to cease its issuance of warnings usually requires disambiguation. This disambiguation is beneficial, because unambiguous code is clearer than ambiguous code. Encode your intent so that current collaborators and future maintainers will not have to guess at it.</p><p>If you truly require your code to run without warnings, then disable warnings entirely. The creation of warnings for potentially misleading or unexpected behavior should never require a battle. Existing code will not become incorrect, because warnings are not errors. However, you should still strive to correct the problems that issue warnings in new and maintained code.</p><p>edit: Some have missed the point of this post. I am <em>not</em> saying that having your code spew warnings is good in itself. I'm saying that having some warnings to alert you to suspicious code and to guide your fixes is what is good.</p> sartak 2009-04-15T00:28:54+00:00 journal Breaking Sys::Protect http://use.perl.org/~sartak/journal/38702?from=rss <p>Sys::Protect does not bill itself as unbreakable protection, but it's fun to break it anyway.</p><p>PadWalker is used as an example of an XS module that could seriously mess with other code.</p><blockquote><div><p> <tt>#!/usr/bin/env perl<br>no strict;<br>use warnings;<br>use Sys::Protect;<br>use Test::More tests =&gt; 1;<br> <br>XSLoader::load(bless {}, 'Break::Sys::Protect');<br> <br>my $password = 'c53eb8f992b4fdf70a03a4d437820028';<br>is(${PadWalker::closed_over(sub { $password })-&gt;{'$password'}}, $password);<br> <br>package Break::Sys::Protect;<br>use overload q{""} =&gt; sub {<br>&nbsp; &nbsp; return "Math::BigInt::FastCalc"<br>&nbsp; &nbsp; &nbsp; &nbsp; if caller eq 'Sys::Protect';<br> <br>&nbsp; &nbsp; $_[0] = "PadWalker";<br>};</tt></p></div> </blockquote><p>Don't use Sys::Protect.<nobr> <wbr></nobr>:)</p> sartak 2009-03-26T02:52:19+00:00 bugs MooseX::Role::Parameterized http://use.perl.org/~sartak/journal/38309?from=rss <p>Jonathon Worthington just wrote about <a href="http://use.perl.org/~JonathanWorthington/journal/38308">Perl 6's new support for parametric roles</a>. Excellent!</p><p> <a href="http://search.cpan.org/~drolsky/Moose/lib/Moose.pm">Moose</a> supports this feature too, through the <a href="http://search.cpan.org/~sartak/MooseX-Role-Parameterized/lib/MooseX/Role/Parameterized.pm">MooseX-Role-Parameterized</a> extension I wrote a little over a month ago. It has proved to be a very useful pattern. I'm pleased that Perl 6 has it built in.</p><p>Out of curiosity, I ported the examples Jonathon provided to MXRP. I'll have to work more with rafl to make <a href="http://search.cpan.org/~flora/MooseX-Declare/lib/MooseX/Declare.pm">MooseX-Declare</a> support something resembling Perl 6's much nicer syntax. We do plan on having syntax for positional parameters in much the same way Perl 6's parametric roles do.</p><blockquote><div><p> <tt>package Greet;<br>use MooseX::Role::Parameterized;<br> <br>parameter greeting =&gt; (<br>&nbsp; &nbsp; is&nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'ro',<br>&nbsp; &nbsp; isa&nbsp; &nbsp; &nbsp; =&gt; 'Str',<br>&nbsp; &nbsp; required =&gt; 1,<br>);<br> <br>role {<br>&nbsp; &nbsp; my $p = shift;<br>&nbsp; &nbsp; my $greeting = $p-&gt;greeting;<br> <br>&nbsp; &nbsp; method greet =&gt; sub {<br>&nbsp; &nbsp; &nbsp; &nbsp; print "$greeting!\n";<br>&nbsp; &nbsp; };<br>};<br> <br>package EnglishMan;<br>use Moose;<br>with Greet =&gt; { greeting =&gt; "Hello" };<br> <br>package Slovak;<br>use Moose;<br>with Greet =&gt; { greeting =&gt; "Ahoj" };<br> <br>package Lolcat;<br>use Moose;<br>with Greet =&gt; { greeting =&gt; "OH HAI" };<br> <br>EnglishMan-&gt;new-&gt;greet; # Hello!<br>Slovak-&gt;new-&gt;greet; # Ahoj!<br>Lolcat-&gt;new-&gt;greet; # OH HAI!</tt></p></div> </blockquote><p>I'll skip the second example because it's contained by the third example.</p><p>Moose doesn't give you multiple dispatch. <i>sigh!</i> Instead we model the problem with a default value for the transform, which is a code reference. In this way we meet the original requirement of EnglishMan and Lolcat not needing to provide a nominative-&gt;accusative transform.</p><blockquote><div><p> <tt>package Request;<br>use MooseX::Role::Parameterized;<br> <br>parameter statement =&gt; (<br>&nbsp; &nbsp; is&nbsp; &nbsp; &nbsp; &nbsp;=&gt; 'ro',<br>&nbsp; &nbsp; isa&nbsp; &nbsp; &nbsp; =&gt; 'Str',<br>&nbsp; &nbsp; required =&gt; 1,<br>);<br> <br>parameter transform =&gt; (<br>&nbsp; &nbsp; is&nbsp; &nbsp; &nbsp; =&gt; 'ro',<br>&nbsp; &nbsp; isa&nbsp; &nbsp; &nbsp;=&gt; 'CodeRef',<br>&nbsp; &nbsp; default =&gt; sub {<br>&nbsp; &nbsp; &nbsp; &nbsp; sub { $_[0] }, # identity function<br>&nbsp; &nbsp; },<br>);<br> <br>role {<br>&nbsp; &nbsp; my $p = shift;<br>&nbsp; &nbsp; my $statement = $p-&gt;statement;<br>&nbsp; &nbsp; my $transform = $p-&gt;transform;<br> <br>&nbsp; &nbsp; method request =&gt; sub {<br>&nbsp; &nbsp; &nbsp; &nbsp; my ($self, $object) = @_;<br>&nbsp; &nbsp; &nbsp; &nbsp; print "$statement " . $transform-&gt;($object) . "?\n";<br>&nbsp; &nbsp; };<br>};<br> <br>package Language::Slovak;<br>sub accusative {<br>&nbsp; &nbsp; my $nom = shift;<br>&nbsp; &nbsp; (my $acc = $nom) =~ s/a$/u/;<br>&nbsp; &nbsp; return $acc;<br>}<br> <br>package EnglishMan;<br>use Moose;<br>with Request =&gt; { statement =&gt; "Please can I have a" };<br> <br>package Slovak;<br>use Moose;<br>with Request =&gt; {<br>&nbsp; &nbsp; statement =&gt; "Prosim si",<br>&nbsp; &nbsp; transform =&gt; \&amp;Language::Slovak::accusative,<br>};<br> <br>package Lolcat;<br>use Moose;<br>with Request =&gt; { statement =&gt; "I CAN HAZ" };<br> <br>EnglishMan-&gt;new-&gt;request("yorkshire pudding");<br>Slovak-&gt;new-&gt;request("boravicka");<br>Lolcat-&gt;new-&gt;request("CHEEZEBUR<nobr>G<wbr></nobr> ER");</tt></p></div> </blockquote><p>I have no conclusion, except that Perl 5 hasn't been stagnant, though its new features can be a lot more verbose than in Perl 6.</p> sartak 2009-01-17T20:21:41+00:00 cpan Devel::REPL: now with multiline support http://use.perl.org/~sartak/journal/34519?from=rss <p>I've been using <a href="http://search.cpan.org/perldoc?Devel%3A%3AREPL">Devel::REPL</a> for a while now. Like all good modules (<a href="http://perlcritic.tigris.org/">Perl::Critic</a>, <a href="http://poe.perl.org/">POE</a>, <a href="http://plagger.org/">Plagger</a>, etc), it's very extensible. <a href="http://chainsawblues.vox.com/library/post/a-perl-read-excute-print-loop-repl.html">Devel::REPL's design</a> is worth studying: keep a simple core and ship all the fancy behavior as plugins. <a href="http://www.iinteractive.com/moose/">Moose</a> amplifies the power and convenience of this design with roles, method modifiers, and general awesomeness.</p><p>There are plugins to dump output with Data::Dump::Streamer, enable tab completion of the current lexical environment and loaded modules, save input history across sessions, and more. However, if you dabble in other P-languages such as Python and Ruby (know thy enemy.. honest!) you'll find yourself wanting more out of Devel::REPL. Let's take the example of writing a factorial function in python:</p><blockquote><div><p> <tt>% python<br>Python 2.3.5 (#1, Dec&nbsp; 7 2006, 14:50:51)<br>[GCC 4.0.1 (Apple Computer, Inc. build 5363) (+4864187)] on darwin<br>Type "help", "copyright", "credits" or "license" for more information.<br>&gt;&gt;&gt; def fact(n):<br>...&nbsp; &nbsp; &nbsp;if n &lt; 2:<br>...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return 1<br>...&nbsp; &nbsp; &nbsp;return n * fact(n - 1)<br>...<br>&gt;&gt;&gt; fact(10)<br>3628800</tt></p></div> </blockquote><p>in irb:</p><blockquote><div><p> <tt>% irb<br>irb(main):001:0&gt; def fact(n)<br>irb(main):002:1&gt; if n &lt; 2<br>irb(main):003:2&gt; 1<br>irb(main):004:2&gt; else<br>irb(main):005:2* n * fact(n-1)<br>irb(main):006:2&gt; end<br>irb(main):007:1&gt; end<br>=&gt; nil<br>irb(main):008:0&gt; fact 10<br>=&gt; 3628800</tt></p></div> </blockquote><p>in lua:</p><blockquote><div><p> <tt>% lua<br>Lua 5.1.2&nbsp; Copyright (C) 1994-2007 Lua.org, PUC-Rio<br>&gt; function fact(n)<br>&gt;&gt; if n &lt; 2 then<br>&gt;&gt; return 1<br>&gt;&gt; else<br>&gt;&gt; return n * fact(n-1)<br>&gt;&gt; end<br>&gt;&gt; end<br>&gt; =fact(10)<br>3628800</tt></p></div> </blockquote><p>and in Devel::REPL:</p><blockquote><div><p> <tt>% re.pl<br>$ sub fact {<br>Compile error: Missing right curly or square bracket at (eval 60) line<br>8, at end of line<br>syntax error at (eval 60) line 8, at EOF</tt></p></div> </blockquote><p>D'oh. OK, let's try again..</p><blockquote><div><p> <tt>% re.pl<br>$ sub fact { my $n = shift; return 1 if $n &lt; 2; $n * fact($n - 1) }<br> <br>$ fact 10<br>3628800</tt></p></div> </blockquote><p>Well, that works in this case, but one big line of code quickly becomes unmanageable.</p><p>Recently I had the idea to use PPI to figure out if the current line of code is complete. PPI::Dumper quickly confirmed that I can detect the most important case: a PPI::Structure that doesn't have both a -&gt;start and -&gt;finish. Structures encompass { {nested { blocks } } }, (parentheses), [array indexing], {hash indexing}, and so on. Hopefully future versions of PPI will be able to figure out that, say, an s/// or quoted string is incomplete.</p><p>Here's what the factorial example looks like with the MultiLine::PPI plugin.</p><blockquote><div><p> <tt>% re.pl<br>$ load_plugin 'MultiLine::PPI'<br>1<br>$ sub fact {<br>&gt; my $n = shift;<br>&gt; return 1 if $n &lt; 2;<br>&gt; $n * fact($n - 1);<br>&gt; }<br> <br>$ fact 10<br>3628800</tt></p></div> </blockquote><p>I believe Devel::REPL is the only Perl REPL that can do this. Hooray!<nobr> <wbr></nobr>:)</p><p>You can change the default prompts with my FancyPrompt plugin. Here's how I actually have my prompt (code is slightly different to show off nesting). It may look like "ugh", but it's actually really nice when you're in the driver's seat.</p><blockquote><div><p> <tt>% re.pl<br>&gt; sub fact {<br>&gt;&gt; my $n = shift;<br>&gt;&gt; if ($n &lt; 2) {<br>&gt;&gt;&gt; return 1;<br>&gt;&gt;&gt; }<br>&gt;&gt; else {<br>&gt;&gt;&gt; return $n * fact($n-1);<br>&gt;&gt;&gt; }<br>&gt;&gt; }<br> <br>&gt; fact 10<br>3628800</tt></p></div> </blockquote><p>MultiLine::PPI hasn't been CPANed yet, but you can get it (and other new plugins) from <a href="http://dev.catalyst.perl.org/repos/bast/trunk/Devel-REPL">the Devel::REPL Subversion repository</a>.</p><p>I'll continue stealing good features from other REPLs.<nobr> <wbr></nobr>:)</p> sartak 2007-09-22T01:20:29+00:00 tools