News for hackers. Stuff that matters.
Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @11:25AM (#38405549)
Why are there so many kinds of things that can be passed to a Ruby function?
Re:"Useless Ruby sugar": Argument forwarding by yebyen on Friday November 24, 2023 @11:33AM (#38405636)
You can pass positional arguments because that's how arguments have typically been passed in the history of computing. You can pass keyword arguments because they are much less ambiguous to use when a method signature is changing; you never have any confusion about which method argument is missing.

You can pass positional and keyword args together in a way which is rigidly formalized since Ruby 3.0 because, at one point in history, you could pass a hash, you could pass positional arguments, and you could pass keyword arguments, and nobody was ever able to tell reliably what you were doing:

https://www.ruby-lang.org/en/news/2019/12/12/separation-of-p...

You can pass a block because in Ruby, a block is an object like anything else. And you can pass an anonymous block because in Ruby, the "yield" keyword is an idiom that's commonly used with anonymous blocks. The curly braces and the "do" keyword that are both common idioms in Ruby are nearly identical forms of anonymous block.

The throwaway answer to your question is that you can pass anything that is an object, and in Ruby since anything is an object, you can just pass anything! I haven't read the whole article, but I get the sense that I shouldn't read much into the clickbait headline, since it looks like this is a really thoughtful show or treatment of all the neat handy things that Ruby lets you do with various types of arguments, and not a hit piece! whew relieved

Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @11:39AM (#38405706)
I would call it a thoughtful treatment of how late versions of Ruby solve a problem that well-designed languages never have in the first place.
Re:"Useless Ruby sugar": Argument forwarding by endorphine on Friday November 24, 2023 @12:55PM (#38406443)
I intuitively expected this to get downvoted but I'd like to hear opinions of the people who downvoted this, wrt how much of this flexibility is a design flaw (or accidental complexity?) and how much it is expected given the history and evolution of the language.
Re:"Useless Ruby sugar": Argument forwarding by tetha on Friday November 24, 2023 @01:59PM (#38407001)
I didn't downvote it, but I don't like the swipe of ruby not being a well-designed language.

One thing to consider: Ruby is old. Ruby stems from a time when "Everything is an object" and "You can pass a code block to a function" are borderline revolutionary. Ruby comes from a time of very imperative PHP, C and such. Python was another language during these early days, as was perl.

And ruby has strayed into a few paths of ambiguities. Like, hash as an arg vs kw-args, blocks, references to blocks. Quite a few things are weird there. Tolerable, moving into better spaces, but certainly weird.

But at the same time, have you looked closely at Java Generics? Or, Pythons multiple inheritance? Or, Perls Object Orientation. Or, PHPs types, until recent versions. If three of us get together, we can start making fun of every language for taking a wrong step, I'm sure.

Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @02:04PM (#38407047)
If I found myself defending a language by comparison with Perl, I'd be nervous. I worked in that language for most of a decade, and there are many reasons why I refuse ever to touch it again for longer than required to write a shell oneliner.

I didn't work with Ruby for nearly as long as that, not least because I found it to share too many of the same problems. I understand why the few people who deeply appreciate it do so, and I don't really judge them for that, but a wider and less partial perspective is also needed.

Then, too, nothing here actually defends Ruby's design per se. That nothing better could be expected at the time is really as close as we get, but as I discussed in more detail on another branch of the thread, contemporaneous Javascript suffices to dispose of that claim. That there are less well designed languages than Ruby I freely grant, but that's also not much of a defense.

Re:"Useless Ruby sugar": Argument forwarding by tetha on Friday November 24, 2023 @03:07PM (#38407654)
I'm not even defending ruby too much. I used ruby for many years and it always felt somewhat off.

However, with the brevity of original comment, it feels like Ruby is getting a lot of flak for shaky design decisions.

While in reality, a lot of languages from that period had very shaky design decisions. Newer generations of languages or better versions of these languages - built upon the lessons of that period - avoid these mistakes and put the spotlight on these "obvious" design issues.

Re:"Useless Ruby sugar": Argument forwarding by vidarh on Friday November 24, 2023 @04:30PM (#38408591)
In 43 years of programming, it's by far the most readable of the several dozen languages I've used.

That I routinely can convert code from other languages and end up with something far smaller and more readable is another major plus.

That is all I need to defend its design.

Re:"Useless Ruby sugar": Argument forwarding by djur on Friday November 24, 2023 @02:44PM (#38407440)
The language didn't have keyword arguments at the time it was originally created (nor did many other languages). The use of hashes as a way of simulating them was popular at the time (I've seen the same in Perl) but it was a good idea to eventually make them a full-fledged feature. It took a while to complete that transition without causing a serious backwards-incompatible disruption. Ruby has generally favored avoiding such things, which sometimes means finding some inelegant solutions.
Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @03:13PM (#38407729)
> it was a good idea to eventually make them a full-fledged feature

Why so?

Re:"Useless Ruby sugar": Argument forwarding by vidarh on Friday November 24, 2023 @04:35PM (#38408636)
Because it provides a clearer way of enforcing calling conventions. Calling a method with the wrong keyword argument raises an error automatically. Calling a method with hash arguments the method expect replies on the method manually checking for unexpected keys. In Ruby as in other languages it was error prone.
Re:"Useless Ruby sugar": Argument forwarding by gls2ro on Saturday November 25, 2023 @03:18AM (#38412109)
Positional arguments creates a dependency on the position of the argument. And this is a cause of bugs when calling a method with the arguments in the wrong order.

Keyword arguments remove the depedency on the position.

Re:"Useless Ruby sugar": Argument forwarding by lamontcg on Friday November 24, 2023 @01:22PM (#38406669)
They didn't comment on what they think good design was so its just pretty uselessly taking a swipe at Ruby. They may be correct that languages made more recently are better designed from the start because they can work around issues that ruby hit because people largely didn't know any better (some contemporaries may have claimed to know better, but there's always people after the horse race who really did bet on the right horse). They may be starting a religious war, believing that something that ruby supports is just so clearly wrong that ruby shouldn't exist. We can't really say, but it doesn't offer any useful comment. And its really easy to say that a 28 year old language shouldn't have been developed exactly the same way, given what we know now.
Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @01:59PM (#38407002)
Javascript and Ruby are of an age, both first released in 1995. Javascript has always supported all of the use cases described here for Ruby, until very recently with exactly one syntactic convention for argument passing. If you want keyword arguments, pass an object; if you want to pass a function, pass a function.

That's simpler to understand because there is less to understand, with these capabilities composed from extant syntax rather than having been invented as one-offs that require being learned and understood as such, each hedged around with its own special cases and failures to generalize - if that were not the case, the article here under discussion and all others like it would never have needed writing in the first place.

I realize describing Javascript as "well designed" will be controversial, and certainly it has not been without its share of flaws: loose equality and IEEE 754 float behavior come most quickly to mind, along with the lack of a general conditional expression. I am comfortable with describing Javascript as better designed than Ruby, though. Certainly it is far more ergonomic.

Good engineering above all else is, as much as possible, simple: it can't help being about as complex as the domain it addresses, but any complication beyond that represents an error of design. Programming a general-purpose computer is an arbitrarily complex domain, which gives all the more point to the need for simplicity in design: the user of the tool has enough to think about already, and should insofar as possible not also be forced to manage unnecessary complexity in tooling. Under such a metric, that Ruby needs three kinds of calling conventions to accomplish what Javascript does with one is already enough to demonstrate that Ruby's design is lacking.

Re:"Useless Ruby sugar": Argument forwarding by djur on Friday November 24, 2023 @02:53PM (#38407536)
The ergonomics of passing anonymous functions in JavaScript as originally released was awful, as was passing "keyword arguments" as objects. That's why arrow functions, async/await, and object destructuring were added to the language years later. 1995 JavaScript didn't even enforce function arity!

A language that is self-evidently superior due to simplicity and ergonomics would not inspire the publication of a hugely successful book that promises to show people the "good parts" of the language. The superior language you're describing should only _have_ "good parts".

Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @03:00PM (#38407598)
This gets us a bit into the definition of "sugar", I think. Specifically, all the constructs you mention are syntactic shorthands for the same underlying concepts, and the original syntax also remains available - which is to say, those constructs actually are syntactic sugar. Ruby having three ways, in two cases, to do one thing, is not.

I'm glad you mentioned "The Good Parts"! Crockford published in 2008 and the state of the art in JS has so evolved as to make further such work mostly unnecessary, or so I infer from its more-or-less absence over the last decade or so at least. That Ruby still requires such explainers be published in 2023 seems more an argument to my point than to yours.

You're also very anxious to make the perfect the enemy of the good here, which is a surprise after the explicit disclaimer in my prior comment. Why are you asking me to defend an argument I've been at such pains to make clear I'm not advancing?

Re:"Useless Ruby sugar": Argument forwarding by djur on Friday November 24, 2023 @05:36PM (#38409157)
> the state of the art in JS has so evolved as to make further such work mostly unnecessary, or so I infer from its more-or-less absence over the last decade or so at least. That Ruby still requires such explainers be published in 2023

async/await was introduced in 2017. If you're suggesting that this required fewer "explainers" than a set of gradual changes to Ruby method call syntax, I'm afraid we're not operating under a common understanding of reality.

Re:"Useless Ruby sugar": Argument forwarding by lamontcg on Friday November 24, 2023 @07:12PM (#38409818)
Kind of funny -- if I understand this correctly -- that Javascript was descended from Scheme which has delimited continuations and yet Javascript has async/await and function coloring nonsense, while ruby has continuations and fibers and doesn't need to worry about "function coloring" or "callback hell".

(Which I don't understand very well because I was a ruby programmer for 12 years, so missed all the async/await/callback-hell nonsense entirely that everyone is so obsessive about these days)

Re:"Useless Ruby sugar": Argument forwarding by remexre on Friday November 24, 2023 @09:19PM (#38410562)
I don't believe Scheme as standardized has delimited continuations, only call/cc; it's just that Scheme implementations have often been the laboratories in which experiments on delimited control have been performed.
Re:"Useless Ruby sugar": Argument forwarding by vidarh on Friday November 24, 2023 @04:33PM (#38408617)
Simplicity is why I detest the Javascript syntax and love the Ruby syntax. I spend far more time reading code than worrying about very simple rules for how to write the arguments, and so readability matters far more.
Re:"Useless Ruby sugar": Argument forwarding by codesnik on Friday November 24, 2023 @04:33PM (#38408615)
in my opinion, Ruby (and also aforementioned perl back in it's era, but this would be pointless to defend) is one of the languages where syntax and semantics looks like they took order of magnitude more thought than most of other languages.
Re:"Useless Ruby sugar": Argument forwarding by masklinn on Friday November 24, 2023 @11:35AM (#38405650)
Assuming you're not talking about values, there's really two things which can be passed to a ruby function: normal arguments and blocks.

And arguments may be passed either positionally or by name.

Blocks are the weird part, they have special support because they're a bunch of syntactic sugar / magic, which doesn't even have to be part of the function's prototype e.g

    def foo
      yield if block_given?
    end
"yield" will invoke the implicit block, "block_given?" is a metamagic kernel method which checks if the current context was passed a block.

I haven't kept up to date with Ruby so I don't know if that style is still en vogue. The equivalent "explicit" version is

    def foo &block
        block.call if block
    end
in which the block — if passed — is reified to a Proc, which you can manipulate normally. If no block is used, then `block` will just be `nil` (as the essay notes, blocks are always optional).
Re:"Useless Ruby sugar": Argument forwarding by mdavidn on Friday November 24, 2023 @12:10PM (#38406005)
These two forms are equivalent in modern Ruby, but they weren't always. The explicit &block required a heap allocation to close over the block's local scope. This is a "reified" Proc object. The implicit block could remain on the stack, since a block never outlives the stack frame that defined it.

Fun fact: Both yield and block.call may never return. The block is free to return from its enclosing method, which effectively pops multiple frames, including foo and possibly more, off the stack.

Re:"Useless Ruby sugar": Argument forwarding by shadowbanned4 on Friday November 24, 2023 @12:47PM (#38406359)
> The block is free to return from its enclosing method, which effectively pops multiple frames, including foo and possibly more, off the stack.

As an aside, this is one of the key differences between a lambda and a proc. Last I checked, you can pass a lambda as a block, but it is implicitly converted to a proc.

Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @02:23PM (#38407235)
I'm glad you mentioned that! The existence of three distinct abstractions over the concept of function values is another good example of Ruby's flawed design.
Re:"Useless Ruby sugar": Argument forwarding by djur on Friday November 24, 2023 @02:54PM (#38407542)
Unlike JavaScript, which only has, uh, three (functions, arrow functions, and methods).
Re:"Useless Ruby sugar": Argument forwarding by throwanem on Friday November 24, 2023 @03:20PM (#38407803)
No, Javascript has functions. That arrow functions handle the "this" binding specially I'll grant as a potential design error, and certainly as a complication; to reiterate, I have not said Javascript is perfect. But classes and methods are sugar over prototype-based objects from 1995, which you are still perfectly free to write if you like.
Re:"Useless Ruby sugar": Argument forwarding by masklinn on Monday November 27, 2023 @09:44AM (#38432765)
> That arrow functions handle the "this" binding specially

It’s more the opposite, arrow functions treat `this` as a regular lexical variable, it’s normal functions which special-case `this`.

Re:"Useless Ruby sugar": Argument forwarding by vidarh on Friday November 24, 2023 @04:54PM (#38408801)
They're not three different abstractions.

The distinction between a block and a Proc is an implementation detail - an implementation can choose to always make blocks Procs (my experimental Ruby compiler does just that) and a program shouldn't be able to tell the difference.

The distinction between proc and lambda with respect to how returns are handled provides significant utility with very low added implementation complexity that for the most part work together to do what people will expect of them.

That is, the most logical reading of the block syntax is that a return will return from the function it is lexically in, so it does, while a lambda looks like a function, and acts accordingly.

If anything, to me these are prime examples of what makes Ruby a great language that values developer happiness over pointless exercises in purity.

Re:"Useless Ruby sugar": Argument forwarding by corytheboyd on Friday November 24, 2023 @11:36AM (#38405673)
It’s really just positional arguments, keyword arguments, and block, in that order, all optional.
Re:"Useless Ruby sugar": Argument forwarding by Pxtl on Friday November 24, 2023 @11:34AM (#38405643)
There's only 3.

Named args, unnamed (positional) args, and a special block. Because Ruby was basically "let's make Python but without Guido's hatred of metaprogramming", so it copied Python's *args and **kwargs and then added the block so you could make functions that look like control blocks.

To me the problem is that they're handled as 3 vars instead of 1 object that has 3 public properties.*

Re:"Useless Ruby sugar": Argument forwarding by 38 on Friday November 24, 2023 @12:44PM (#38406322)
> only

That word doesn't mean what you think it means.