I’m born and raised in Kraków, a beautiful city in Poland, maybe you’ve heard about it, maybe you’ve even been here. In Poland we speak Polish, which is a really difficult language, it’s actually considered one of the top-10 most difficult languages to learn in the world. In Poland, just like in many other countries, there are regions where dialects are used rather than “the pure” form of the language, and so in my city, we have our own dialect. It’s not too different from Polish, but we have our special words, and a special way of saying certain words. For example, we say “czy”, which means “three”, even though the correct form is “trzy”, but we’re like “that’s too hard” so we keep it simple, “czydzieści czy” (33) instead of “trzydzieści trzy”. The rest of Poland is making fun of us because of this kind of stuff, but whatever, it’s our dialect – this is how we like to speak.
What does it have to do with Rails and Ruby though? Good question. Programming languages have dialects as well, by definition, a programming language dialect is “a (relatively small) variation or extension of the language that does not change its intrinsic nature”. It doesn’t really matter how exactly such variation or extension is implemented. The important part is that the original language is extended and it provides more functionality, while it’s original nature and behavior stay the same.
This brings us to Ruby – a programming language with open classes, where even the core functionality of the language can be extended by simply adding new methods to core classes, like String
or Array
. This makes it very simple to create your own Ruby dialect!
This unique feature of Ruby has been leveraged by DHH back when he created Ruby on Rails framework. The very foundation of this framework is a library called ActiveSupport – a big collection of core Ruby extensions, which together create a Ruby dialect, an extended version of the Ruby language, which doesn’t change it’s intrinsic nature. Why is it a foundation of the framework, you may ask – the answer is very simple: everything would break if you tried to remove ActiveSupport from Rails.
What does it actually mean if you take into consideration the entire Ruby ecosystem though?
Monopoly for monkey-patching
Monkey-patching is another way of saying that some piece of code alters an existing class by leveraging open classes in Ruby. The ActiveSupport library monkey-patches many classes, there are currently 3471 LOC
in its core_ext
directory. Here, I’ve generated some stats:
{Array=>{:original_methods=>196, :as_methods=>251, :added_by_as=>55},
Class=>{:original_methods=>117, :as_methods=>172, :added_by_as=>55},
Date=>{:original_methods=>132, :as_methods=>240, :added_by_as=>108},
DateTime=>{:original_methods=>142, :as_methods=>277, :added_by_as=>135},
File=>{:original_methods=>236, :as_methods=>279, :added_by_as=>43},
Hash=>{:original_methods=>182, :as_methods=>246, :added_by_as=>64},
Integer=>{:original_methods=>148, :as_methods=>206, :added_by_as=>58},
Module=>{:original_methods=>114, :as_methods=>165, :added_by_as=>51},
Object=>{:original_methods=>63, :as_methods=>83, :added_by_as=>20},
Range=>{:original_methods=>133, :as_methods=>171, :added_by_as=>38},
String=>{:original_methods=>188, :as_methods=>256, :added_by_as=>68},
Symbol=>{:original_methods=>92, :as_methods=>114, :added_by_as=>22},
Time=>{:original_methods=>121, :as_methods=>257, :added_by_as=>136}}
When you count them all, you get 853 instance methods added to the core classes.
Notice that I’m only talking about the core extensions. I skipped classes from the stdlib! I also counted only public instance methods. It would be interesting to see how many class and private methods ActiveSupport adds. This would be a fun excercise.
When you have a library, a ruby gem, which adds such a significant amount of new methods to the core classes, it is important to understand that:
- You are no longer using Ruby, you are now using a Ruby dialect, implemented as a library called ActiveSupport
- You must be aware that the methods that you are adding to your own classes in your application’s code could potentially cause conflicts with ActiveSupport
- It is a very bad idea to build other libraries, that also monkey-patch core classes, because they can cause conflicts as well
Some time ago, we had a lot of ruby gems that would also rely on monkey-patching. We even had a full-stack framework that was meant to compete with Rails. It was called Merb and it also had something like ActiveSupport, it was called extlib. As you probably guessed – it caused conflicts with ActiveSupport so it wasn’t really feasible to use both libraries in the same codebase. Merb and Rails “merged” into Rails 3 though, and that’s how we don’t have “an extlib problem” anymore, because the library is gone. Over time, many Ruby developers