tag:blogger.com,1999:blog-55834119772001545192024-03-08T20:34:59.878+02:00Code speaksA blog on how to write nicer codeLeon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.comBlogger11125tag:blogger.com,1999:blog-5583411977200154519.post-84442332643321880132010-04-09T12:50:00.000+02:002010-04-09T12:50:17.641+02:00Enlightening perl's documentation (you too can help!)<p>(This entry was first posted <a href="http://blogs.perl.org/users/leon_timmermans/2010/04/enlightening-perls-documentation-you-too-can-help.html">here</a>)</p>
<p>Enlightened perl programmers often complain about how outdated most online perl manuals. Truth is, some of the official documentation is quite outdated too. Perl ships with a lot of documentation, some of it is old and badly needing some maintenance.</p>
<p>For example, a quick <code>ack</code> through the documentation showed about 250 cases of open used with a glob as its first argument (e.g. <code>open FOO;</code>), even one in perlstyle! I think everyone agrees that in 2010 that's no longer a good example. I don't think it has a place outside of perlfunc and perlopentut. The same argument goes for two argument open and use vars. I'm sure there are plenty of other issues that I can't think of right now.</p>
<p>That's not hard to fix, in fact you could almost write a program for it. It may be a lot of work though to fix all of them, but not so much to fix them one by one.</p>
<p>Some things are harder. Some things are a lot more work. Let's take some docs on object oriented programming perlbot, perltoot and perltooc for example haven't seen major updates since 1995, 1997 and 1999 respectively. perlboot and perlobj seem to have had the most loving the past decade, but can still use some more attention. Surely we all agree a lot has happened in object oriented perl in the mean time. We don't directly assign to @ISA anymore in our modules, do we?</p>
<p>But there's much more to improve in the documentations.
<ol><li>Why does perltrap list traps for perl4, awk and sed but not for modern languages like python, php or ruby?
<li>Why doesn't perlipc use IO::* instead of low level functions?
<li>Why isn't perlmodinstall Build.PL aware?</ol></p>
<p>I suspect many other pieces of documentation that I haven't taken a good look at that could also use a spring (autumn for inhabitants of the southern hemisphere) cleaning.</p>
<p>The good part of the story? <strong>You can help</strong>. This work can be done not only incrementally, but also distributed.</p>
<p>Edited to add: So how to get started? <a href="http://perldoc.perl.org/perlrepository.html">perlrepository</a> has detailed information how to submit patches. The easiest way is to fork perl at <a href="http://github.com/mirrors/perl">github</a> and when you're done mail the perl-5-porters about it. </p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.comtag:blogger.com,1999:blog-5583411977200154519.post-34980028499004219572010-03-28T12:45:00.000+02:002010-04-09T12:48:30.459+02:00DynaLoader considered harmfulharmful<p>(This entry was first posted <a href="http://blogs.perl.org/users/leon_timmermans/2010/03/dynaloader-considered-harmful.html">here</a>)</p>
<p><a href="http://perldoc.perl.org/DynaLoader.html">DynaLoader</a> is a portable high-level interface around you OS's dynamic library loading. It's the code that's loading your XS modules. It's actually doing a pretty good job at that. You may wonder then why I consider its use harmful.</p>
<p>If all you want to do is load the XS part of your module, it's the wrong tool for the job. Most of all because it has a truly awful interface. It requires you to inherit your module from it. It's common knowledge that public inheritance from an implementation detail is a really bad idea. It breaks not only encapsulation rather badly, but also violates separation of concerns.</p>
<p>This would be as bad as it is if DynaLoader didn't use AutoLoader. Because of this, when you call some undefined method on an instance of a class that derives from DynaLoader you don't get this error:</p>
<blockquote>Can't locate object method "undefined_method" via package "Foo"</blockquote>
<p>But this rather cryptic error:</p>
<blockquote>Can't locate auto/Foo/undefined_m.al in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .)</blockquote>
<p>No way a perl novice will understand what's going on there!</p>
<p>Worst part may be that this interface buys us very little in practice. The inheritance is used only once in the DynaLoader code, to call the dl_load_flags function. Surely there has to be a better way to pass on that <strong>one bit</strong> of data!</p>
<p>One solution to this is to simply encapsulate the module loading to a different module. This is a working approach, but then you're reimplementing a module that has been in the perl core for a decade now: <a href="http://search.cpan.org/perldoc?XSLoader">XSLoader</a>. It's not perfect, but it will cover 98% of all XS user's needs with significantly less disadvantages.</p>
<p>Honestly, there are valid uses of DynaLoader, but standard XS modules just aren't one of them. Use XSLoader or if that doesn't suit you write a patch for it or a better wrapper and put it on CPAN*, but don't use DynaLoader directly.</p>
<small style="font-size: smaller">* I might even do that myself.</small>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.comtag:blogger.com,1999:blog-5583411977200154519.post-52455117955576871332010-03-24T23:41:00.001+02:002010-03-24T23:41:57.580+02:00Threads in Perl, Erlang style<p>Adam Kennedy's recent post on <a href="http://use.perl.org/~Alias/journal/40241">threads in Padre</a> reminded me to post about an experiment of mine. Last year I learned some Erlang. I really liked their model of multi-threading: many threads that share no data at all and communicate through message queues. A lot of other things where really annoying though, specially their crappy support for strings and lack of libraries in general. I kept thinking <em>I want perl with these threads</em>, so I started implementing it. And thus <a href="http://search.cpan.org/perldoc?threads::lite">threads::lite</a> was born.</p>
<p>The main difference between threads::lite and threads.pm is that t::l starts an entirely new interpreter instead of cloning the existing one. If you've loaded a lot of modules, that can be significantly quicker and leaner than cloning. As an optimization, it supports cloning itself right after module loading, so you can quickly start a large number of identical threads. Threads can be monitored, so that on thread death their send an exit code to their listeners.</p>
<p>Every thread has it's own message queue. Every thread can send messages to any thread whose thread-id it knows. Any kind of data that can be serialized using <a href="http://search.cpan.org/perldoc?Storable">Storable</a> can be send, including coderefs.</p>
<p>Receiving messages is done on basis of pattern matching (based on smart matching). This can range from a simple null-pattern (matches anything, so returns the front message on the queue) to complex tables of patterns.</p>
<p>I've started building some high level abstractions on top of it, most notably a implementation of a <a href="http://search.cpan.org/perldoc?threads::lite::lists">parallel map and grep</a>. I'd like to do a map-reduce, but that's for a later stage.</p>
<p>This is very much an experimental module. I'm still not sure perl is really suitable for true erlang style threading: I suspect perl interpreters are to heavy to have a 100000 of them in one process, but it would be interesting to try…</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-55186251069015350392009-08-26T22:43:00.000+02:002009-08-26T22:46:57.055+02:00Prototypes: the good, the bad,and the ugly<p><i>This is a reply to chromatic's post <a href="http://www.modernperlbooks.com/mt/2009/08/the-problem-with-prototypes.html">The Problem with Prototypes</a>, but his blog didn't allow me to post it there so I post it here.</i></p>
<p>Pretty much everyone agrees that there are good (such as blocks and sometimes reference) prototypes and bad ones (scalar most of all). Few discuss the third class: the ugly glob prototype.</p>
<p>perlsub describes them as such:
<blockquote>A * allows the subroutine to accept a bareword, constant, scalar expression, typeglob, or a reference to a typeglob in that slot. The value will be available to the subroutine either as a simple scalar, or (in the latter two cases) as a reference to the typeglob.</blockquote></p>
<p>In other words, they are the same as scalar prototypes, except that they also accept globs and barewords. This is mainly used to pass filehandles, like this:</p>
<p><blockquote><code>sub foo (*) {...}<br>
<br>
foo STDIN;</p>
</code></blockquote>
but in fact it can be used to pass any bareword to function, as it leaves the interpretation of it to the function.</p>
<p>It's tempting to call this bad, but it offers some API possibilities that would otherwise not be possible, hence I would call it ugly rather than bad <i>per se</i>.</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-2203142118889153402009-02-09T14:01:00.003+02:002009-02-09T14:04:55.117+02:00Casting magic against segfaults<p><strong>The problem</strong></p>
<p>For years, there has been the <a href="http://search.cpan.org/perldoc?Sys::Mmap">Sys::Mmap</a> module, however, it has a few issues. For example, let's take this piece of code:</p>
<p><code>use Sys::Mmap;
open my $fd, '+>', 'filename';
mmap my $var, -s $fd, PROT_READ|PROT_WRITE, MAP_SHARED, $fd, 0;
$var = 'Foobar';
munmap $var;</code></p>
<p>First of all, it's simply not user-friendly. mmap takes 6 arguments in a weird order, and uses weird constants. Also munmap shouldn't be necessary: variables should dispose of themselves when they run out of scope.</p>
<p>But more importantly, this program does not do what you think it does, though the only hint of that is an <i>Invalid argument</i> exception when doing munmap. During the assignment, the link between the mapping and the variable is lost, so nothing is written to the file. Worse yet, this can even lead to a segfault in some circumstances.</p>
<p>Ouch!</p>
<p><strong>Tying things up?</strong></p>
<p>The documentation clearly says that you shouldn't do this (or anything else that changes the length of the variable), but IMHO this hole shouldn't be left open in the first place, if only because it is extremely counterintuitive (and thus a maintenance nightmare). Modules should fail more gracefully than this.</p>
<p>Sys::Mmap offers a tied interface as compensation, but this didn't work out. The tied interface indeed is safe, but it creates another problem.</p>
<p>Every time it is read, it copies the <em>whole</em> file into the variable. Every time the variable is modified, it writes the whole new value to the file, even if the change only affects a single byte.</p>
<p>Ouch!</p>
<p>Obviously, that doesn't scale at all. One user of the module reported a 10-20 times slowdown of his program after converting to ties. That's not a workable solution.</p>
<p><strong>The solution</strong></p>
<p>Perl has a powerful but rarely used feature called magic. (It's rare use by module authors is indicated by the fact that the prototypes of the magic virtual table as documented in <a href="http://perldoc.perl.org/perlguts.html#Magic-Virtual-Tables">perlguts</a> aren't even complete: they lack <code>pTHX_</code>'s). They are used by the perl core to implement magic variables such as <code>$!</code> and ties (surprise, surprise). It offers 8 hooks into different stages of handling a variable, the three most important being fetching(<code>svt_get</code>), storing(<code>svt_set</code>) and destruction(<code>svt_free</code>).</p>
<p>In my case, I didn't need <i>get</i> magic, but I did use <i>set</i> and <i>free</i> magic. Freeing the variable is not that interesting (simply unmapping the variable), but setting it is. This function is called just after every write to the variable:</p>
<p><code>static int mmap_write(pTHX_ SV* var, MAGIC* magic) {
struct mmap_info* info = (struct mmap_info*) magic->mg_ptr;
if (SvPVX(var) != info->address) {
if (ckWARN(WARN_SUBSTR))
warn("Writing directly to a to a memory mapped file is not recommended");
Copy(SvPVX(var), info->address, MIN(SvLEN(var) - 1, info->length), char);
SvPV_free(var);
reset_var(var, info);
}
return 0;
}</code></p>
<p>This function is called after every write to the variable to check if the variable is still linked to the map. If it isn't, it copies the new value into the map, frees the old value and restores the link. As copying is potentially expensive, it will issue a warning if <code>warnings</code> (or actually, <i>'substr'</i> warnings) is in effect.</p>
<p>There is no perfect solution to this problem, but getting a friendly warning is undeniably better than getting a segmentation fault or data loss.</p>
<p>Anyway, you can find Sys::Mmap::Simple <a href="http://search.cpan.org/~leont/Sys-Mmap-Simple/">here</a>. It offers more goodies, such as portability to Windows, a greatly simplified interface, and built-in thread synchronization.</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-22750151547587535882009-01-29T17:25:00.009+02:002010-01-03T00:24:49.082+02:00Elegance in minimalism<p>Some time ago, I read <a href="http://use.perl.org/~Aristotle/journal/37831">this</a> journal entry by Aristotle. I liked it and suspected it could be easily implemented in XS. It turned out to be the most elegant piece of XS I've ever written.</p>
<code>void
induce(block, var)
SV* block;
SV* var;
PROTOTYPE: &$
PPCODE:
SAVESPTR(DEFSV);
DEFSV = sv_mortalcopy(var);
while (SvOK(DEFSV)) {
PUSHMARK(SP);
call_sv(block, G_ARRAY);
SPAGAIN;
}</code>
<p>I assume most readers don't know much C, let alone the perl API or XS, so I'll explain it piece by piece.</p>
<p><code>void
induce(block, var)
SV* block;
SV* var;
PROTOTYPE: &$</code><br>
This declares the xsub. It has two parameters, both scalar values. The function has the prototype <code>&$</code>. So far little surprises.</p>
<p><code> PPCODE:</code><br>
This declares that a piece of code follows. Unlike <code>CODE</code> blocks, <code>PPCODE</code> blocks pop the arguments off the stack at the start. This turns out to be important later on.</p>
<p><code> SAVESPTR(DEFSV);
DEFSV = sv_mortalcopy(var);</code><br>
These lines localizes <code>$_</code> and initializes it to <code>var</code>.</p>
<p><code> while (SvOK(DEFSV)) {</code><br>
This line is equivalent to <code>while (defined($_))</code>.</p>
<p>Now comes the interesting part:<br>
<code> PUSHMARK(SP);
call_sv(block, G_ARRAY);
SPAGAIN;</code><br>
To understand what this block does, you have to know how perl works inside.</p>
<p>If you've read <a href="http://perldoc.perl.org/perlxs.html">perlxs</a>, you may notice this function does not push any values on the stack. Are careless reader might be mistaken and think this function doesn't return anything: they couldn't be more wrong!</p>
<p>If you've read <a href="http://perldoc.perl.org/perlcall.html">perlcall</a>, you would notice a lot more is missing. For starters, the function calls <code>SPAGAIN</code> (pretty much equivalent to saying <i>I accept the values you return to me</i>), but it doesn't do anything with them.<br>
Also, you may notive that both <code>ENTER/LEAVE</code>(needed to delocalize <code>$_</code>) and <code>SAVETMPS/FREETMPS</code> (needed to get rid of temporary values) are missing. The function that calls the xsub automatically surrounds it by an <code>ENTER/LEAVE</code> pair, so that one isn't necessary. The lack of <code>SAVETMPS/FREETMPS</code> however is not only deliberate but also essential.</p>
<p>The loop calls the block without arguments (<code>PUSHMARK</code> & <code>call_sv</code>). The xsub accept the return values on the stack and leaves them there. This sequence repeated. This way it assembles the induces values <b>on the stack</b>. <code>PPCODE</code> removing the arguments at the start prevents it from returning those as first two return values. It also adds a trailer that causes all elements that have been pushed on the stack to be recognized as return values of this function. That's why a <code>SAVETMPS/FREETMPS</code> pair would break this code: the values must live after the code returns.</p>
<p>That's the elegance of this function. It doesn't even touch it's return values, it delegates everyting to the block. All the things that are missing make that it does exactly what it should do.</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-39514187343929768462008-03-04T23:45:00.007+02:002008-06-25T12:40:22.055+02:00Where java stopped<p>Yesterday I explained my problems with garbage collection. I don't think garbage collection is bad or any, I just think it isn't being used properly. GC was invented in the late 50's for LISP, the first of high level programming languages. Lambda calculus required that the memory is managed by the system. Having freed the programmer from memory management, Lisp and is brethren enabled the development of true high level features such as dynamic typing, higher-order functions, closures, macros and continuations. These are exactly the feature that give those languages their incredible power.</p>
<p>That is what doesn't make sense in Java and derivatives: those really powerful features are missing in Java. Java is mostly lacking the features that absolutely require a GC. Guy Steele once said <i>"We were after the C++ programmers. We managed to drag a lot of them about halfway to Lisp"</i>. Considering the conservativeness of the industry it's understandable they stopped halfway (the step from C to C++ was even smaller). That kind of makes Java a middle level language; a watery compromise that fails to offer the best of both worlds.</p>
<p>Both high and low level languages have their niches, but what about the middle level languages? My intuition tells me their proper niche should be way smaller. It's hard to say what will be Java's successor, but I'm pretty certain of two things. It will not be a Java derivative and it will take the second half step, if not more.</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-56155980974313698502008-03-03T22:36:00.002+02:002008-06-25T12:41:28.478+02:00Garbage collection revisited<p>Garbage collection must be one of the most misunderstood features of programming languages. GC has existed for 50 years, yet a lot of languages have not adopted it. One of the most important commonly cited advantaged of Java and similar languages over languages such as C++ is garbage collection. Having used a number of Java applications I'd dare to say most have memory problems though. They feel extremely bloated. I've seen a few programs improve drastically when some expert started to optimize the memory usage. Most Java programs can be lean enough to be usable, but it will take a lot of effort. I imagine it is a major disillusion for a lot of Java programmers to find out they haven't found a memory panacea after all.</p>
<p>One could see all variables and their resources as a directed graph. In the most elementary programs this graph will be a tree and in such cases manual memory management is trivial. Real programs aren't this simple. Having said that, most programs are not random or unpredictable. Usually substantial pieces of the graph are trees on their own. Acyclical graphs and even most cyclical ones can be solved using reference counting and similar techniques. If you understand the resource usage pattern of your program, you can usually solve it without resorting to garbage collection. However this often requires planning and thinking ahead of time. A GC on the other hand is able to manage any graph, mostly without help from the programmer, but does not guarantee to do so efficiently. So the question <i>when do you need a GC?</i> reduces to <i>when can't I know the pattern?</i> To date, I've only come across one concrete and common example that really can not be solved semi-manually: programming languages themselves. The reason for this is obvious: it is inherent to them that you don't know ahead how they will be used.</p>
<p>It is undisputed that GCs make it easier to write programs, but this issue makes me wonder if it also is easier to write <b>good</b> programs. Java programmers are happy to think they don't have to think about memory, but it turns out they will have to think ahead (though less than C or C++) if they want decent performance. On the server side that doesn't really matter that much, but in client-side programs it does.</p>
<p>In the end, it is a matter of trade-offs. Both approaches can solve most problems. I don't believe a GC by itself gives us better programs than RAII management. Having said that, garbage collection makes business sense in a LOT of situations. Companies don't earn money by building the best program they could, they earn money by selling a finished program, good or not.</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-75608536673241107852007-09-28T14:31:00.003+02:002008-03-04T23:53:42.735+02:00Operators and types<div><p>Ruby and Python overload the <b>+</b> operator for a large number of things, the most common ones being addition of numbers, concatenation of strings, and concatenation of tuples. Very different things are represented by the same syntax. In Perl these three roles are occupied by three different operators (<b>+</b>,<b>.</b> and <b>,</b>). For that matter almost all operators for numbers are separated from operators on strings in Perl. This causes is one of the most common misconception among non-natives about Perl's typing system: it's not weakly typed. This piece of code:<br/><blockquote><p>my $foo = "1";<br>return $foo + 0;</p></blockquote><p style="text-align: left;">does not cause an implicit type conversion, nor is the last statement in any way ambiguous. The addition operator causes an <b>explicit</b> conversion of its argument. It's not an implicit one for a simple reason: it's the Perl idiom for converting any variable to a number.</p>
<p style="text-align: left;">I think this is an excellent example of the waterbed theory of complexity. To reduce the number of operators in the language Python and Ruby use runtime polymorphism on data whose behavior is already known to the programmer (not to the compiler) at compile time. I cannot think of real-world code where you don't know if your variable is a number, a string or a tuple but want to do addition/concatenation nonetheless. It is trading semantic clarity for syntactic clarity. It's a valid choice, just as Perl's choice of separating them. I think a lot of rubyists and pythonistas fail to see that their choice has its disadvantages too.</p></div>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com0tag:blogger.com,1999:blog-5583411977200154519.post-80658099155081619352007-09-17T19:40:00.002+02:002008-03-04T23:56:07.815+02:00Control structures in Perl<p>As I said in my previous entry, there is a need for education in social coding skills in Perl. Therefor I'll put my money where my mouth is ;-)</p>
<p>Basically there are four patterns for branching in Perl.
<ol>
<li>Conditional statements: <code>if(condition) { true_action }<br />else { false_action }</code></li>
<li>Statement modifiers <code>action if condition;</code></li>
<li>Logical operators: <code>condition and action</code></li>
<li>Ternary operator: <code>condition ? true_action : false_action</code></li>
</ol>
</p>
<p>How to decide which one to use? That depends on the situation of course. Only <i>conditional statements</i> and the <i>ternary operator</i> can provide an else clause. If you need one, your choices are already limited. All four put their emphasis differently. For example
<code class="block">print $line unless $line =~ /^#/;</code>
may be better than <br />
<code class="block">$line =~ /^#/ or print $line;</code>
Because the principles of prominence. This is a linguistic notion that tells us that people tend to prefer important things to be in front and details to be in the end so they can skip over the details when scanning the code. When skipping the second part the code still makes sense (even though it may not be correct anymore). In general <i>statement modifiers</i> are best used when the action is much more important than the condition.</p>
<p><i>Logical operators</i> are useful in two situations. The first one is exactly the opposite of the statement modifier: When the condition is vastly more important than the action. This usage typically uses the low precedence version. For example:
<code class="block">open my $filehandle, $filename or die "Can't open $filename: $!";</code>
is better than
<code class="block">die "Can't open $filename: $!" unless open my $filehandle, $filename;</code>
because the first one communicates the intend of the programmer (opening a file) better. Error handling is not important for understanding the big picture of the code.</p>
<p>It has another trait that is important for deciding when to use this pattern. Unlike the previous two patterns, logical operators are expressions not statements. As such they can be used in places where the former can not.
<code class="block">parse($filename || "default.filename")</code>
is significantly easier to read than
<code class="block">if(!$filename) {
$filename = "default.filename";
}
parse($filename);</code></p>
<p>Similarly
<code class="block">my $id;
if($input >= 0) {
$id = $input;
}
else {
$id = 1;
}</code>
can be simplified using the <i>ternary operator</i> to
<code class="block">my $id = $input >= 0 ? $input : 1</code>
</p>
<p>You may wonder now, when should I use old fashioned <i>conditional statements</i> then? First of all, if the action contains multiple statements and isn't suitable for putting in a function. It puts an equal emphasis on the condition and the action. It makes sense to use this pattern if you don't have a reason to do otherwise.</p>
<table summary="An overview of when to use wich pattern..." class="extra_padding">
<thead>
<tr><td colspan="6" style="font-size: larger; text-align: center">Summary</td></tr>
<tr>
<td></td>
<td>Conditional statements</td>
<td>Statement modifiers</td>
<td>Logical operators</td>
<td>Ternary operator</td>
</tr>
</thead>
<tbody>
<tr>
<td>Emphasis</td>
<td>None</td>
<td>Action</td>
<td>Condition</td>
<td>Condition</td>
</tr>
<tr>
<td>Expression</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Else clause</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Nestable/Chainable</td>
<td>Yes, very well</td>
<td>No</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Multiple statements</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
</tr>
</tbody>
</table>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com1tag:blogger.com,1999:blog-5583411977200154519.post-7210219286843140752007-05-21T01:03:00.000+02:002007-05-29T20:46:19.439+02:00When Perl is beautiful<p>Programming is hard. Writing maintainable programs is even harder. This is because code tends to be easier to write than to read. Writing easily readable code is almost as hard as reading it.</p>
<p>When writing code, one has to take two kinds of readers into consideration: computers and humans. Writing a correct program is a only matter of making your intentions clear to the computer. Writing a maintainable program however requires making it readable for your fellow humans (including yourself). For any program you're not going to throw away really soon, the latter is just as important as the former. <i>Programs must be written for people to read, and only incidentally for machines to execute.</i><sup>1</sup></p>
<p>The syntax of Perl and Python are quite different from each other (even though under the hood they are much more similar than many zealots would like to admit). This difference stems mostly from a difference in how each tries to make code more accessible for humans.</p>
<p>Python has a philosophy of readability that is minimalist. <i>There should be one—and preferably only one—obvious way to do it</i><sup style="padding-left: 0.1em">2</sup>, don't ask for an other one. Python tries to make the programmer reads exactly the same as what the compiler reads.</p>
<p>Perl on the other hand tries something very different. Perl's creator (Larry Wall) was not only educated as a computer scientist, but also as a linguist. As such, Perl behaves more like a natural language than pretty much any other programming language out there. Where some languages such as COBOL have tried to do this by abusing half of the English dictionary, Perl does so by having a 'natural' structure. Thus it tries to fit in with the way humans naturally think. This structure, with its plenitude of operators and other syntax, gives rise to the Perl motto: <i>There Is More Than One Way To Do It</i> (or TIMTOWTDI).</p>
<p>Perl has a lot more syntax than Python, but they have more or less the same functionality. This provides Perl with a lot more bandwidth than Python has to talk to the human reader. This bandwidth comes at a price: programmers who don't know how to make use of this bandwidth will emit line noise without realising it. This phenomenon has given Perl a bad name in much of the programming world.</p>
<p>When people learn to program they learn to talk to the computer, but sadly most books, courses and websites forget to teach the novice programmer how to talk to other humans (Damien Conway's <i>Perl Best Practices</i> is the welcome exception). Perl is more affected by this lack of what I call <i>social coding skills</i> than other programming languages because of its design.</p>
<p>Good Perl code is a thing of beauty and beautiful Perl code is almost always good code. For Perl to lose its bad reputation, novice programmers need to learn how to communicate on the human channel.</p>
<p class="footnote">
1. Structure and Interpretation of Computer Programs - Abelson & Sussman<br />
2. PEP 20: The Zen of Python - Tim Peters
</p>Leon Timmermanshttp://www.blogger.com/profile/03810998594297294088noreply@blogger.com