News for hackers. Stuff that matters.
Re:Ruby 3.2.0 Is from Another Dimension by xigoi on Wednesday January 04, 2023 @05:29AM (#34244045)
One aspect in which Ruby is much more consistent than Python:

    sorted(arr)
    arr.sort()
versus

    arr.sort
    arr.sort!
Re:Ruby 3.2.0 Is from Another Dimension by samwillis on Wednesday January 04, 2023 @05:38AM (#34244096)
Personally I think the Python syntax make its more explicit which is anin-place sort vs returning a sorted copy. And also what's a method call vs an attribute access.

Someone new to Ruby will the WTF is the ! for?

Re:Ruby 3.2.0 Is from Another Dimension by xigoi on Wednesday January 04, 2023 @05:44AM (#34244126)
How does having a function instead of a method indicate that it's out-of-place?

Every Ruby tutorial explains that an exclamation mark means in-place, and this convention is consistent across Ruby libraries, unlike Python.

Re:Ruby 3.2.0 Is from Another Dimension by aidos on Wednesday January 04, 2023 @06:09AM (#34244265)
It's a convention, quite a nice one, but not all libraries are consistent and it does have different meanings too (! is sometimes used for "raise an error instead of returning a boolean").

In the Python case, `list.sort()` operates on the object, so you can kind of expect it to do mutation (but there's no convention / guarantee). Though it only makes sense as a function that the list object itself implements.

`sorted` is a general function that gives you a sorted list from any iterable, and because working with iterables is such a common thing in software, Python has a bunch of standard functions like that. It's nice because you learn them once and they apply absolutely everywhere.

Ultimately you learn the behaviours of a language and they become second nature. I find both Ruby and Python very clean and easy to read.

Re:Ruby 3.2.0 Is from Another Dimension by peoplefromibiza on Wednesday January 04, 2023 @06:53AM (#34244518)
> it does have different meanings too

the meaning is the same high level: it has side effects, being it a destructive update, an in place operation or throwing an exception.

> `sorted` is a general function that gives you a sorted list from any iterable

iterable in Python is a very loose concept though.

And it's not very consistent too

    sorted("gheliabciou")
    ['a', 'b', 'c', 'e', 'g', 'h', 'i', 'i', 'l', 'o', 'u']
you give it a str it returns a list of char

in Ruby it makes much more sense

   "gheliabciou".chars.sort.join
   "abceghiilou"
You take out the chars from the string, sort them and then join them together again

because a string cannot be sorted, sorting a string makes no sense, you sort the chars composing it.

Also, Python could not do this for many years, while Ruby could no prob

  sorted("gheliabciouรŸโŒšโŒจโŒ›๐Ÿ†”๐Ÿ‰‘๐Ÿˆถ๐Ÿˆš๐Ÿˆธ๐Ÿˆบ๐Ÿˆท๐Ÿ†š๐Ÿ‰ใŠ™ใŠ—๐Ÿˆด")
Re:Ruby 3.2.0 Is from Another Dimension by nindalf on Wednesday January 04, 2023 @07:16AM (#34244655)
You can use emoji in HN comments? Emojis get automatically removed from mine.

Edit: ok, some do and some donโ€™t. ๐Ÿˆถ is allowed but :laugh_with_tears: isnโ€™t. I guess thereโ€™s a specific list of emojis that are getting stripped.

Re:Ruby 3.2.0 Is from Another Dimension by saagarjha on Wednesday January 04, 2023 @07:26AM (#34244747)
There are specific blocks that are filtered out.
Re:Ruby 3.2.0 Is from Another Dimension by peoplefromibiza on Wednesday January 04, 2023 @07:26AM (#34244748)
Re:Ruby 3.2.0 Is from Another Dimension by aidos on Wednesday January 04, 2023 @09:25AM (#34245810)
Lots of objects don't have a natural way to return a sorted version of themselves, especially inplace (what's the reverse sort of a range, for example). You get the same in Ruby, as you've just demonstrated. Sorting into a list is the only thing that makes sense in all cases.

In that way `sorted` _is_ totally consistent - it always takes an iterable and returns a list of the elements. If we can't agree on that then I don't think there's much of a discussion to be had here.

Re:Ruby 3.2.0 Is from Another Dimension by peoplefromibiza on Wednesday January 04, 2023 @11:25AM (#34247581)
> In that way `sorted` _is_ totally consistent - it always takes an iterable and returns a list of the elements

except Iterable is the wrong "interface"

in Python it is defined as

> An iterable is any Python object capable of returning its members one at a time, permitting it to be iterated over in a for-loop.

which is not always what you want for sorting

quicksort doesn't work one element at a time

so basically you have to extract all the elements before sorting them

what about infinite streams?

At least Ruby Enumerable mixins explicitly states that

> The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to __sort__.

Another problem with sorted is that it accepts any iterable, true, returning a list of items, but it is not clear how you can tell if the object is an iterbale or not

  >>> sorted(123)
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: 'int' object is not iterable
ok

  >>> isinstance(123, iterable)
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  NameError: name 'iterable' is not defined
mmmm

maybe it's because int is not iterable?

  >>> isinstace("abc", iterable)
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  NameError: name 'iterable' is not defined
so the solutions are

  # fails for strings in Python 2
  >>> try:
     _ = iter(some_object)
  except TypeError as te:
     print('is not iterable')
or

  # if 2.6 >= Python < 3.3
  from collections import Iterable
  # if Python >= 3.3
  from collections.abc import Iterable # <- personal note, abc stands for...? core maybe?
  # no idea on how to do it in Python < 2.6

  >>> isinstance("abc", Iterable)
  True
not only it's very ugly, but it can also fail in mysterious ways. As per documentation

Checking isinstance(obj, Iterable) detects classes that are registered as Iterable or that have an __iter__() method, but it does not detect classes that iterate with the __getitem__() method. The only reliable way to determine whether an object is iterable is to call iter(obj).

while in Ruby it's straightforward

  [3] pry(main)> [1, 2].is_a? Enumerable
  => true

  [4] pry(main)> "abc".is_a? Enumerable
  => false

  [5] pry(main)> "abc".chars.is_a? Enumerable
  => true
Re:Ruby 3.2.0 Is from Another Dimension by laserlight on Wednesday January 04, 2023 @06:13AM (#34244291)
Newcomers to Python will have many more WTFs, many of which are syntactically invisible.
Re:Ruby 3.2.0 Is from Another Dimension by consp on Wednesday January 04, 2023 @08:14AM (#34245148)
I have (had) this for all languages, including ruby. No two people are alike and since it's all a "I think this is best" approach (either by person or committee) you will always have some form of it. Unless you use brainfuck, maybe.
Re:Ruby 3.2.0 Is from Another Dimension by pizza234 on Wednesday January 04, 2023 @08:52AM (#34245480)
When i learned Ruby, it wasn't really a WTF for me - I just learned that '!' methods are destructive, while non-'!' aren't.

However, the destructiveness semantic has been significantly overloaded over the time, so each Ruby (Rails) project probably interprets them in a different way, and it ends up having arbitrary semantics.

I'm used to it, but I personally think that for the reason above, it's not a good syntax/semantic to have in a language.

Re:Ruby 3.2.0 Is from Another Dimension by michaelteter on Wednesday January 04, 2023 @02:12PM (#34249997)
> arbitrary semantics

I wouldn't go so far to say it is arbitrary (unless someone uses it wrongly :) ).

As far as I know, a bang name only exists if a non-bang name exists as well. And the one with ! indicates an unexpected or comparatively dangerous outcome, such as a mutation, raising an exception, bypassing some normal check, etc.

Re:Ruby 3.2.0 Is from Another Dimension by bobbylarrybobby on Wednesday January 04, 2023 @10:32AM (#34246713)
But random.shuffle also operates in place despite being a free function
Re:Ruby 3.2.0 Is from Another Dimension by michaelteter on Wednesday January 04, 2023 @02:08PM (#34249952)
> WTF is the ! for?

This takes so little time to learn. Same with ?.

While ! is not always the same meaning, it exists when there is a non-bang version; and it means "watch out, this does some sh*t". Maybe it means mutating the source, or maybe it means "doesn't take the usual path", as with Active Record stuff (raising an exception if validations fail on save instead of just returning false).

And the ? is a godsend, as you can clearly indicate functions which return a boolean (or intentionally truthy) value. As naming functions is a chore, and one which can have significant impact on code readability later, the ! and ? have good value when used properly.

For example, Python's sorted() vs list.sort(). If you are new to Python, and you see sorted(list), you may wonder if that is telling you if the list is sorted or sorting the list. It's actually also very awkward, because most functions are named as their actions in present tense, not in past tense. The built-in Python function "sorted" really should be "sort".

In the list of Python built-in functions, you see present tense verbs like slice(), sum(), round(), etc. Those are inconsistent with sorted() and reversed(). When we see a past tense verb, it feels like a question. With Ruby, if it's a question, it ends with a ?.

BTW, why the hell is Python sorted() and reversed() not just called sort() and reverse()?

And while I'm ranting about inconsistencies, Python my_list.sort() mutates my_list, while sorted(my_list) doesn't. In Ruby, my_list.sort returns my_list sorted, without mutating. my_list.sort!. That is consistent and concise, and the bang warns you that it is destructive.

Re:Ruby 3.2.0 Is from Another Dimension by unethical_ban on Thursday January 05, 2023 @12:27PM (#34263263)
I had to login to respond to this.

To me, the ! and ? syntax in Rugby is genius. It is a language wide self documenting tool to explain a dangerous function and a boolean, which make total sense.

Re:Ruby 3.2.0 Is from Another Dimension by Ancapistani on Wednesday January 04, 2023 @01:08PM (#34249155)
I'm definitely a Python person, having used both fairly significantly - Python about ~12y, Ruby ~3y.

One thing I think Ruby gets right is the naming convention for methods that modify the object they're called on (<obj>.<method>!) and callables in general that return a boolean (<callable>?).

My biggest gripe with Ruby is the class implementation. I find metaclasses a bit more difficult to understand in Ruby. I hate that I can't easy determine where a given method of an arbitrary object is defined.

I recall that it wasn't uncommon for popular libraries to "open up" a class that was an integral part of Rails and redefine methods, overriding the original implementation. I recall trying to figure out why the method I was calling wasn't returning the value I expected, even after reading the Rails source. Come to find out, some random library had overridden it. They'd matched the behavior of a previous Rails version, but the Rails behavior had since changed. I spent hours on that specific problem and still resent it to this day :P.

Re:Ruby 3.2.0 Is from Another Dimension by lcnPylGDnU4H9OF on Wednesday January 04, 2023 @06:05PM (#34253265)
> I hate that I can't easy determine where a given method of an arbitrary object is defined.

https://tenderlovemaking.com/2016/02/05/i-am-a-puts-debugger...

The relevant bit is under the heading:

> Iโ€™m calling a method, but I donโ€™t know where it goes

  def index
    p method(:render).source_location
    render params[:id]
  end
It sounds like this is the answer to your monkey-patching woes.

  my_object.method(:my_method).source_location # returns path/to/file:[line number]