Friday, April 9, 2010

Enlightening perl's documentation (you too can help!)

(This entry was first posted here)

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.

For example, a quick ack through the documentation showed about 250 cases of open used with a glob as its first argument (e.g. open FOO;), 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.

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.

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?

But there's much more to improve in the documentations.

  1. Why does perltrap list traps for perl4, awk and sed but not for modern languages like python, php or ruby?
  2. Why doesn't perlipc use IO::* instead of low level functions?
  3. Why isn't perlmodinstall Build.PL aware?

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.

The good part of the story? You can help. This work can be done not only incrementally, but also distributed.

Edited to add: So how to get started? perlrepository has detailed information how to submit patches. The easiest way is to fork perl at github and when you're done mail the perl-5-porters about it.

Sunday, March 28, 2010

DynaLoader considered harmfulharmful

(This entry was first posted here)

DynaLoader 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.

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.

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:

Can't locate object method "undefined_method" via package "Foo"

But this rather cryptic error:

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 .)

No way a perl novice will understand what's going on there!

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 one bit of data!

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: XSLoader. It's not perfect, but it will cover 98% of all XS user's needs with significantly less disadvantages.

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.

* I might even do that myself.

Wednesday, March 24, 2010

Threads in Perl, Erlang style

Adam Kennedy's recent post on threads in Padre 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 I want perl with these threads, so I started implementing it. And thus threads::lite was born.

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.

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 Storable can be send, including coderefs.

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.

I've started building some high level abstractions on top of it, most notably a implementation of a parallel map and grep. I'd like to do a map-reduce, but that's for a later stage.

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…