5 ms·
Yehuda Katz's 10 Favorite Things About Ruby
"I work with Ruby every single day, and over time have come to really enjoy using it. Here’s a list of some specific things that I really like about Ruby. Some of them are obvious, and some are shared with other languages. The purpose is to share things I like about Ruby, not to compare and contrast with any specific language."
- defunkt 17y agoUnfortunately try illustrates the exact problem with open classes so many non-Rubyists are afraid of: collisions. try was originally defined as: class Object def try(method) send method if respond_to? method end end In Rails it is defined as: class Object alias_method :try, :__send__ end class NilClass def try(*args) nil end end The following code will exhibit different behavior depending on which version of try you're using: [].try :upcase For example: # original try >> [].try :upcase => nil # rails try >> [].try :upcase NoMethodError: undefined method `upcase' for []:Array If Rails uses try internally, and a Rails plugin you've loaded depends on the original version of try, what now? They both behave differently and, presumably, code using them depends on their specific behavior. Also don't forget the dozen or so other versions of try people have added to their own plugins and apps...
- dylanz 17y agoArticulated perfectly! Any time I'm working on a Rails project, and run into odd behaviours, the first thing I'll do is check to see if I'm actually using a Ruby or a Rails method. Most often than not, I'm expecting a "Ruby" way of doing things, but find out I'm actually using the "Rails" version, which does something completely different. If I run into any in the next few hours, I'll post them here :)
- carbon8 17y agoIt's not really a Ruby vs Rails way of doing things. The Rails implementation is arguably more in line with the standard Ruby behavior since it throws a NoMethodError for everything other than Nil objects.
- defunkt 17y agoI would argue that, no, there isn't "standard Ruby behavior" in this instance. It's just a method.
- carbon8 17y agoTrue, they are all just methods, but it's basically just an altered version of Object#send, and the current Rails implementation only significantly differs from it in the specific situation it's intended for. I realize there are a range of preferences regarding ways to tackle the problem this is intended to solve, and I'm relatively agnostic about the overall issue, but if the implementation is basically a #send that guards against nil, then it would be unexpected for it to deviate remarkably from #send when dealing with non-nil objects.
- steveklabnik 17y agoThis was supposed to be a really simple example. One could always write the code such that try only gets defined if there's no existing definition.
- defunkt 17y agoAgain: you are using two libraries (Rails and plugin X) that depend on their own versions of try, which they include. One of the libraries is going to break.
- wycats 17y agoIndeed. It's probably wise to use namespaced internal methods inside of libraries or frameworks. However, Rails has historically pioneered new language features that eventually make their way into the language itself (Object#tap, Enumerable#group_by, etc. etc.). In Rails 3, we've made it reasonable to pull in just small pieces of the ActiveSupport library, making it more likely that users will reuse functionality from there rather than reinvent the wheel. Of course, it's not perfect.
- simonw 17y agoAm I right in thinking that once a piece of ActiveSupport is pulled in anywhere in the codebase it will affect ALL Ruby objects, rather than having its effect scoped to just the module that included it?
- wycats 17y agoYep. You'd be modifying the String class itself, not just Strings that find their way into some file.
- steveklabnik 17y agoWell... yes. You're right. If you're depending on one behavior rather than the other, then totally. I guess I was thinking about it more in terms of two different implementations of the same thing. "If we don't have a quicksort defined yet, make one."
- xenophanes 17y agoAnother difference: the original version doesn't take multiple arguments, but the new one does.
- tptacek 17y agoNot everything in Ruby is a full-fledged class; for instance, you can't extend Fixnum. [I am apparently completely wrong here].
- jcapote 17y agoSays who? irb(main):001:0> class Fixnum irb(main):002:1> def doit irb(main):003:2> puts "hey" irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> 2.doit hey => nil irb(main):007:0>
- jeremymcanally 17y agoYup. Perhaps he was thinking of Python, where his assertion is true.
- blasdel 17y agoNot true in Python either since new-style classes unified types and classes.
- nudded 17y agoclass Fixnum def +(other) 42 end end 3 + 2 => 42
- judofyr 17y agoYou're partly right. Fixnums don't have a metaclass (or virtualclass) because they're actually "immediate". So you can't say 123.extend(Something) because 123 isn't really a full Object.
- mpk 17y agoI love reading articles like this. 8 years or so ago Ruby replaced Perl for me as my 'go to' language for day-to-day problems. I haven't looked back since. What other people call 'magic', I call not understanding the language and execution environment. For long-running server-side stuff Ruby would not be my first choice, but for eloquence and scripting capabilities... accept no substitute.