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. 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. The Java Virtual Machine is terrific in compiling long-running code during runtime to produce faster code than what a C compiler can do. 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.
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 of beer bottles that executes and prints the lyrics to ‘99 Bottles of Beer on the Wall,’ 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, pretty much as-is. 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 Unix/Linux operating systems, even with Power Shell.
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.
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.
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
This is code driving the above.
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= 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
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 a fascinating paper and 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 Nazi’s Enigma machine and the shameful way that England treated him. 5-stars, can’t recommend it more for anyone interesting in programming and mathematics.
Ruby’s syntax heavily borrows from an obscure language called Eiffel, among others. The syntax is a little different from other well-known OOP languages and is extremely flexible and simple
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.