Post

Why I like Ruby

For some reason, Ruby is often maligned, usually by those that have little understanding of the language. They see it as object-oriented and think it is like Java, or whatever. The situation is similar to JavaScript and how many misunderstand its prototype object system, so they approach it like Java and come away disappointed and very confused.

Performance in Ruby can be an issue, and much work is ongoing in that area. It is in the same performance area as Python and other dynamic languages. Programming, thus language design, is all about trade-offs. The ability to easily change code at runtime adds power, but that has performance penalties.

Language wars are pointless. I understand that decisions made can annoy, and some might actually like those weird decisions. Python is full of weirdness, making the language less powerful and more verbose, and for what? I would love to write a “Why I hate Python” article, but that serves no useful purpose other than to allow myself to nerd rage for a while. That is not very productive. Python is useful because of some first-rate third-party libraries. These areas include mathematics, and “AI”. Scientific computing is a strong point of Python because of these libraries. There are others like the very well done SQLAlchemy. These are more or less the only compelling things about Python, which is less about the language and more about the ecosystem. Seriously, there is some fantastic work being done in Python. The language is still weird. Useful, but weird. That is weird in and of itself.

It is not great that the Ruby ecosystem does not yet have third-party libraries in these areas on par with Python’s scientific libraries. Many of the features of Ruby would aid greatly to make programming easier and more flexible for these types of programs. I have been toying with the idea of building a solid linear algebra library in Ruby that performs well, at least roughly equivalent to Python’s linear algebra libraries. I’ve got nothing but time, and I like to keep my math skills up.

To my shame, my linear algebra skills were never as good as my understanding of calculus or discrete mathematics. Cold weather is approaching, so that might be a fun way to pass a miserable winter and make it less pointless. If I get the basics working well, I don’t have the energy or a consistently clear mind to be running a project. Otherwise, I wouldn’t be retired. It might be a fun thing to do and would be a useful addition to my private libraries and maybe throw it up somewhere and see what happens.

Oddly, talking about programming languages elicits lots of pointless flame wars and weird arguments that don’t make sense. Such as ‘other languages are flawed, so my favorite language is equal.’ Okay, that is the default PHP argument since most other languages not named PHP are designed reasonably.

Programming is mathematics; mathematics is logic; therefore, programming is logic. It is a professional and academic endeavor, yet those attributes are often not valued very highly. That is a rant for another day.

This is not a ‘my language is better than yours’ post, especially since I don’t have a language. If I use it, I like it, and it is useful for whatever project I am working on. I stopped using languages I don’t like. Life is too short. This is why I can’t tell you much of anything about Python 3 or anything after Java 8. If I need a new language for a new project or augment an existing one, I will look around for something I can enjoy. That is what brought me to Kotlin and Elixir. So, I am not a “Ruby programmer,” I am simply a programmer. The best advice to the budding programmer that anyone can give is to learn as many languages as you can, in as many categories as you can. At least to the point that you could write something nontrivial in it. Never stop learning new languages. Even if you won’t use them, you will benefit from the ideas that they present.

The exception is PHP, which causes brain damage.

Many of the things that Ruby is great at are IO bound anyway, so performance isn’t as big of an issue. Just don’t use Ruby for important CPU bound projects. It has a simple foreign function interface(FFI), so writing C libraries or just using existing C libraries is fairly trivial to call from Ruby, which can help if performance is a problem in parts of your program. The Java Virtual Machine is terrific in compiling long-running code during runtime to produce faster code than what a C compiler can create. A JVM port of Ruby exists called JRuby, which helps a bit. I would bet that something like Kotlin or Clojure is probably still faster than JRuby.

Raw speed is rarely an issue in the majority of problem domains, and obsessing about it is a waste of time. Ruby is fast enough for most problem domains.

To understand Ruby, it is good to know that it borrowed concepts from many languages and paradigms. They were brought in with few, if any, changes, and made it all work seamlessly. It is remarkable how it can combine various paradigms into coherent syntax and semantics. It was initially developed in Japan by Yukihiro Matsumoto, known as “Matz.”

Ruby was initially made public in 1995. The core tenant is focusing on “programmer happiness.” It appeals to the programmer’s sense of aesthetics. It also tries to conform to the Principle of Least Surprise. Of course, while it is well-designed, it can surprise, especially before the object system is fully understood. I can say it almost always makes me very happy to use it. Most of the time that it surprises me, it is a good thing. “Why don’t other languages do it like this!” is something I thought a lot while learning it.

Its string manipulation abilities come from Perl and are about on par in its flexibility. I am not sure if it is a good or bad thing, but the bizarre things that you can do in Perl, such as create ASCII art as code. That can’t be done in Ruby, I least I have never seen it, so it cleaned up the considerable mess that is Perl.

Ruby also brought over Unix integration from Perl. A lot of the built-in functionality in Ruby objects exists to support integration with the underlying operating system. Writing scripts for Unix/Linux is a joy in Ruby. It is not as great on Windows, but Windows is not nearly as scriptable as the Unix/Linux operating systems, even with PowerShell.

Microsoft’s awkwardly named ‘Windows Subsystem for Linux’ makes Ruby more useful in Windows, as does the better Windows installers that have been around since Ruby 2.4. Using Ruby in Windows used to be such a pain. It was not worth the hassles but is pretty simple now.

The syntax is inspired by Eiffel, it does look slightly different compared to C or Java, but Ruby more flexible and easy to read. Eiffel is an object-oriented declarative language. Ruby is an object-oriented procedural language, so it will feel more familiar.

Its object-oriented system is mostly lifted from Smalltalk. A language that was designed by the guy that coined the term object-oriented.

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.

Alan Kay

He has expressed dismay that many allegedly OOP languages bit hard on everything listed except messaging and has said the big idea is message passing. Ruby OOP is indeed all about message passing. It is not at all like the weird cultish Java-style OO that is full of magical incantations. It is not like C++ or Python. All are languages that missed the point.

Ruby objects also hide state - all class and object-level variables are private. Its powerful reflection capabilities make that easy to bypass. So much so that it is possible to trivially test an object’s private methods in total isolation from its public methods if one chooses to do such a thing.

Supposedly, testing private methods in isolation is a bad thing to do. I heard it from Java cult members so take that with a grain of salt.

Calling a private method “outside” of the object
1
2
3
4
5
6
7
8
9
10
class Test
  attr_accessor :data
  def initialize data={}
    @data = data
  end
  private
    def do_something
       puts @data.size
    end
end

This is code driving the above.

1
2
3
test= Test.new
test.data = [1,2,3]
puts data.send :do_something

This will print 3.

The private keyword applies to all methods below it unless public or protected keyword appears after it. There is no need to individually mark method visibility. The send method belongs to Object and will execute what you send to it.:do_something is the name of the method we wish to call in the form of a symbol, which will be covered later.

While we do invoke the private method from outside the object, all the work done to accomplish that is inside the object. It is a bit of smoke and mirrors and results in a simple reflection method.

attr_accessor is a method that will automatically create accessors and mutators for the object based on the name(s) given to it. In this case the methods data and data= are created during runtime.

The Ruby parser allows you to write the setter method with the ‘=’ separated from the name, like in the example above. It is important to remember that the method name is data=, even if it is written as data =.

Ruby has both powerful list and meta-programming support. Both features are heavily influenced by Lisp, among others. Ruby’s meta-programming support is well done and allows for a lot of powerful and advanced features. Not as powerful as Lisp, but the clean syntax over the headache-inducing abstract-syntax-tree-as-its-syntax style of Lisp is a win in my book.

That is not a slam on Lisp, which has many different implementations of the Lambda calculus: the first mathematical construct to prove what can and can not be computed. Lisp isn’t a language but an entire family of them.

The lambda calculus was developed by an incredibly smart and influential mathematician named Alonzo Church at Princeton. It was developed to solve the decision problem. The decision problem was an important open question and one of the math challenges for that century posed by German mathematician David Hilbert in the 1920s.

Several of Church’s doctoral students did foundational work in what would later be called computer science, such as Stephen Kleene. A more famous student of his is English mathematician Alan Turing, who had at the same time had independently solved the decision problem. He did it using an abstract construct called Turing Machines.

Turing’s work was done as a student and normally would have more than justified a doctorate but for the fact that Alonzo Church’s paper that solved the problem was published first. Yikes!

Turing machines describe a small number of actions, such as read, write, move left, move right, halt. No matter how complicated computers and programs get, they boil down to these simple concepts.

Turing machines were overall more influential on the field than lambda calculus, which are equivalent to each other since they solved the same problem.

Alan Turing moved to the US to study at Princeton under Church. He finally earned his doctorate there with Church, as the chair of his doctoral committee, on work not directly related to Turing Machines.

The paper describing the Turing Machine is fascinating and his life is a sad story. That book is pretty easy to follow. The mathematics in Turing’s paper is very complex. I didn’t have the mathematical background to follow all of it, so I read this book. A minor in mathematics just doesn’t get it done. It has a lot of interesting mathematical and historical context for Alan Turing’s paper. It also has a bit of a biography, including his work on decrypting the Nazis’ Enigma machine and the shameful way that England treated him.

I don’t typically post things in list form, but hopefully, it will keep me from rambling too much.

1. Simple, fun, and hides a lot of complexity

The #1 reason I like Ruby is it is so easy to learn mainly because of its simple and coherent syntax. Despite that, the language supports many advanced features and has done so since the mid-to-late-90’s in many cases.

Like many other programmers, I took to it so easily because it is clean and logical. It is by far the quickest that I learned a language where I was comfortable and rarely needed to look up docs. It took about a week to get comfortable, and after two or three weeks, I had a solid grasp of it.

I struggled with the inspired insanity that is Perl.

I was annoyed from day one with Python, and that annoyance never went away but have no such issues with Ruby.

It is a much better Perl. It is Python done right.

The ability to hide great complexity and make it look simple is its biggest selling point. There is a lot of power and flexibility in that. Indeed, there are often many ways to do something, and most of those ways are equally good. You might notice in my code samples that I often omit parenthesis in method arguments.

That I can do that makes me happy. It lights up my brain.

Unless there is a need for it because there is ambiguity, parenthesis is just redundant noise. Just like end-of-line delimiters, those are optional also because it is easy enough to tell if the line continues and the parser is smart enough to know.

**_I didn’t realize how friggen long this post was when I first wrote it. Since I have to redo the syntax highlighting, I will split it up into smaller posts. To be continued here.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.

© Vilanye. Some rights reserved.