or, how Ruby has changed the way I write Perl.

This post prodded into being by sawyer and moritz.

<@jashank> All the Ruby I've written of late has changed the way I write Perl.
<@jashank> (I'm writing a small $work project in Perl to get back up to speed, and woah...)
<@moritz> jashank: how did it change the way our write Perl? I'm curious

I think the best answer to this is, “the way I think about manipulating data—manipulating sets of data—has changed”. “Manipulating data” may seem vague and meaningless, but to me, it’s the essence of why I enjoy computing and computer science.

Much of the code I’ve written of late heavily involves manipulating data sets by mapping, reducing, or collecting—essentially, defining a transformation from one set to another. I do this multiple times daily in Mathematica, in Ruby, and in just about every shell one-liner I write.

The way mathematics approaches functions (a subset of the Cartesian product of the domain and codomain1, where all elements in the subset satisfy a mapping condition) is, to some, ivory-tower-grade abstract, but considering it concretely, it feels intuitive to go from “condition on subset of product of sets” to “transformation from one set to (a subset of) another2”.

And, surprise! You can consider that intuitive leap to be the basis of computer science as I see it.

Down at the level of Turing machines and cellular automata, state is data, and the automaton transforms one set of data—one state of the system—to another. Work your way up, and you see that searches merely manipulate a set of data to one element; sorts transform sets onto themselves; considering more complex structures as n-ary tuples takes you towards statements like “my X environment transforms user input into graphical output”.

Admittedly, at the level of complexity of a typical X11 setup, it’s impossible to say “here is the transformation function that goes from an event to a system state” with any degree of certainty3. But I feel the point still stands: data transformation is what defines computer science.


In Ruby, the idea of transforming one set—some Enumerable collection of T objects—to another4 is by a map (or a reduce or a collect). I’ll apply long chains of complex blocks to map from one thing to another.

In Perl, I’d always viewed map and grep and other such friendly structures with suspicion, because, I suppose, I’d never had much success with their use, or perhaps because I couldn’t quite grasp the meaning of them. Now, they feel just as intuitive as their Ruby counterparts in transforming data from one set to another.

If we define a function \(f:\mathbb{N}\to\mathbb{N}\,x\mapsto x^2\) and evaluated \(f({5,\cdots,10})\Rightarrow {25,36,49,64,81,100}\).

In both Ruby and Perl, it’s pretty obvious that you map on a range, but in Ruby, that the range offers up a method for mapping—

(5..10).map {|i| i**2 }
# => [25, 36, 49, 64, 81, 100]

—makes it much more obvious (to me, at least) that the transformation exists on the set. This distinction isn’t made in Perl—

map { $_ ** 2 } 5..10;
# => [25, 36, 49, 64, 81, 100]

— as map is a global name, not a method tied to the “class” of iterable things.

Manipulating by map‘ing isn’t new at all, but attaining a mastery of it through (ab)using it in Ruby makes me more comfortable with using it in Perl, and thus makes the monstrous, ugly foreaching I used to do in Perl redundant.

Is this a reflection on when (in my life and in the chronology of Perl books) I learned Perl? Probably.


The association that Ruby (and, indeed, any of the languages I’ve programmed in lately) has improved my skill is possibly just perception bias, because over the last year, yes, I’ve written lots of Ruby, but I’ve also learned lots of mathematics and computer science fundamentals that link the concrete with the abstract. I’ve learned a lot about how to think about programming in the abstract from a CS lecturer, and in the concrete from another.

But it’s possible it isn’t perception bias at all, and all the time I spent grokking Ruby has actually properly improved my Perl: I’ve spent a lot of time actually knuckling down and programming in Ruby (and C), and brought in a lot of knowledge from learning idioms in Ruby (and C and Perl).

<@moritz> I guess the thing that changed my p5 style most was reading HOP

I, too, had an influential encounter with Higher Order Perl by Mark Jason Dominus—last year, in fact—and even though I was programming mainly C and Ruby at the time, lots of the techniques and concepts it taught stuck, because they were so clear and philosophically influential. And even though I’ve not formally applied HOP techniques to Perl (yet), it’s changed the way I program at large.

(Many of the tricks HOP teaches are applicable in such a range of situations that it’s worthwhile reading it, even if you aren’t programming Perl.)


Programming isn’t just “I know how to write code”.

Programming is about understanding how to convert your thoughts into code, and if your process doesn’t evolve over time as you experience different things—whether it be reading other people’s code, or experimenting with other libraries or programming languages—you aren’t becoming a better programmer, and that’s what you should be striving for.

And I feel that, because I explore languages, libraries, techniques and projects, I’m a more confident programmer, and the code I’m writing has better style, idiom, and quality. If that’s a measure of becoming a better programmer, then I guess, yes, I’m becoming a better programmer.

Footnotes

  1. I use the terms domain, codomain and range very loosely. In mathematics, of course, it’s easy to say that the domain (or codomain or range) is ℂ or ℝ or ℚ or ℤ or ℕ or whatever, because those have very intuitive meaning… but how do you define the range of a strict, say, or bound the possible values of it? 

  2. Because, of course, it’s the Cartesian product of the domain and codomain, not the domain and range. The difference is subtle and quick to anger. 

  3. I hypothesise, probably incorrectly, that the halting problem is merely a restating of the fact that one cannot, for all states of a sufficiently complex system, concretely define a state-to-state transformation function, although I may have just converse-fallacied myself. 

  4. One thing I have longed for in Ruby is type annotations and type constraints, because I would be able to define that the range of the transformation. I want to be explicitly able to say “the value I assign into this variable is a a Rugged::Branch or whatever, and if it’s not, that’s an error”. Also nice: “this value is immutable”, but that’s probably from too much Rust.