4 ms·
I have been using Perl (5) for new projects until very recently (and, realistically, I might still use it in the future). I also did some contracting until very
by jstanley 4y ago
I have been using Perl (5) for new projects until very recently (and, realistically, I might still use it in the future). I also did some contracting until very recently for a company whose product makes extensive use of Perl. I've been writing Perl professionally for over 10 years.
The backend of my network programming challenge[0] is all Perl daemons, including the web API, the solution checker, leaderboard calculation, and new problem announcement mailing. (The frontend is Next.js, but it's not using any server-side JavaScript, it's delivered as a static site).
Perl is good because it is very quick to write. Common idioms are very terse, first-class support for regexes is a superpower, and the TIMTOWTDI philosophy ("there is more than one way to do it" - polar opposite to Python) means you can often find a quick and succinct way to make most small code changes you want to make.
I am personally looking to move away from Perl for new projects for the following reasons:
1. Perl doesn't have sensible support for multi-threading.
There's "use threads", which is quite heavyweight because (as I understand it) every time you make a new thread with "use threads" it creates a memcpy() of the entire interpreter.
There's "use forks", which is the same as "use threads" except it uses fork() so that the "copy" is less expensive (because Linux gives us copy-on-write). "use forks" is still bad because inter-thread communication still involves serialising your data and passing it over a pipe, and you don't necessarily notice where you're doing it.
Then there's Coro[1], which is actually very very good, for what it is. Coro allows you to write code in a straight-line synchronous style, but allows you to cede control to other threads when you need to wait for a result to become available. Coro calls itself "the only read threads in Perl", but it's still not real threads in Perl because it still doesn't let you take advantage of more than 1 CPU. In my experience Coro also interacts poorly with XS (i.e. native code) modules that aren't reentrant, and it's difficult to predict when you might be using such a module, and sometimes your Perl scripts will segfault or leak memory through no obvious fault of your own. But Coro is a really neat hack.
If you actually want to make use of multiple CPUs, the best option (IMO) is to fork() manually and keep inter-process communication to a minimum.
2. Further than multi-threading, Perl doesn't even have sensible support for async/await style concurrency.
The closest thing to async/await style concurrency is AnyEvent[2]. AnyEvent is quite good, and I think is the best way to write asynchronous code in Perl. But it still doesn't hold a candle to basically any modern programming language, because you still have the "callback hell" style of passing closures as an argument to anything that has to be asynchronous. This is extremely annoying and results in enormous, complicated, and error-prone refactors if you ever have to change a component deep in your stack from synchronous to asynchronous. For example, if you are moving away from a hash table "database" to an actual RDBMS, and you don't want your database queries blocking your entire application, this is extremely painful, because everything that lives higher up the stack needs to be rewritten in "callback hell" style. See "What color is your function?" for more on this.[3]
3. Lots of things that should be caught statically don't actually cause problems until runtime.
This is mainly because Perl is dynamically typed and isn't compiled, but it is annoying, and avoidable in other languages.
What language am I moving to? I don't know yet. Probably Go. I don't like how opinionated Go is about a lot of things that Perl doesn't give a shit about, but it is at least quite small.
I don't like Rust because it seems overly bloated (the recommended way to parse command-line arguments - "clap" - involves downloading 140 megabytes of dependencies off crates.io, which just seems unreasonable), although the borrow checker is a very interesting idea.
I'm also interested in Zig, but I think the Zig community is possibly too small at the moment, and not being fully memory-safe seems overly risky. But I haven't written enough Zig yet to know whether or not I like it.
[0] https://protohackers.com/ https://protohackers.com/
[1] https://metacpan.org/pod/Coro https://metacpan.org/pod/Coro
[2] https://metacpan.org/pod/AnyEvent https://metacpan.org/pod/AnyEvent
[3] https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...
- return_to_monke 4y ago> I don't like Rust because it seems overly bloated (the recommended way to parse command-line arguments - "clap" - involves downloading 400 megabytes of dependencies off crates.io, which just seems unreasonable), although the borrow checker is a very interesting idea. Where do you get that from? https://lib.rs/crates/clap https://lib.rs/crates/clap states that the code itself is 1MB, and the maximal amount of dependency code is 7mb, with all optional features enabled.
- jstanley 4y ago`du -h` of a project that did nothing but use clap was 380 megabytes or there abouts. EDIT: A blank "cargo new" project plus a clap dependency weighs 143 megabytes, not 400. Maybe the 400 megabyte project had another dependency as well, I can't remember. I've edited the comment to say 140 instead of 400. $ cargo build Updating crates.io index Downloaded clap v3.2.23 Downloaded textwrap v0.16.0 Downloaded proc-macro2 v1.0.47 Downloaded clap_lex v0.2.4 Downloaded hashbrown v0.12.3 Downloaded clap_derive v3.2.18 Downloaded once_cell v1.16.0 Downloaded libc v0.2.137 Downloaded os_str_bytes v6.3.1 Downloaded unicode-ident v1.0.5 Downloaded syn v1.0.103 Downloaded 11 crates (1.4 MB) in 3.71s Compiling proc-macro2 v1.0.47 Compiling version_check v0.9.4 Compiling unicode-ident v1.0.5 Compiling quote v1.0.21 Compiling syn v1.0.103 Compiling autocfg v1.1.0 Compiling libc v0.2.137 Compiling os_str_bytes v6.3.1 Compiling heck v0.4.0 Compiling hashbrown v0.12.3 Compiling textwrap v0.16.0 Compiling strsim v0.10.0 Compiling termcolor v1.1.3 Compiling once_cell v1.16.0 Compiling bitflags v1.3.2 Compiling clap_lex v0.2.4 Compiling proc-macro-error-attr v1.0.4 Compiling proc-macro-error v1.0.4 Compiling indexmap v1.9.1 Compiling atty v0.2.14 Compiling clap_derive v3.2.18 Compiling clap v3.2.23 Compiling clapdemo v0.1.0 (/home/jes/clapdemo) Finished dev [unoptimized + debuginfo] target(s) in 36.61s $ du -h | tail -n1 143M
- kupfer 4y agoDoing it with 'clap = "4.0"' gives me 46MB. Still surprisingly large.