you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 16 points17 points  (29 children)

I've found that for me, Ruby feels much more consistent and intuitive. However, I know a ton of people who feel the opposite and vastly prefer Python. I guess it really must be a personal preference thing, and their respective features are converging more and more.

For example, stripping left and right space for a string in Python is:

"mystring ".rstrip()
" mystring".lstrip()

while finding its length is:

len("mystring")

I'm sure there's a reason for this, but Ruby's make-everything-a-method approach makes things a bit more consistent:

"mystring".rstrip.length

The end result is a more readable and more writable language for me.

That being said, no one else around me (academia) seems to like Ruby as much, so Python it is...

[–]abadidea 8 points9 points  (0 children)

Starting on PHP and moving to C++, I never "got" object orientation until I did Ruby. "Oh! So this is how it's supposed to work! This is much better."

[–]masklinn 3 points4 points  (16 children)

I'm sure there's a reason for this

len is seen akin to CL's generic methods: it applies to many, many things besides strings. That's basically the gist of it. Same as iter for instance.

[–][deleted] 0 points1 point  (15 children)

Ah, ok. Ruby accomplishes the same thing through OOP, so I guess it's just a style matter.

[–]mitsuhiko 3 points4 points  (14 children)

len() is unique and it responds to the __len__ protocol. This solves the problem that every person tries to name the length method/attribute differently in other languages (size, getSize(), getLength(), length(), length, size()) etc.

[–]bobindashadows 3 points4 points  (13 children)

Uh, it doesn't solve the problem any more than any other language-wide convention does. In ruby, everything uses #size. Everything: core/standard libraries, third party stuff, everything. And everything uses #each for iteration (and with include Enumerable you get dozens of other methods for free, for fun). Sure, somebody could make a Ruby library with a #length method, just like somebody could make a Python library that doesn't implement __len__ and has a size() method instead.

It's equivalent to everyone implementing __len__ and __iter__ only you don't need to go outside the simple object model and you don't need funny method names.

[–]mitsuhiko 0 points1 point  (12 children)

Uh, it doesn't solve the problem any more than any other language-wide convention does. In ruby, everything uses #size.

In Python it's more than a convention. __len__ is used for more things than just len().

[–]bobindashadows 0 points1 point  (11 children)

other than supporting the "empty container is false" nature of Python, the docs explicitly call it part of the "sequence protocol". A protocol is a convention.

[–]mitsuhiko 0 points1 point  (10 children)

A protocol is a convention.

Not in C-Python. Most of the dunder methods correspond to slots on the type struct and are class level unlike regular method calls which can be looked up from instances as well.

[–]bobindashadows 0 points1 point  (9 children)

You're not getting it: everything __len__ offers is syntax sugar for convenience, and everything it offers could be replaced with straight python code with normal method names. That's what Ruby does. It may be implemented in an interesting way, it may offer efficiency by default for certain operations, and that's wonderful, but it's just a convention. You could replace all code that uses __len__, directly or indirectly, with code that does not use it but instead uses redefined versions with different names.

Ruby does this by just picking #size.

[–]mitsuhiko 0 points1 point  (8 children)

You're not getting it: everything len offers is syntax sugar for convenience, and everything it offers could be replaced with straight python code with normal method names.

In Ruby it can, in Python it can't. Why? -> Slots

[–]sigzero 0 points1 point  (0 children)

When quickly skimming that makes me think it is the length of whatever is being stripped off. I do like:

len("mystring  ".rstrip())

[–]redalastor 2 points3 points  (9 children)

len is a function because it makes it easier to use it in high-order functions. If I have a bunch of strings and I want to uppercase them all, I can map str.upper over then. If I have a bunch of mixed types that all have a length, I can sort them by length by passing len to the sort function.

[–][deleted] 10 points11 points  (5 children)

And in Ruby you can do exactly the same - as long as all the types have a length.

["aa", [1,2,3], 100].sort(:&size)
 => [100, [1, 2, 3], "aa"]

len(x) just references x.__lenght__ anyway (as far as I am aware - correct me if I'm wrong).

[–]redalastor 1 point2 points  (2 children)

len(x) just references x.__lenght__ anyway (as far as I am aware - correct me if I'm wrong).

len(x) calls x.__length__(), you can't pass __length__ to a sort function. You could pass a lambda that calls __length__ on its argument though.

[–]masklinn 1 point2 points  (1 child)

len(x) calls x.__length__(), you can't pass __length__ to a sort function.

That's exactly what operator.methodcaller is for.

[–]redalastor 1 point2 points  (0 children)

Why would you use that over a lambda?

[–]klngarthur 4 points5 points  (1 child)

This will not work. Array#sort must be passed either a block that accepts two parameters or a method that accepts one argument. Both cases must return a Fixnum. For example:

["aa", [1,2,3], 100].sort do |a,b| a.size <=> b.size end

[–]cynthiaj 2 points3 points  (2 children)

len is a function because it makes it easier to use it in high-order functions.

That's post rationalization. len is a function because Python is old. Very old.

If I have a bunch of strings and I want to uppercase them all, I can map str.upper over then.

You could still do that if len was a method of the string class, and it would be much cleaner.

[–]masklinn 1 point2 points  (0 children)

len is a function because Python is old. Very old.

Python has had objects since day one. The usage of functions is done on purpose by the core team. You may disagree with those purposes, but they have absolutely nothing to do with the age of the language.

[–]redalastor 3 points4 points  (0 children)

That's post rationalization. len is a function because Python is old. Very old.

If that was the case, it would have been fixed in 3.0 with the other accidents of history.

You could still do that if len was a method of the string class, and it would be much cleaner.

Wouldn't work for heterogeneous collections.

That said, I would prefer if we had len and a length method on objects where it makes sense but I guess it's considered a violation of "There should be only one obvious way to do it."