What I would like in Ruby 3

Ruby development is hurtling along these days. In 2012 1.9 finally became the norm, and in 2013 we got both 2.0 and 2.1. All of these versions brought small but steady feature improvements.

Here are some thoughts on how I would like the language to change, possibly appropriate for Ruby 3 or Ruby 4.

Methods consistently as first-class objects

Ruby has fantastic support for anonymous functions and closures. But they have some problems that I think can be improved to make them more intuitive and consistent.

procs — lambda cares about arity, proc doesn't. lambda doesn't take over the return value of the outer method, proc does. I guess this simply means that procs are a special-purpose construct (I don't think one is "higher-level" than the other, as neither can be used to implement the other, right?). What are procs useful for, and what is their history? I don't know. At the very least I think we should stop mentioning procs alongside lambdas in guides and documentation. As far as I'm concerned they could be removed from the language, or maybe moved into a gem with more description of what they are useful for, or maybe their functionality should be expanded (could they becomes Erlang processes?) .

syntax for methods objects — if object foo has method bar, in order to get the method as a lambda that can be passed around or inspected, one must invoke foo.method(:bar). I would prefer that this instead be done javascript style: foo.method returns the method object, foo.method(...) invokes the method.

invocation syntax for lambdas — If we have the above change, now we can also simplify the invocation syntax for lambdas. If foo is a lambda, it is called with foo.call(...). I would prefer it simply be foo(...).

return value of def — This used to be nil, in ruby 2.1 it became a symbol representing the method name. I think it should be the method object.

syntax for passing a lambda as a block — currently if you have method mymethod which take a block, and lambda mylambda which has the same arity as the block which mymethod expects, you can pass mylambda as the block like so: mymethod &mylambda. I think we should not need the &. Methods which accept blocks should just be methods which accept lambdas, and the block syntax should just be syntactic sugar. However, the limitation to this idea is that if there is a method which both...

accepts optional lambdas as arguments (to compose them into other structures, invoke them conditionally, etc.)

has an optional block

...then it would be possible to have an ambiguous invocation. But I bet there could be easy enough intelligent assumptions here, along the same lines as how ruby currently handles an options hash as the final argument (I haven't thought this through completely thought, maybe it's impossible to support all cases).

::Foo should mean "get top-level Foo, and if there isn't one, blow up. Do not go looking for it somewhere else."

Foo::Bar should mean "get the constant Bar which is inside the namespace Foo, and if there isn't one, blow up. Do not go looking for it somewhere else."

I haven't done a deep dive into the reasons for Ruby's current behavior so maybe what I propose will introduce new problems.

more explicit DSL support

lisp and scheme have syntactic macros. You have the ability to create DSLs with arbitrary syntax. Ruby has amazing metaprogramming and lambda/closure/block support, but the DSLs still have to be tied to the same level of abstraction as the rest of the language (methods and symbols). It would be great to be able to define DSLs which have completely different symbols and grammar. Consider a Gemfile:

In short, Gemfiles are all about gems and groups, so let those things be first-class syntactic constructs. This example isn't great because a Gemfile is already a standalone file, so it kind of just seems like I'm defining a better yml or something. Consider the state_machine DSL:

Now events and states are first-class citizens in the state_machine DSL syntax. Also I'm using → to denote transition. Crazy!

More control flow / concurrency constructs?

For this one I'm not sure what should be in the core language, std lib, or stay in 3rd-party land. But it would be nice to see heavily-used constructs become first-class citizens in Ruby, in the same way that case is syntactic sugar for a common use of if/elsif/else. One clear candidate is state machines. Others might be concurrency constructs like those provided by the concurrent-ruby project.