I use Ruby some, but I'm not sure I'd describe it as clean exactly. I've used Python a bit recently and was struck by just how clean it seemed. (I'm not sure Python has anything that quite replaces blocks, though. I don't claim Python's all better than Ruby.)
I am a pythonista by hobby... and I've seen many times in these too many ruby / python comparison, that only in ruby "Everything is an object, without exception."
but... I cannot find a "thing" that isn't an object, in python neither... care to tell me, or point to a link regarding to, what is the difference in this context between the two languages?
Just an example or something like that.
Thanks.
Trying to guess how Python works is quite hard if you're used to Ruby and other languages closer to Java.
As I don't know much Python myself, it's hard to tell where Python fails the "everything is an Object" check. But in Python some legacy calls were more procedural than OO, like "len(o)" rather than "o.len". I think eventually Python got to support both approaches.
I think Ruby is all objects even in its C abstractions. In Ruby, people create classes and so on in the RubyC abstractions that are visible to the Ruby language too. Not sure how Python does those.
I know Python has reference counting for Garbage Collection, so there are differences to their approaches in that regard and more.
Like Guido Van Rossum said, from 10,000 feet both Ruby and Python are more alike than different. He was saying that people should appreciate them more even if they belong to the community of the other one. That the real enemy is languages like Java that switch around the priority by making code that compilers prefer rather than programmers prefer.
I think Python has a Functions legacy that could not be as OO as they would be in Ruby.
Right now I'm more "in love" with Dart than with Ruby. Ruby was my first real love though.
Just as note: I don't really would call "len(o)" a "legacy call", as in "something it's here just for backward compatibility, but it's ugly and please don't use it".
It's more "the good way to do it" :D
len() is a perfect example of the duck typing and the "protocol-based" philosophy of python: its implementation it's something like
def len(object):
return object.__len__()
as in "just return the result of invoking the object method called __len__".
this lets you just call len() on every "len-able" object. They can be list, dict, custom objects... instead of the need to, I don't know, implements an explicit interface, or define a "getLength()", "size()", "length()", "length" (just an attribute, not a function to call), you can just define a "magic" (as in "normally you don't need to call this directly") method called __len__.
you can create your "not really a container, but it has a length!" object as something like
As indirect effect, it enables you to go on the functional-style approach... a simple
map(len, list_of_lists)
it's more readable than
map(lambda l: l.__len__(), list_of_lists)
(probably [len(l) for l in list_of_lists] it's more readable, but bear with me...)
I'm not really sure about the "ruby C abstractions": do you refer to the use of "object-like" structs used in the C sources of the "ruby MRI" implementation of "ruby-the-language"?
regarding the GC... I don't know, but why is the kind of the GC used by an implementation of the language (or the complete lack of a GC) relevant to the "everything is an object"?
just to be clear, I don't dislike ruby :) it's just that I don't find the "everything is an object" a way to discriminate between ruby and python.
You see, you wrote a bunch about how len is so cool in Python. But in the face of dynamic typing and polymorphism I didn't expect it to be any different really. Languages like Go that are statically typed make more of an issue about interfaces. Even in Dart they dropped explicit Interface usage in favor of implicit interfaces, considering that Dart is more explicit about matters than Ruby is.
Switching those function calls around reminds me of Delphi. When I first learned about Python, those calls reminded me of Delphi which I had used more. But once I learned Java, my frame of mind went from function(object) to object.function. With Ruby I found it quite intuitive. Now all languages work better if they approach things the way Java and Ruby do because of familiarity. That's why I like Dart for what it's worth.
Regarding C extensions of Ruby, they are like OO in C. Not sure how Python does it by default. But in Ruby all C extensions have a OO flavor. The first major book about Ruby writes about them: http://www.ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.h...
I think if you're counting references in the GC perhaps your C extensions are not very OO yet. In Ruby as in Java, the GC is an abstraction over reference counting. I think reference counting is often said to lead to more predictable performance at the cost of increasing the maintenance burden.
So again, not sure where Python is not "Objects all the way down." But Ruby has had the OO philosophy from early on. I think the Ruby OO approach started with the OO of the C extensions and went from there. Unlike Python that had a stronger procedural influence. The gap has closed since, but in Python a class is not written like this yet:
class InRuby
def aMethod
end
end
class InDart {
aMethod() {}
}
so I assume also on C level the python objects are mapped on some structs in OO fashion...
I honestly have no idea on how is (or if it has some meaning) to extend python in rpython on pypy, but in this case I assume there are some objects involved :D
Exactly. In Python you still pass "self" to the method. In Ruby and Dart it's not needed.
In Python I've seen Python users discourage the use of classes. I haven't seen the same distrust of classes in Ruby for instance. It's as though Python has unresolved OO issues. Python could take pride in being "multi-paradigm", whereas languages like Ruby and Dart could take pride in being more OO.
Regarding the C extensions of Ruby, I think the bottomline is that from int, to booleans, to null, to classes, everything is considered OO even in the C code. So common functions can be applied to them even from C, say like Polymorphism would in other languages. From the primitives on up everything is like a high level Ruby. As Python is more "multi-paradigm" perhaps some of its C extension features aren't as OO as Ruby's are.
Funny though that those C extensions that make Python and Ruby so popular end up making other implementations of those languages that target other runtimes incompatible as they don't have access to those C extensions. So even in that regard they are similar.
Say we can't find anywhere in Python where Objects don't exist. Then welcome on board of true OO. Now show OO some love and stop discouraging the using of classes. Maybe drop the "multi-paradigm" approach. I know though that like JavaScript, sometimes you have to live with the shortcomings of the programming language in its support of OO. So while JavaScript could be said to have Objects everywhere, and it truly does, writing classes in JavaScript is not a settled issue. That's why I like Dart instead:
class A {
var aList = ['a', 'aa'];
get length => aList.length;
}
class B {
var aList = ['b', 'bb', 'bbb'];
get length => aList.length;
}
class C extends A {
var aList = ['c', 'cc', 'ccc', 'cccc'];
}
printIt(o) {
print("${o.aList}: ${o.length}");
}
void main() {
printIt(new A());
printIt(new B());
printIt(new C());
}
>>Say we can't find anywhere in Python where Objects don't exist.
You're correct - we can't find a place in Python where Objects don't exist. Python and Ruby are exactly same in this.
>>Then welcome on board of true OO. Now show OO some love and stop discouraging the using of classes.
What do you mean by true OO?
It does not matter if you "love" objects or not.
You can't write in python without OO. Every python module is an object, defs and vars - members of object. (Even classes and other modules are members of module object).
Or, instead of having the convention that objects with a length implement __len__, you could have the convention where they just implement len and you could just call obj.len.
In java the arrays objects expose a public int attribute called .length.
The strings also expose a .length attribute, but it's a method.
If, for some reason, you need to know how many elements are in enum, you need to call NameOfTheEnum.values().length.
If you have a Collection (a Map, a List...), you need to call .size().
...
Yeah. You are right about the fact that a possible "convention" would be to call .len, not .__len__ but you are forgetting 20+ years of backward compatibility.
I don't know when len() was introduced, and I'm not sure it's initial implementation was a simple "return object.__len__()" (or an equivalent...).
What I know is that an explicit len function helped to hide the eventually different implementation details, and allowed the developers of the containers go crazy with attributes.
Moreover, with a len(obj) function and a obj.len() "public" method, you have two ways to do it.
I wasn't trying to compare Ruby and Python (I'm not a big Python user); I was just explaining why I said Ruby was "clean". As simonw observed, all of these points arguably apply to Python too.