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.
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.
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.
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.
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).
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.
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).
Can you explain why? I'm curious.
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...