9 ms·
Some Mental Traps in Learning Ruby
- toisanji 19y agoDataMapper, an ActiveRecord replacement where I am one of the coders,uses the same Person[1] syntax. Check it out sometime: http://datamapper.org/ http://datamapper.org/
- jamesbritt 19y agoIt's been part of Og for a while, perhaps from the beginning. There seems to be some Ruby communal understanding that the use of [x] should follow Array-ish behavior, but when used with a class constant it's apparent that this is not simply an array, and that some other sort of indexing is going on.
- timr 19y agoThe most insightful text on the linked page is the first (currently only) comment: this is unnecessary and confusing. In fact, this is one of the "features" of Ruby that I hate -- it's frequently difficult to know what a particular piece of code does, because the Ruby community's golly-gee fascination with interfaces and dynamic mixins tends to lead to inconsistent behavior in different contexts. The idea of separating interface and implementation is not new. Even us crusty, abused C++ programmers can override the bracket operator; we just happen to believe that overriding that operator in a way that leads to unexpected behaviour for particular subscript values is a Bad Idea. The principle of least surprise is an important one in programming; I wish that more people would obey it as a law.
- mdemare 19y agoIn Ruby, the subscript operator is just another method name. There's no essential difference between an operator and a 'normal' method like to_s. To know which method is called, you need to know the class of the receiver and the method name - together they determine unambiguously which method is called, and hence there is no surprise. The only surprises occur when the programmer is mistaken about the type of an object - those are the risks of dynamically typed languages.
- timr 19y agoYou've missed my point. I understand that [] is a method in Ruby. In fact, operator[] is also a method name in C++, and can be overloaded, overridden, etc. Ruby did not invent these features. Likewise, in C++, the type of an object and the method name invoked determine unambiguously the method that is called. The difference -- and this is critical -- is that in the C++ community, there is a strong bias against syntactical games that make code behave inconsistently. Having operator[] behave differently for different subscripts would be a mortal sin in C++ design (not to mention that the type system would probably punish you for it). We can debate the relative merits of strong/weak typing, but the principle of least surprise is a good one, and should be respected, regardless of what a language may allow you to do (cf. Perl).
- mdemare 19y agoFirst, of course the principle of least surprise is good, but it doesn't apply here. No experienced Ruby programmer would look at 'a[0]' and think - oh, an index into an array. They know that it could mean many things, depending on the receiver, not the subscript value. Also in Ruby there is no overloading. Overloading means that a different method is chosen depending on the types of the arguments. That means that in C++, it is not true that "the type of an object and the method name invoked determine unambiguously the method that is called". In practise there is also little overriding - there seems to be no need. In C++ there is a lot more, and because of multiple inheritance, things can get confusing. (Overriding and overloading are two ways in which OO-languages violate the principle of least surprise). This means that the reasons why using operator overloading is bad in C++ don't (automatically) apply to Ruby.
- timr 19y agoI'm going to ignore your more pedantic points (e.g. method "signature" vs. method "name", and the silly notion of "overloading" in a dynamically typed language), and focus right on the meat of the argument: Every "experienced Ruby programmer" may well come to understand that standard expressions fail to mean standard things when used in Ruby; that doesn't make it a good idiom. The problem here isn't that the bracket operator fails to reference into an array -- it's that the bracket operator might behave inconsistently for certain subscript values. The STL map class is a perfect analogue: rather than implement an operator[] than could fail in certain contexts, the C++ standard demands that map::operator[] must always return an object. This is consistent behavior. Allowing operator[] to fail for subscript N-1 when it works for N? That's inconsistent (and confusing), but apparently, it's the Ruby Way.