💾 Archived View for the-brannons.com › perl-praise captured on 2024-12-17 at 09:48:23. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
Perl 5 was the first programming language I really mastered. There are lots of things to love about it in 2024.
Perl 5 is stable. I have Perl code, some of which I wrote, that is nearly old enough to run for the US House of Representatives. Yet it still runs on a recent Perl 5, with few or no changes. I was writing Python professionally during the 2 to 3 transition, and I'm still butthurt about how terribly that transition went. And I suspect that lots of code running on Python 3 has subtle little bugs hiding and lying in wait for the unwary, especially bugs related to strings and the change to the division operator.
Yeah, Perl has it; another popular scripting language from the 90s doesn't. Perl has dynamic scope, too, if you need it. It's the "have your cake and eat it too" language.
POD and perldoc got this very, very right. POD is even typically rendered as manpages at install time, so I can do things like `man JSON::XS` to see the documentation for the `JSON::XS` module as a manpage. The `perldoc` tool is also excellent.
Other languages have similar things now. Python has `pydoc`, and here is part of what I see when I run `pydoc json`:
Help on package json: NAME json MODULE REFERENCE https://docs.python.org/3.12/library/json.html The following documentation is automatically generated from the Python source files. It may be incomplete, incorrect or include features that are considered implementation detail and may vary between Python implementations. When in doubt, consult the module reference at the location listed above.
Let's compare that with the first few lines of output from `perldoc JSON::XS`, shall we?
NAME JSON::XS - JSON serialising/deserialising, done correctly and fast JSON::XS - 正しくて高速な JSON シリアライザ/デシリアライザ (http://fleur.hio.jp/perldoc/mix/lib/JSON/XS.html) SYNOPSIS use JSON::XS; # exported functions, they croak on error # and expect/generate UTF-8 $utf8_encoded_json_text = encode_json $perl_hash_or_arrayref; $perl_hash_or_arrayref = decode_json $utf8_encoded_json_text; # OO-interface $coder = JSON::XS->new->ascii->pretty->allow_nonref; $pretty_printed_unencoded = $coder->encode ($perl_scalar); $perl_scalar = $coder->decode ($unicode_json_text);
So the `pydoc` documentation starts off by telling me that it was automatically generated and might be inaccurate, while the Perl documentation shows me a clear example of how to use the thing. That's because documentation was strongly emphasized in the Perl community. Somewhere long ago, I read: "You can't have a good module without good documentation in POD (plain old documentation) format." Perl hackers also appeared to be a bunch who prided themselves on their literacy, while also having a well-developed sense of humor.
Perl also had a strong culture of testing. Among Larry Wall's inventions is TAP, the Test-Anything Protocol, which shows up in other languages than just Perl.
That's because Perl uses reference counting and a pay-as-you-go model for freeing memory. When an object's reference count reaches 0, it is immediately freed. Instead of paying an amortized cost over time, or dealing with a "stop the world to take out the trash" situation every so often, you pay the whole penalty for freeing an object and its object graph at the time you delete its last reference. Some GC nerds seem to think that this isn't real garbage collection. But the advantage is that it can give you a really strong intuition about your program's memory performance characteristics as you are writing and testing code. At least, that's what I noticed when I was writing Perl regularly twenty-ish years ago.
It turns out that the Perl interpreter even starts up faster. Who doesn't love a synthetic benchmark? Here's mine. "How fast can various popular scripting languages start, print "Hello world!", and terminate? Here's the code to answer that question:
#!/bin/bash # Stupid synthetic benchmark comparing scripting languages by the time it takes to print "hello world." # WTFPL set -e set -o nounset # We actually give 0 fucks about what gets printed to stdout; may as well send it to /dev/null: exec > /dev/null run_lua() { lua5.3 -e 'print("Hello, world!\n")' } run_perl() { perl -e 'print("Hello, world!\n")' } run_ruby() { ruby -e 'print("Hello, world!\n")' } run_python() { python -c 'print("Hello, world!")' } # Time a bash function. tbf() { func="$1" name="$2" iterations="$3" start_time="${EPOCHREALTIME}" for i in $(seq 1 "$iterations") ; do $func done end_time="${EPOCHREALTIME}" delta="$(printf 'res=1000*(%s-%s)\nscale=0\nprint(res/1)\n' "$end_time" "$start_time" |bc)" printf '%d iterations of %s took %d milliseconds.\n' "$iterations" "$name" "$delta" 1>&2 } case "$1" in lua|perl|python|ruby) tbf "run_$1" "$1" 100 ;; the_works) for i in lua perl python ruby ; do "$0" "$i" done ;; *) printf "Go home, you're drunk!\\n" 1>&2 exit 1 ;; esac
And here are the results:
Script started on 2024-12-11 05:46:15-08:00 [TERM="screen.linux" TTY="/dev/pts/6" COLUMNS="80" LINES="25"] chris@beast:/home/chris $ ~/bench.sh the_works 100 iterations of lua took 276 milliseconds. 100 iterations of perl took 421 milliseconds. 100 iterations of python took 3663 milliseconds. 100 iterations of ruby took 12107 milliseconds. chris@beast:/home/chris $ exit Script done on 2024-12-11 05:46:42-08:00 [COMMAND_EXIT_CODE="0"]
Take that for what you will.
I love Perl's `die` function. Love it so much that I roll my own if there's not an equivalent baked into whatever language I'm using at the moment.
I think I've just about convinced myself that I should get back into Perl. Maybe I've convinced you, too.