4 ms·
In 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 whic
by mdemare 19y ago
In 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.
- bct 19y ago> To know which method is called, you need to know the class of the receiver and the method name Unless someone's been using metaclass trickery, eg. array = [] def array.length; "banana"; end array.length # => "banana" [].length # => 0 (you can do the same thing with []=, the example is just longer)
- mdemare 19y agoI'd argue that this involves changing the class of the receiver (I think that is what actually happens under the covers). Also, I think this would count as a mortal sin in production code (but a lot of fun nevertheless).