I've got up to nine programming languages for The Weekly
Challenge (formerly the Perl Weekly
Challenge). Why am I doing this? (And is it just envy of Abigail, who
usually does 14 or more? I don't think so.)
For quite a while now I've felt that the best way to learn a
language is to have some sort of relatively simple problem that I can
use as an excuse and endpoint. Most of what I write is single-task
programs: take some input, process it in specific ways, produce
output, so even quite small programs can be useful – and graphical
interfaces are often the most complex bits of a program to get right,
but working from the command line lets me ignore those. And the Weekly
Challenges are an ongoing stream of relatively simple problems that
exercise different bits of the programmer's problem-solving toolkit.
Most of the languages I've added are ones with which I wanted to get
some level of familiarity. For example, I've been noodling around with
Rust for a few years on and off, but doing a Rust problem every week
lets me keep most of my knowledge of it in readily-accessible memory,
and encourages me gradually to delve more deeply into it. (And as a
result, I had enough ability in it to use it for all of last year's
Advent of Code.)
Similarly, Ruby is the native language for
Discourse plugins, and ends up feeling
very much like Perl taken to the next level (in fact more than Raku
does). If it weren't also noticeably slower than Perl I might switch
to it for some of my scripting needs.
Kotlin is the preferred language for Android app development (also
I've never used a JRE-based language before); Lua is widely used for
embedding in other things, most specifically for my purposes in
Tabletop Simulator, for which
I've already done quite a bit of mod building and I could use the
ability to have actual code running in there; and JavaScript is still
an ugly mess, but it's the easiest way of writing code that other
people can run on their computers without doing complicated things
like installing a language runtime.
It's a lot easier to learn the Nth language than the (N-1)st. On New
Year's Day I'd never written JavaScript beyond the most trivial; two
days later, thanks largely to David Flanagan's JavaScript: The
Definitive Guide, I'd written a dice
roller with logging, memories to
store commonly-used rolls, etc. The whole thing runs out of that
single web page. (There are no graphical resources, either: the die
symbols, arrows, etc., are all Unicode characters that modern browsers
should already be able to render without effort.)
I don't really have a similar excuse for learning Python, except that
it's very widely used and it's helpful to me to be able to read Python
code (and potentially build things on top of useful Python modules
written by other people). I'm helped in this because I can start
cleanly with Python3 rather than having to un-learn habits from
Python2. I still find it oddly irksome in the way that it mixes
functions (such as len(x)
) with methods (such as x.append(y)
),
using the leading function syntax if it's a concept that applies to
more than one sort of thing, whereas e.g. Ruby will say that lots of
things have lengths, therefore lots of things will have a .length()
method. Also, while I can live with the compulsory indentation, I do
find the lack of anything like a closing brace makes it harder to read
code if multiple loops or blocks are finishing at once – my only clue
to that is the number of levels of whitespace.
I have even less excuse for the other languages. There is basically no
utilitarian point to writing programs in PostScript; it's very
primitive (lacking e.g. variable-length arrays), it's hard to
interface to other things, and it's quite slow. On the other hand it's
the most readily available stack-based language (I already have
GhostScript installed on many machines as part of a PostScript/PDF
rendering chain), and thinking in terms of a stack rather than simply
stuffing everything into variables forces me into a useful mental
flexibility.
Indeed, I've noticed since I started this that Perl, which has really
good implementations of regular expressions and hashes (associative
arrays), tends to push you into using combinations of those two
things. Rust in particular has a much richer array of specialised data
structures, and there's a bit more friction using its hashes and
regexps, so one starts to think about which particular representation
would do best rather than merely using the standard way to write
stuff.
So that just leaves Perl and Raku, the "official" languages of the
Challenge. I've got twenty years' experience of doing stuff in Perl,
and I'm not throwing that away; it's still my default language for
small useful programs that I want running right now. I'm still not
really sure whom or what Raku is meant to be for, now that it's no
longer the next major version of Perl: it has a bunch of flashy
features that Perl doesn't, but mostly so do Python and Rust, and
while it's getting faster it's still very slow.
What I find that I forget, transferring from one language to another,
is the little syntactic details; this is the language in which I
have to write for (let pc of p) {
rather than for (pc in p)
or
for j,pc in ipairs(p) do
or for @pc -> $p {
or p.each do |pc|
.
That's also what I really want a reference book to tell me about: not
"this is what a condition test is" but "this is what a condition test
looks like in this language". Which is why JavaScript: The Definitive
Guide is pretty much the best book for me to learn the language: my
questions tend to be of the form "I know there's a way of getting a
slice of a string, so show me all the string methods and what they do"
rather than "give me ten pages of waffle about strings which includes
examples of some of the string methods". Similarly, the Lua Reference
Manual, which mostly lists the details of the various built-in
operators and functions, is much more useful to me than Programming
in Lua, which straddles what for me are two distinct tasks, "learn to
program" and "learn Lua".
When I start a Weekly Challenge problem, I first think about it in a
fairly abstracted way: for example, this will need a list of prime
numbers, but the solution is bounded by list size rather than maximum
prime, so I need some way of going from the ordinal value to something
like the actual value of the prime. Or that will most neatly be done
by a fraction class with methods for setting values in and out, and
for getting a parent fraction. It's only after that that I settle down
to write code, and the solution takes on the flavour of the particular
language I'm using; to encourage my technical polyglottism, I'm now
randomly selecting the order of languages in which I tackle each
week's problems, because having written one solution I tend to
translate the code rather than go back to basics.
From memory, languages I've used before this: on the VIC-20, CBM
Basic; on the BBC Micro, BBC Basic and Acornsoft C, and a bit of 6502
assembly; IBM Basic, briefly; Fast Basic and GfA Basic on the Atari ST
(both of these abandoning line numbers because you now had the idea of
loading a program from a file as part of the process of running it
rather than these being separate actions, and GfA could even compile
to machine code); Rexx under DOS, and AWK under DOS and Linux. I don't
count DOS batch files or bash scripting; I can manage the very basics,
but for anything more than a trivial program I move to something else
simply to get away from any possibility of shell-escaping problems.
But mostly it was Perl for a very long time, and now I have more
options.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.