kouteiheika 9 hours ago

> "Everything must be done in as many ways as possible with funky characters"

Are you sure you're not talking about Perl here? Because there are very few "funky characters" in Ruby and code written in it tends to be very readable, more so than Python in many cases.

I agree with OP. While Python is not a bad language, Ruby is a better language in general, and I'm reminded of it every time I have to work in Python (which is pretty often nowadays, due to Python's dominance in ML ).

I can give many examples as to why, but here's a quick toy example to show off the difference in philosophy between Ruby and Python. You have a list of numbers, you want to keep only odd numbers, sort them, and convert them to a string where each number is separated by comma. Here's the Ruby code:

    xs = [12, 3, 5, 8, 7, 10, 1, 4]
    ys = xs.filter { |x| x.odd? }.sort.join(", ")
Now let's do the same in Python:

    xs = [12, 3, 5, 8, 7, 10, 1, 4]
    ys = [x for x in xs if x % 2 != 0]
    ys.sort()
    ys = ", ".join(str(y) for y in ys)
Or alternatively in a single line (but in more complex cases this gets extremely unwieldy since, unlike Ruby, Python forces you to nest these, so you can't write nice pipelines that read top-to-bottom and left-to-right):

    xs = [12, 3, 5, 8, 7, 10, 1, 4]
    ys = ", ".join(str(y) for y in sorted(x for x in xs if x % 2 != 0))
And this matches my experience pretty well. Things I can do in Ruby in one line usually take two or three lines in Python, are more awkward to write and are less readable.

2
Demiurge 23 minutes ago

Ruby is in the running, so to speak, so of course that means there are thousands of people who agree with you. I'm not one of them. The fact that Ruby did not take of as much as Python did, even though there was all that RnR hype, is a testament to that. I don't think your examples are readable. What is |x| x.odd? ? (question mark pun intended) This is just "cleverness". I, personally, want my programming language to use method to use a keyword like "is" instead of operand?[question mark operator]

abenga 8 hours ago

To a beginner who is used to ordinary imperative languages, that Ruby line is extremely difficult to understand. Is `.filter` a method or a property of `xs`? Is `{ |x| x.odd? }` an argument to a method or just a statement that comes after `xs.filter`? If it is passed to `.filter`, why does it not have parentheses around it but the `", "` passed to `join` does?

This all makes sense to a person who knows the language a lot, but wrinkles the brain of a newcomer. Too many concepts to juggle in order to understand. On the other hand, the Python one reads quite easily, even if you may have to go right to left.

usrbinenv 8 hours ago

The only difficulty in Ruby code is the block notation. Even then, it is very similar to constructs in JavaScript, Go, D and a number of other languages -- the only difference form JS would be that instead of `(x) => ...` you write `{ |x| ... }`.

Questions such as

> why does it not have parentheses around it but the `", "` passed to `join` does?

would be exactly the same for JavaScript, Go or D. Ruby has the best syntax with regards to blocks/lambdas/closures.

Qem 49 minutes ago

> Ruby has the best syntax with regards to blocks/lambdas/closures.

A bit of Smalltalk shining through Ruby.

abenga 7 hours ago

I don't know much Ruby outside of a few toy examples I wrote a long time ago. For most languages, there would be parentheses around objects you pass to functions, like `.filter({|x| x.odd? })`. This lends some consistency and makes it easy (for me at least) to understand that an anonymous function is passed to `filter`. Just separating it using spaces feels like Bash, something I find difficult to write anything slightly complicated in.

creata 5 hours ago

Lua, Haskell, ML, plenty of other languages where one-argument functions don't need parentheses. I think it makes a lot of code more readable.

abenga 5 hours ago

All not-exactly-popular languages.

creata 5 hours ago

Maybe relative to juggernauts like C or Java. But Lua is pretty widely used.

Defletter 1 hour ago

Kotlin too

kouteiheika 7 hours ago

> To a beginner who is used to ordinary imperative languages, that Ruby line is extremely difficult to understand.

I don't understand this argument. You are a beginner only for a tiny fraction of your time using a given programming language. Why are we optimizing a programming language for people who don't know it, instead of optimizing it for people who actually program in it?

abenga 4 hours ago

> Why are we optimizing a programming language for people who don't know it, instead of optimizing it for people who actually program in it?

Everyone who actually programs in a language was once a person who didn't know it. Languages which optimize for succinct terseness might be powerful once you master them, but they will never enter mainstream use, which I guess is not necessarily the aim.

creata 5 hours ago

The Ruby syntax doesn't seem that different to many other languages. For example:

    xs.filter(x => x & 1).sort().join(", ") // JavaScript

    xs & filter odd & sort & map show & intercalate ", " -- Haskell
Python seems to be the odd one out. Imo, its list comprehensions are confusing as hell to "newcomers". For example, when a list comprehension has multiple `for`s, what order are they nested in?

quietbritishjim 1 hour ago

> ... confusing as hell to "newcomers". For example, when a list comprehension has multiple `for`s, what order are they nested in?

I get that this is just a rhetorical question to make a point about newcomers, and I do agree it's not immediately obvious, but for the record: you can imagine any "if"s and "for"s in a list comprehension are nested statements in the same order. So, for example, this:

   l = [
      y.foo()
      for x in my_list
      if x.blah() > 7
      for y in x.ys()
   ]
Is equivalent to this:

   l = []
   for x in my_list:
       if x.blah() > 7:
           for y in x.ys():
               l.append(y.foo())
So the least comprehension is basically in left to right order with the one exception of the actual expression to be added to the list (like y.foo() in the example above).

creata 57 minutes ago

Yeah, I know, I know. But I imagine many people would mentally want to bracket [e for x in xs for y in ys] like [(e for x in xs) for y in ys] and thus conclude that y is the outer loop.

abenga 4 hours ago

Those both seem a little bit more consistent than the Ruby example, however. To understand the JS example for example, you only need know that to call a method on an object, you do `object.method(arguments)`, and this is chained in a straightforward manner, with methods called on the returned values left to right. Ditto for the Haskell example. Maybe the Ruby one does the same thing, but even in this extremely simple example, we still have two different ways of doing the same thing.

For Python, you don't really have to use list comprehensions in the place of multiple for loops, you can sacrifice the brevity afforded to write the same thing in a more easily understandable fashion.