loading...
Runtime Revolution

Transposing Lisp into Ruby

brunjact profile image B Jacquet Originally published at revs.runtime-revolution.com on ・5 min read

Photo by rawpixel.com on Unsplash.

When you work for a long time on the same technology you can become alienated from the world around you. For the past eight years I must have spent 90% of my time in the land of lisp (pun intended) developing Windows desktop applications. Web development, mobile development, cloud infrastructure, machine learning, data analysis… These were topics I loved reading about in newsletters but never got around to working on. None of it was in my company’s road-map, thus I decided to leave my previous company in pursuit of something different.

And so I landed in Runtime Revolution land where we tackle web and mobile development.

Having to learn Ruby (fast) was a must! So, whilst following tutorials I was also taking notes on how things are done in Ruby. I’ll share some of those today.

Stripe taken from Why’s (Poignant) Guide to Ruby.

Similarities

It wasn’t by chance that I switched from Lisp to Ruby. They have a lot in common.

On my previous company I got into the habit of trying out things in REPL (Lisp’s interactive console), see if it works on its own, and only then would I move it into the source code and test it with the rest of the project. Now at Runtime I can continue developing in the exact same way as both Ruby and Rails (not to mention JavaScript) provide interactive consoles, $ irb and $ rails console respectively.

In both Lisp and Ruby, function arguments are passed by value. Which means that functions are non-destructive, thus minimising side effects. And that’s a good thing! Also, in both languages, variable scope is confined to the block scope where they are created and their descendants. And in the case of Ruby that can either be global, class, instance, or local.

List Processing

One does list/array/vector processing on any language. Both Lisp and Ruby have a sufficiently high level abstraction which makes list processing a breeze. Best of which is that lists can contain different types of objects. Lisp’s standard has a great collection of list operators available. Looking back, my most used operators must have been: mapcar, remove-if , and loop.

mapcar applies a function to each element of the list and returns a new list. I used this a lot.

This may or may not be something often done in Ruby, but it’s still part of how I approach problems. Ruby’s mapcar equivalent is map.

Filtering out elements from a list is also a common task. In Lisp we can do this with remove-if.

In Ruby there is reject.

Notice how both languages accept function reference. This is a great feature which saves in code typing and eases maintenance. If instead you want the code to express the selection of elements then one can use remove-if-not and keep_if respectively.

Another common scenario is to iterate over two lists in parallel. Lisp has this big gun called loop.

I don’t think Ruby has something the likes of this but one can be creative and combine zip with map.

This example makes Ruby the one with lots of irritating, silly parentheses {and brackets |and pipes|}. 😆

Recursion

One method to solve problems is to break them down into smaller and easier ones. Divide and conquer. Recursion uses this methodology and is used a lot in Functional Programming, and in Lisp. I knew that Python has limitations on the amount of times a function can call itself. (Functional Programming in Python, Packt) It’s a big number, but reachable. I needed to know if Ruby also has this constraint before I start disseminating recursion everywhere.

Turns out Ruby also has a memory constraint. On my home computer I cannot calculate the factorial of a number bigger than 10912. This was my test function.

One can increase the stack size or activate Tail Call Optimisation. I haven’t tried this. Unless your code is meant to be run on the same machine it was written on, relying on installation configuration hinders code distribution. Thus sometimes it’s best to go with what the language gives us by default and, in this case, use an iterative solution instead.

Macros

Although macros were used a lot they were not an everyday task. I must have made three macros and only one has endured the test of time. So as you can see, my expertise on this matter may not amount to much. Nevertheless I won’t leave you disappointed.

Eric Kidd had a really good take on this subject comparing Lisp to Ruby on Lambdas and Macros, Why Ruby is an acceptable LISP.

Error Recovery

Lisp has a great error recovery system. When things go wrong the process execution is interrupted and at that moment it’s possible to inspect the process stack. That means all function calls and all variables that lead to that point. Not only is this a great debugger, as it also allows the developer to correct the bug and resume the process execution from that point on.

So far I haven’t found anything like this for Ruby. (Maybe I’ll build it one day. :-)

The End

And to conclude, the most overlooked feature for a lisper wanting to be a rubyist is the end keyword. Until I setup my editor to do code-completion I was constantly forgetting the trailing steps of ends. So get yourself an editor with all the bells and whistles, save yourself some typing, and be nice.

Stripe taken from Why’s (Poignant) Guide to Ruby.

Coda

Although an objected-oriented language I really enjoy the fact that one doesn’t have to create instances to invoke class methods. This was a big turn off, not to mention cumbersome, on my previous C# jobs.

These days I don’t do much console driven development but I don’t miss it that much. Mostly because with Rails code changes are available with a page refresh. The language itself was built in a way to make it easier for the programmer. You can think of the English word for what you want to do and odds are there is a function with that name!

Another habit I picked up is to spend more time on Stack Overflow. Not that it’s a bad thing. I guess lispers don’t have so many questions on how to do things. Either that or there aren’t many lispers around to answer. I think Ruby is better off on this chapter.

From sunny Lisbon to the world, at Runtime Revolution we transform ideas into scalable products. Do you have a project to move forward or a product you’d like to launch? We would love to help you!

Runtime Revolution


Posted on by:

brunjact profile

B Jacquet

@brunjact

Former Lisp engineer turned Ruby engineer who is trying to understand Rails, JavaScript, Life, the Universe, and Everything. I work at Runtime Revolution, which is based in Lisbon, Portugal.

Discussion

pic
Editor guide