I came to Ruby from a different direction, working on Puppet/Chef and VMware/NSX, but I came to a similar conclusion. I'd always assumed the reason I liked it so much was because I wasn't a programmer. The language operates generally as expected (to someone without a real coding background) as well as being so much more flexible and powerful than the other options available.
Since then I've done a little rails work, learned enough Python to be moderately useful, and stumbled through a few other languages. I still try to be impartial, and to use the best tool for the job, but it's always a joy when I find a chance to use Ruby again.
Wow, what horrible persons use 3 spaces indentation in C?
As someone who started writing in Ruby with tabs indentation, I switched over to 2 spaces as most other projects were using it.
After a short period of getting accustomed to it, I can't imagine doing it any other way (but only in Ruby!). It just feels more natural in Ruby than any other indentation style.
I'm not sure why, maybe the language keywords are different enough and the length of line is just so that 2 spaces hit a sweet spot?
There's only one language more elegantly designed than Ruby and that's Clojure. Ruby for scripting and Clojure[script] for everything else is as good as it gets.
Wish all languages comes with a fmt tool that will end all stylistic guide debates.
We use linters at work, but even setting linter rules will cause a lot of arguments.
Well, you don't need one for Python.
You do when your lines get too long. :)
I had to learn Ruby when I got a job as a full stack dev. Before then I mostly used Python and Java. To date I have not found a language that I love more than Ruby. It's a delight to use. I truely enjoy coding in Ruby, whereas I'm usually some flavor of neutral with most other languages (except PHP... blah). Perhaps there are some people that are on the same wavelength as Matz. One thing I found interesting is that when surveying whitespace of Github repos, 100% of Ruby repos surveyed had 2 spaces for indentation. Looking down that list, I wonder why some languages have more conformity of indentation style (other than frameworks helping enforce styles). Perhaps certain languages attract certain types of developers or help foster a particular culture?
In general, I think Ruby does a good job of being unsurprising. I like that most things work as I'd expect, with the syntax I'd expect. But then you've got weird things like `File.read("|ls")` that are entirely surprising.
Compared to what, though? I really like how everything is a method in Ruby as compared to, say, Python where it seems completely random if something is or isn't -- for example, I have to constantly remember that to get a length of an array in Python I have to do len(x) rather than x.len().
Although I like what Rust and Nim are doing with making the method/function distinction irrelevant -- there, x.f() is just syntactic sugar for f(x) -- so you can use whichever you prefer.
Small note about Rust; you're not 100% right. For example, method syntax will do auto ref/deref on the reciever, for most methods, it'd be f(&x), not f(x), though if f took self by value, it would be!
It is true that you can invoke it either way if it's a method, but you cannot if it's a function, as well.
Compared to most everything (PHP is probably worse, and there might some that I don't know). I'm not saying it's surprising because it's different, rather it's surprising because it doesn't seem to be very internally consistent. Lots of complicated rules instead of a few simple ones.
As I pointed out in another comment, the way lookup is handled for instance is really a clusterfuck (http://norswap.com/ruby-lookups-scopes/)
Other OO languages like Java or Smalltalk (the more direct Ruby inspiration) do much better in this regard of having simple rules for lookup (and other things).
>I have to constantly remember that to get a length of an array in Python I have to do len(x) rather than x.len()
On the other hand, in Python lists, tuples and arrays are fundamental data types and thus len() is defined as a fundamental built-in function. I think it makes sense.
What i didn't like was when map() and reduce() were moved away from the basic functions.
> On the other hand, in Python lists, tuples and arrays are fundamental data types and thus len() is defined as a fundamental built-in function. I think it makes sense.
But len() is only a fundamental built-in function for fundamental data types and you can implement it on any class by implementing the method __len__(self).
For those it doesn't make sense any longer to be able to do len(x).
I'm afraid you're right...
Matz has also maintained that it's the principle of his least surprise. You can't be not-surprising to every single possible person.
Matz also mentioned Ruby is no longer his project.
>In many ways, Ruby is one of the worst offenders.
Can you explain why? I'm curious.
The powerful metaprogramming features get used to make dsls and also make it harder to know what methods are available or built in or what gem added them in. I love the language and it's a joy to program in but it's not without fault. Also, there are many ways to do something so you need to know multiple ways. I don't find it particularly hard to program in once you get used to a few paradigms though.
I actually have a whole series of posts up: http://norswap.com/ruby-dark-corners/
The three topics (module linearization, scope lookups and method parameters) are constant source of wtfs as soon as you go beyond something basic.
What is your standard for non-offender? Certainly not C++ or Common Lisp. Scheme, Smalltalk, Go?
C++ is probably an offender but for other reasons. My experience is limited, but from I've seen it's mostly vast But when you look at each feature they're not incredibly unintuitive. A huge problem in C++ is that there many ways to do everything (the old way and the new way and the new better way, all which have slightly different semantics).
Common Lisp is also vast but seems really solid on its foundations.
Scheme, Smalltalk and Go, definitely better. Lua. Java as well excepted maybe the really fine points of generics (captures) -- but in practice understanding that is almost never needed. C, unless you count undefined behavior as against least surprise, then it fails. Python I'm really not practiced enough to tell.
All in all, we're probably not using the same criteria for least surprise. I'm not even considering libraries, just baked in language features, and being able to predict what they do. In that sense, Ruby is really much worse than Java. It's really bizarre (see my blog posts in the other comments). And the problem is made worse by the fact that all that weird behavior is not documented anywhere.
(1) e.g. https://drive.google.com/file/d/0B0O9lcl5dMLQbDFkYk1kX28xM1U...
16 years ago, but just 6 years after the language was released, and 4 years before Rails came on the scene.
In retrospect, I'm not sure how successful Matz has been in upholding the principle of least surprise. In many ways, Ruby is one of the worst offenders.
> However, I don't think i'd feel comfortable with a language that only allows object-oriented programming
Ruby is multi-paradigm; in particular it's easily the most "functional"-feeling of the major scripting languages.
> and moreover OOP of the old way (a method must be tied to only one object. This is what prevents me from going to Smalltalk, btw.)
I'm unsure what you mean by this. Ruby has one of the most flexible OOP systems in existence, a good deal more flexible than Python's, and lets you create more or less any conceivable relationship between methods and objects. (Which is why Ruby is slow).
> Additionally, the MRI is perhaps the slowest implementation of a dynamic language out there (besides "R"). I know there are alternative implementations; is there any implementation that is significantly faster (at least as fast as Google V8 for ECMAScript) and that supports the full Ruby language without compatibility issues?
Ruby's not fast, but it's improved quite a bit from the 1.8 days. It's comparable to Python.
As for high-performance alternative implementations, there's TruffleRuby, but it still has compatibility issues and isn't ready for production use. There's also Crystal, which is a very similar (but incompatible) compiled language with performance on par with Go/Java/Swift. It's also still in beta but they plan to have a 1.0 release by the end of the year.
First of all, thank you very much for your informative reply on the implementations.
>I'm unsure what you mean by this.
I believe that any OOP system that wants to be flexible, modern, and powerful, should have most of the features that CLOS (Common Lisp Object System) has. Julia (language) did, for example.
It would be lengthy to explain all the features and benefits of CLOS here, but in CLOS, methods are not tied to objects, and all methods do multiple-dispatch. This also allows doing OOP in a functional-like way (this is easier to understand once you see how CLOS works.)
In comparison, most other OOP systems feel limited and restrictive, and very different from CLOS.
>a good deal more flexible than Python's
Probably, but OTOH Python's OOP system is perhaps one of the weakest OOP systems out there, and speaking from my 2 years of professional experience with Python. I find it acceptable, but not good.
There are plenty of lispers in the ruby world. "Ruby is an acceptable lisp" is a decently common saying.
While Ruby's OO is not a verbatim copy of CLOS, it is much more versatile than you've described above. The best way to think of it is it's delegation under the hood using a little syntax sugar to resemble classes. It's not multiple dispatch, but methods can be aggregated into modules that can be mixed into classes or objects arbitrarily. Dispatch is dynamic and structural (duck typing). All of this combined with ruby's meta programming features make for an expressive system. It's not restrictive, in fact it runs the risk of the opposite problem, which is people over use the flexibility and write overly magic code that proves difficult to maintain down the road.
>"Ruby is an acceptable lisp" is a decently common saying.
I got excited the first time I read that phrase (i think it was Matz who said it?), but they are very very different languages; for example metaprogramming is a piece of cake in Lisp, while it is something reserved for advanced Ruby users, to put just one example. And for me, metaprogramming is extremely important.
In any case, I think i'll give Ruby a second look.
I wouldn't say that metaprogramming is for "advanced Ruby users" at all, FWIW. I find writing dynamic/"unfolding" Ruby code much, much easier than wrangling Lisp macros.
It is worth your time.
> they plan to have a 1.0 release by the end of the year.
Actually that was delayed to next year.
> a method must be tied to only one object
What do you mean by that?
You can do this:
class A; def m; 'A'; end; end
class B; def m; 'B'; end; end
=> ["A", "B"]
I like Ruby especially because "everything is an object". That's a simple concept that you can understand easily.
Every time I use Python I stumble over how it does things differently. I can't wrap my head around the Python way.
Note, I don't like the metaprogramming approach that Rails popularized. Metaprogramming in small doses is okay but when everything you touch has some kind of indiscernible magic around it, it's just too much.
>What do you mean by that?
"m" is a method in class A,
"m" is a (different) method in class B.
Each method is tied to only one class. While in CLOS i can do the following:
let's say i have class Vehicle -> subclasses Spaceship and Car
then i have class Person
i can define, for example, the method "drive" two times:
drive (Spaceship, Person)
drive (Car, Person)
To put it in another way,
drive (Spaceship, Person)
Thus if i call the method "drive" and pass it two objects (a,b) , the language will check if there is an implementation of "drive" for the specific combination of class-of "a" and class-of "b" and apply the correct method.
CLOS also allows, for example, doing other interesting stuff, like, for example, if we have method "xxx" and when we call method "xxx" with some objects as arguments, there is more than one method that could apply, i can also configure things such as:
a) all methods are called and the results of all methods are collected in a list
b) the maximum of all results is used
c) the minimum
etc etc (you can define your own behavior)
There are much more features as well. For example, on your code you can specify the code that should execute whenever any vehicle is driven by a person; also, in separate, the code that should execute when a person drives a Spaceship, and also some piece of code that should be executed after any kind of vehicle is driven. These three methods aren't tied to a particular class definition, and will be called accordingly with just one line of code that calls the method "drive".
The point to all these features is that they allow mapping your problem domain to OOP in an easier way, because the language's limitations do not get in your way. You directly tell the OOP system what do you want it to do; there's less need to do workarounds.
My explanation, of course, is weak compared to the excellent explanation/tutorial here:
This sounds really cool.
I think you can get close to this with modules, for example defining a Drivable module with the drive(Person) method, and including that into Spaceship and Car. But I see how method combination would be more flexible and cleaner in many situations.
> significantly faster (at least as fast as Google V8 for ECMAScript)
Not by a long shot.
> and that supports the full Ruby language
And that's not even counting that.
Your best bet for speed with some remotely Ruby flavored language would be Crystal. Your best bet for parallelism (using JVM threads) with full Ruby support would be JRuby. Topaz is dead. There's the experimental TruffleRuby but I'd rather not bet on this yet.
You left out Substrate VM.
> I always get tempted to switch to Ruby * whenever i remember that Matz intended to make programmers happy. However, I don't think i'd feel comfortable with a language that only allows object-oriented programming, and moreover OOP of the old way (a method must be tied to only one object. This is what prevents me from going to Smalltalk, btw.)
That's a pretty strange stance. OOP is around and alive, and with the prudent addition of functional constructs, you get the best of both worlds.
To me, the deal breaker about a language is static typing: if the language is dynamically typed (like Ruby, Python and Smalltalk), it's a non starter.
Ruby string processing is faster than Python due to Ruby's built-in regular expressions. Numeric computation is generally faster in Python though Ruby does have some shortcuts which make it faster for certain types of calculation. I think these are due to memoisation.
I always get tempted to switch to Ruby * whenever i remember that Matz intended to make programmers happy. However, I don't think i'd feel comfortable with a language that only allows object-oriented programming, and moreover OOP of the old way (a method must be tied to only one object. This is what prevents me from going to Smalltalk, btw.)
Additionally, the MRI is perhaps the slowest implementation of a dynamic language out there (besides "R"). I know there are alternative implementations; is there any implementation that is significantly faster (at least as fast as Google V8 for ECMAScript) and that supports the full Ruby language without compatibility issues?
* in place of Python
It is largely a mature language and the inherent flexibility of the language means that a lot of things that require new language level constructs in other languages like Java aren't needed here.
The interesting stuff is happening in the runtimes (See TruffleRuby https://github.com/graalvm/truffleruby )
Yes, although many changes are performance optimizations and other under-the-covers sorts of things. Here are the changes for 2.5 which if tradition holds will be out on Christmas:
What new features does Ruby need? Why does a language need to be "cutting edge technology"? What are the issues with Ruby that need changing? These aren't rhetorical questions, I don't know much about Ruby and am genuinely curious.
They're adding a kind of pipeline operator (actually a method)
Along with what other people already responded, I think they're also pretty focused on the Ruby 3x3 project (making Ruby version 3 be three times faster), which may be slowing down the general heap of new features Rubyists were used to.
>It seems the language is not this cutting edge technology it was once.
Was it really cutting edge? I understood it as an improved OOP-only Perl. Rails, on the other hand, did knock me out the first time I saw it.
I guess few languages can be called 'cutting edge', perhaps the ML family including Haskell and (yes, after all these years) the Lisp dialects.
Well, they were cutting edge decades ago, it just took mainstream programming languages a long time to catch up (sort of). For example, you see macros in Elixir, Julia and Crystal, which are all newer languages.
Is there still some new features coming to Ruby? It seems the language is not this cutting edge technology it was once. I mean we see more changes in Java and PHP than Ruby these days.
> I'm planning a full rewrite of the interpreter for Ruby 2.0 [...] It will use a bytecode engine.
And so it did! https://en.wikipedia.org/wiki/YARV