
Ruby's Creed - rlue
https://metaredux.com/posts/2019/04/02/ruby-s-creed.html
======
dasyatidprime
Regarding the @ positional-argument syntax: I mean, my use of Ruby dropped
considerably years ago, but from a Ruby-philosophy standpoint it looks
fantastic to me. Having to constantly make up (usually single-character
anyway) names for those parameters in map/filter chains was one of the ugliest
parts of the language, especially when there was no actually-good name for
things like temporary tuples, and the Smalltalk-derived (I think) syntax for
block parameters is so visually heavyweight: { |…| … } { |…| … } { |…| … }
where all the stuff in the || is close to useless, as opposed to just { … } {
… } { … }. Method references passed with &, while separately useful, are not a
good substitute; they're often less readable (to me) because the form of the
expression is obscured, and they break down much faster, for instance as soon
as you need any single other argument, rather than just when the block gets
complex enough that the parameter names become important for readability.

I can appreciate that it moves farther away from “requiring things to be
explicit means you get fewer accidental barriers to moving code around or
increasing/decreasing complexity”, though, as some of my recent work has been
in Java and I've had an eye for that aspect of it. But the next time I do
anything in Ruby I'll be remembering that this is there.

~~~
vbsteven
I like Kotlins solution for this. If there is only one argument in the
lambda/block and the type is clear from the context you don’t have to declare
it and you can use the ‘it’ keyword instead.

~~~
jimmychangas
Kotlin is great, but I think the "it" syntax was derived from Groovy.

~~~
zbentley
I'm not positive, but Groovy may in turn have been inspired by Perl's $_, as
in 'map { $_ + 1 } (1..10);'.

If I recall correctly, the canonical name for that parameter is 'it' as well
(though I've never met a Perl programmer that calls it that . . . er, calls it
'it' . . . er, you get the idea).

~~~
dchest
The first time I saw `it` in a similar construction was in Arc language's aif
macro:

    
    
            (mac aif (expr . body)
               `(let it ,expr
                  (if it
                      ,@(if (cddr body)
                            `(,(car body) (aif ,@(cdr body)))
                            body))))
    

HN uses it quite a lot, e.g.:

    
    
            (defop logout req
               (aif (get-user req)
                    (do (logout-user it)
                        (pr "Logged out."))
                    (pr "You were not logged in.")))

~~~
bjoli
Anaphoric macros have been used in common lisp since forever.

~~~
dchest
Thanks for the name! Here's a wikipedia article about them:
[https://en.wikipedia.org/wiki/Anaphoric_macro](https://en.wikipedia.org/wiki/Anaphoric_macro)

------
intertextuality
Allowing @1 and @2 instead of |a, b| is a horrible change to Ruby. In the ruby
tracker Matz himself states this is a compromise. So now Ruby is getting half-
baked compromises that look out of place, all to appease some people making
requests.

If the requested functionality is so pertinent, then a _proper_ solution
should be made, in line with Ruby's style. Not cryptic sigil soup with @ and
.:, etc.

If a feature exists, it will get abused down the line. I do not want to read
Ruby codebases that have @1, @2, @3, etc instead of named variables. We all
know that temporary code is permanent. Just making this syntax possible is
terrible.

I have to say I'm disappointed. I have enjoyed using Ruby for the last ~5
years but I disagree strongly with this syntax change.

~~~
kazinator
Properly used, it's just a short-hand for small expressions, where adding
formally declared parameters adds 50% or more bulk to the code.

    
    
      {|a, b| a + b}  versus {@1 + @2}
    

type of thing. Note also that a and b are not more informative than @1 and @2.

Both these examples convey one message: "I'm a function that adds two
arguments".

Here is a useful power: omit the smaller numbers:

    
    
      # TXR Lisp:
      5> (mapcar (aret @3) '((a n 1 10) (b m 2 20)))
      (1 2)
      6> (mapcar (aret @2) '((a n 1 10) (b m 2 20)))
      (n m)
    

aret: a)pply list to function, which ret)urns an expression.

Simply by using @20, we get a twenty-argument function with 19 don't-cares.

~~~
ricardobeat
Perl is still available if you want to use it.

Naming arguments “a” and “b” is widely considered bad practice either way, of
course it’s not more informative.

~~~
philwelch
So you would prefer {|dividend, divisor| dividend/divisor} over {@1/@2}?

~~~
rajangdavis
On a team, I would prefer the former over the latter.

As a single contributor that's trying to hack together an idea, the second
option is not so bad; however, it will probably need to be changed far off in
the future.

I think named block parameters are cool in the sense that they enable some
expressiveness but bad in the sense that they lose some readability. I won't
know how I truly feel until I have to maintain/read a large codebase where
they are used.

~~~
philwelch
How do you feel about the Groovy/Kotlin style that would translate (roughly
speaking):

[1,2,3].map{|n| n * 2}

to:

[1,2,3].map{it * 2}

?

It's not generalizable to multi-argument lambdas, but multi-argument lambdas
are the ones that are more important to name. (e.g. with reduce, {|memo, it|
memo += it})

~~~
vorg
The underscore is fairly pleasant to read:

    
    
      [1,2,3].map{_*2}
    

I think that's what Scala has. For multi-args, perhaps:

    
    
      [1,2,3].reduce{_1+=_2}

~~~
vidarh
Underscore is very commonly used to signifiy "I don't care about this
argument" in Ruby, so at least on it's own it'd be confusing, and _1 is a
valid local variable name, so would risk breaking existing code, though I've
personally not seen it used, so maybe it'd be an acceptable risk.

------
burlesona
Syntax is hard. In general I think that adding a simple numbered argument
access for blocks makes sense, and something like swifts $ syntax would look
pretty natural, ie:

``` books.map { $0.title } ```

In the Ruby lang discussion on this they go through a dozen different possible
syntaxes and they all have issues -- for example the $ is problematic because
Ruby currently uses these for global variables.

Even so, IMO using the `@` symbol for this will make the language harder to
learn. It's not a very nice thing to have syntax that is almost ambiguous to
the human.

``` books.map { @prefix + @1.author } ```

I teach Ruby to a lot of engineers (of all different experience levels), and
one of the nice things is that it's so easy to pick up and be productive
quickly. But there are bits where it takes some practice, and I'm not looking
forward to telling people, "The at sign means it's an instance variable. Well,
except if you're in a block and it's @1 or @2 or something, in which case it's
a positional argument." Oof.

~~~
ololobus
I absolutely agree, interference with instance variable/method alias '@' looks
awkward. For me it seems a little bit against Ruby-way.

~~~
vidarh
Instance variables can not start with a digit, so this works fine from that
perspective.

~~~
jimbokun
So another exceptional edge case to learn.

~~~
vidarh
Given how little of Ruby syntax most people know before they're able to read
and understand Ruby, I don't see that as much of a concern. "@" suggests it's
probably local of sorts, the number makes it clear it's not an instance
variable, and the absence of |somevar| in a chained block will strongly
suggest it's an argument, without having to know the precise details.

There are many additions to Ruby I don't care much for, but this is one of the
most intuitive I've seen.

------
djur
Ruby 1.9 hash literal syntax was introduced as an evolutionary step toward
keyword arguments. If the former didn't exist, the latter would be a special
syntax similar to but incompatible with the existing idiom to use a hash in
terminal argument position as keyword arguments. That is, without the ability
to treat foo(:a => 1, :b => 2) as equivalent to foo(a: 1, b: 2), you end up
with two versions of every API -- "hash kwargs" and "real kwargs". And you'd
similarly lose the ability for existing APIs to migrate to explicit keyword
arguments from hash kwargs.

Would I prefer it if Ruby had started out with Crystal's named argument
syntax? Absolutely. But Crystal had the luxury of starting from scratch
without any need for backwards compatibility.

~~~
DarkWiiPlayer
I think Rubys vararg syntax is terribly unintuitive and inconsistent though.

~~~
djur
It is, but it was also a compromise meant to maintain compatibility with
existing code. And I mentioned it specifically because the OP identified
keyword arguments as a good new feature but the new hash syntax as bad.

------
ashelmire
I agree and disagree.

The more features the language has, the harder it is to read.

And using @ for positional arguments when it’s already used for instance
variables is a questionable choice. But on the other hand, the syntax for
these blocks has always been clunky.

But Ruby is all about options. You can do things the way you want, when you
want. That’s the happiness you achieve. But it does become more difficult to
read for newcomers and devs not up on the latest updates, which is a major
sacrifice.

Some of these new features are blessings though. The safe navigation operator
saves lots of checks and I wish I had it in JavaScript and other languages
(rather than checking for a property first).

~~~
intertextuality
> Ruby is all about options

Err, is that why things like Rails are convention over configuration? I
personally would rather have consistency throughout ruby codebases than
various random solutions people have come up with.

@1 and @2 is more difficult to read, full stop. It's more difficult for
newcomers because it's more random "magic" that one has to learn, and it's
difficult for ruby devs when they read other people's code and have to discern
what @1, @2, @3 might possibly be. At least variable names give information,
if done properly.

Matz even stated this was a compromise. I think it's utterly unsatisfactory
for Ruby to just accept this as it is currently. There has to be a better
solution than @1 and @2.

~~~
kenforthewin
Ruby != Rails. I think it makes sense that the language remains flexible while
the framework is opinionated. I probably won't use @1 et al in my projects,
that's where enforcing consistency via rubocop comes into play.

~~~
intertextuality
Sure, ruby isn't rails. But a lot of tools are also opinionated (like Rubocop,
even.. or Brakeman, etc). One can always change values but there -are- default
configurations that people generally tend to go with.

Having consistency in the language is also better overall for the community.
If you read through a new codebase, having consistent patterns makes that
process significantly better.

@1 and @2 are only going to make things less readable. People will choose the
easier option and never go back to refactor it once completed. It's a horrible
change for Ruby.

------
joelbluminator
I don't necessarily agree but it's a fair argument and well written. It's
probably impossible to satisfy everyone; if Matz drops these features the
people who want them (and I'm sure they exist) will yell that the language is
stagnating compared to Python 3 and Node. If he adds them, we are adding
bloat. There is constant pressure to add more stuff to "evolve" the language,
hopefully the community steer through this pressure to the right direction.

------
undecisive
As a rubyist of 10 years, a few thoughts. I wasn't aware of these upcoming
features, but to some extent they make a lot of sense. Except... yeah, those
symbol choices.

I agree that @1, @2 etc look totally wrong, and maybe that subjective view
will change - but scope-wise, having @-variables that are nothing to do with
the current instance would utterly ruin scannability. On the other side, I
suspect Rubocop will very quickly react to outlaw it, so no big problem as far
as my code goes.

I very rarely use &method(:foo). I find it ugly, and &:foo is more useful in
98% of circumstances. Maybe I would use it if it were shorter - but .:foo
seems wrong. I feel like it would, again, be harder to scan.

That said, the more I let it sit in my brain, the less passionately I object.

> Still, I was disappointed when the safe navigation operator as introduced,
> as it basically acknowledged that it’s fine to return nil

I think this is indicative of the crux of the problem. Optimizing for
programmer happiness implies you know what programmers need. Some programmers
have no problem working with nils - we've long since accepted them, even
embraced them.

The safe navigator pattern almost gave us a way of implementing a null object
pattern with literally no work, while screaming out to the world "this method
accepts nil, so watch out". I would much prefer code that accepts nil as a
fact of life than code that denies its very existence.

I feel that "hacky code" will be well served by these changes, and I think
that "production code" will be better served by tight Rubocop rules. So,
everyone's happy!

~~~
lloeki
> I very rarely use &method(:foo). I find it ugly, and &:foo is more useful in
> 98% of circumstances. Maybe I would use it if it were shorter - but .:foo
> seems wrong. I feel like it would, again, be harder to scan.

Ever since the near-death of the hash rocket syntax have these days been
coming as you can already see the same line of thinking coming out of it.
Superficially the introduction of the symbolic hash syntax that aligns it with
yaml/js and saves a few chars was locally good for readability, yet
fundamentally it could not deprecate the hash rocket because if one of your
keys is not a literal symbol then you're toast and have to use hash rockets in
your code, which means you end up with mixed patterns throughout your code and
thus have to 1/ keep two tokenisation branches inside your head and 2/ make
decisions about the syntax to use every single time you write a hash, which
looks like small things but long term sand in a gearbox grinds it to a stop.

At some point you end up with all those little syntactic sugary things which
make sense locally but which overall makes for increasingly heavy cognitive
overload and you end up in a tar pit through normalization of deviance.

When Ruby began to take off, people said it was like Perl's heir, only
readable. Today as both a Rubyist and a former Perlist, I do long for Perl
(and violently enforce readability rules on Ruby projects I own)

------
jacobsenscott
I'll come to the defense of &. - for better or worse Ruby is mostly used for
building database backed web applications where nils are simply unavoidable
without some extreme over engineering or awkward idioms.
`user&.address&.street` is at least safer than `try` -
`user.try(:adress).try(:street)` - will not raise an error that `adress` is
not a method. You could try and apply the null object pattern, but then
`user.address.present?` is quite a rabbit hole - and frankly nil is the right
return value for a user with no address on file.

~~~
schneidmaster
Yeah, the safe navigation operator is great, and I really miss it especially
when I write JavaScript and have to do something like `foo && foo.bar &&
foo.bar.baz` instead (...which isn't even the same since it returns `false` if
something is null).

~~~
lobo_tuerto
Just use lodash for that.

Your example would become:

    
    
      // this won't throw an exception if foo is null
      _.get(foo, 'bar.baz')
    

And you can even set a default value to return if it is:
[https://lodash.com/docs/4.17.11#get](https://lodash.com/docs/4.17.11#get)

~~~
freewilly1040
The point isn't that it's an unsolvable problem, the point is that you have to
resort to clunky syntax or a 3rd party library to do this. And for something
as basic as this, there's probably a number of different libraries that solve
the same problem a slightly different way.

------
johnlinvc
It's interesting to see that languages try to get features that other
languages have.

In Swift they have position argument in block from the start

    
    
        users.map{$0.name}
    

now they want to add Ruby's &:attr feature[1]

    
    
        users.map(\.name)
    

Maybe the best feature user want is the one other languages have. Or this is
just Blub Paradox[2] in real life.

[1]: [https://github.com/apple/swift-
evolution/blob/master/proposa...](https://github.com/apple/swift-
evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md)
[2]: [http://www.paulgraham.com/avg.html](http://www.paulgraham.com/avg.html)

edit: grammar

~~~
pmontra
They both look ugly to me. Furthermore, there is a cognitive burden. There is
nothing to think about in

    
    
      users.map{|u| u.name}
    

I even use to write it more explicitly as

    
    
      users.map{|user| user.name}
    

The short forms

    
    
      users.map{&:name}
      users.map{@1.name}
    

are like "oh wow, what does that mean?" and I've been using Ruby since 2005.
And the ugliness...

~~~
ben-schaaf
I don't actually mind the syntax that much, `&` on a symbol just gives you a
proc for calling `send` on the first argument. What bothers me is the
limitations. If you're going to have special case syntax to avoid having a
useless first argument why not go all the way?

Something like this would have made a lot more sense imo:

    
    
        users.map { .name.uppercase + '3' }
        numbers.map { * 3 }

~~~
majewsky
The last one looks a lot like Haskell:

    
    
      map (* 3) numbers

------
59nadir
> In my opinion half-baked micro-optimizations add nothing, but complexity in
> the long run, and should be avoided. I’m really worried that Ruby has been
> gradually losing its way and has strayed from its creed.

It seems to me that "Optimizing for programmer happiness" is bound to end up
with these half-baked micro-optimizations. The very first example of what the
author considers the essence of Ruby is a perfect showcase of that, in my
opinion.

Without a criteria that establishes whether or not you've now optimized _more_
or _less_ for programmer happiness, your users will just create blub
fortresses that they stay in. Since the entire tagline is based on
subjectivity and the users don't have any meaningful foundational principles
to appreciate, all they have is their opinions on that feature they don't see
why they need.

------
whalesalad
I’m a huge fan of all the features this person is complaining about.

~~~
olingern
But do any of these features progress the language or provide any performance
benefits? Most read as syntactic-sugar (I understand Ruby is about developer
happiness) and unnecessary.

~~~
prophetjohn
They progress the language by adding syntactic sugar. Many Ruby programmers
aren't waiting around for Ruby to suddenly become fast. If that happened it'd
be great, but most code I write isn't performance critical, so it's okay if
they just give me a feature where i can write `user&.name` instead of `user &&
user.name`

------
wlll
Completely agreed. I find it hard to read anything but the simplest of @
positional examples, and code has to be written to be read.

I have been writing Go a lot more these days and greatly appreciate the
simplicity of language. Coming from a Perl background, and the TMTOWTDI
(There's More Than One Way To Do It) philosophy, I've seen how that can make
for clever but hard to read programs and I'd have preferred Ruby to err in the
other direction.

------
revskill
I was happy with Ruby and Rails until when i have to write my own abstraction.
(something like has_many, belongs_to in ActiveRecord).

Ruby class/metaclass things is really cumberstone to me. It's not about the
magic, it's about the complicated data flow through all the class abstractions
that push me off Ruby.

I prefer functional abstraction to class abstraction whenever i can.

~~~
mirceal
meta programming and the flexibility Ruby has around how it can be achieved
are the things that set Ruby in a league of its own.

~~~
StaticRedux
Definitely a league of it's own in difficulty of refactoring

~~~
ravenstine
That and difficulty introducing new developers to Ruby projects. When so much
metaprogramming and abstraction is used, and everyone creating their own DSLs,
developers often have to learn new languages every time they are brought on
board to a Ruby project. It basically defeats the point of "convention over
configuration" in Rails. Rails is fine on its own, but what Ruby allows people
to do creates these "elegant" messes that end up being more difficult to
learn, requiring people to become "experts". (which I suppose creates job
security)

Don't even get me started on how lots of Ruby developers don't believe in
documentation because the expressiveness of the language makes their code
"self-documenting". (i.e. their shit doesn't stink)

I actually love Ruby, but I've learned to avoid the advanced features unless
they make perfect sense for the task at hand. The Ruby culture, however, is
what caused me to appreciate JavaScript; the fact that it contains a simpler
set of tools makes the language more readable IMO, despite it being less
English-like, and I find today's JS projects much easier to understand than
almost any Ruby or Rails project of even modest scale.

~~~
mirceal
you were either burned really hard by metaprogramming gone wrong or you've
actually never seen it done properly.

there is a school of thought that says in some cases you should not shoehorn
the problem you are trying to solve into <insert your favorite programming
language in here>. In cases like that having a DSL (which does stand for
Domain Specific Language) is worth its weight in gold. Focusing on expressing
the problem in it's own domain language is beautiful. Ruby just happens to be
awesome at building DSLs.

to your point about "elegant" messes: you can create a mess whatever
tool/language you want. the language is not there as guardrails. I agree with
you that less is more and in most cases you don't need some of the
uberpowerful features, but when you do, the way you solve the problem is
absolutely beautiful. IMHO, Ruby code is the closest to code poetry that you
can get with a vanilla/for the masses programming language.

~~~
ravenstine
I've seen it done properly, it's just that the majority of the Ruby
metaprogramming I've seen is completely unnecessary. I'm sure it's God Mode to
a lot of people, and the powers of God are difficult to resist.

DSLs can be great. The problem I have with DSLs in the Ruby world is that it's
too normal to just whip up a DSL for things that don't require it. A good
example of a DSL is RSpec, which has a very specific goal in mind and is well
documented. A bad example of a DSL is one that Bob the developer created for a
Rails app at Acme Corp., which is sparsely documented because Bob is a busy
guy and there's a lot of tasks in the backlog more important to stakeholders
than documentation. Said Rails app at the end of the day serves webpages, and
somehow the business logic "required" its own language built by one or two
people who couldn't dedicate enough time and thought to the design of the DSL;
it was built _pragmatically_ , and down the road when Bob quits nobody is
going to want to touch it because the methods defined in the DSL have their
tentacles in everything. In the best case, Bob actually wrote tests just for
the DSL as well as the business application itself.

You are right in that a mass can be made using any tool. Where I disagree is
where a language can act as guardrails. Guardrails might not even be the right
term. What I do believe is that, a great deal of the time, the most powerful
tool isn't necessarily better than the simpler one. Someone learning to fly
probably shouldn't be given a fifth-generation fighter jet, as a much smaller
aircraft would allow them to fly sufficiently without the complexities I'm
sure there are in operating a military fighter jet, despite the fact that the
fighter jet can do "more". Even an experienced aviator probably doesn't need
to be flying a fighter jet for their purposes.

Ruby, IMO, is a lot like a fighter jet. Yes, it can fly from A to B, but it's
can evade radar, has a machine gun, and do maneuvers other planes can't. Other
languages might not have those other things, but that prevents less
disciplined pilots from the temptation of doing unnecessary things that can
result in mistakes. Sometimes you need a fighter jet, but most of the time
we're not at war.

Everyone's experience is different, and I'm not saying your point of view is
invalid, but I just feel different personally. I really wish people wouldn't
use Ruby like they're a fighter jet pilot all the time. As someone who
attended a coding bootcamp, I would like for bootcamps to emphasize hesitance
around writing DSLs and metaprogramming rather than pushing those concepts on
to junior developers as if they are the duct tape that applies to all
problems.

------
jsant
In “optimizing for programming happiness”, there's much more left to be
defined than ”happiness”. I think the biggest ambiguity here is ”programming”.

”Programming” can mean a lot of things, and I think Ruby still tailors too
much to the ”be able to scrap things together somewhat elegantly” meaning.

But once the project takes off, you want performance and safety. Performance
is constantly improved, but it seems safety is completely overlooked.
TypeScript & co. proved you can make a type system that doesn't compromise for
flexibility, so I think it should be at the core of the Ruby language
improvements discussions.

~~~
majewsky
I would like to have a language that has a builtin dial for strictness. The
lowest setting (for use on a REPL or when prototyping something) would use
dynamic typing with implicit coercions like e.g. JavaScript. But then, as the
safety/performance/stability of your code becomes more critical, you can turn
the dial higher and higher to get static type checking, then borrow checking,
etc.

Sort of like how the NPM guys rewrite some critical-path components in Rust,
but without having to hop to a different language. Sort of like how a lot of
JS devs move to TypeScript halfway through the project, but then again,
TypeScript can only go so far because it's shoehorned onto the existing JS,
rather than designed in from the get go.

------
DarkWiiPlayer
ah, _that_ topic... Well, for what its worth, I mostly agree with the author,
except I never felt Ruby has made me "happy" more than any other programming
language with at least some semi-decent features. Its problems make up for its
features and, at the end of the day, it has enough annoying parts to make me
angry at times.

The new features, of course, is pointless. It solves no problem, but brings
with it the typical downsides of adding a new language feature. It reinvents
the wheel, but makes it triangle-shaped, and tells you it's only meant for
crash-tests anyway.

~~~
59nadir
> Well, for what its worth, I mostly agree with the author, except I never
> felt Ruby has made me "happy" more than any other programming language with
> at least some semi-decent features.

In surveys, Ruby hasn't (to my knowledge) scored highest in developer
happiness for a very long time (if ever). Languages that don't tie themselves
to a subjective tagline like that do, though. Rust, for example, has a pretty
clear direction and mission and has some of the most excited and happy users
in every survey I've seen.

Trying to talk about developer happiness as some kind of defining
characteristic has always been a bad idea and I think, ironically, you end up
with unhappy users by using it as an ideal to make change in your language. I
think it only gets worse when the paradigm the language is built on and how it
expresses that paradigm is also susceptible to more bugs than the
alternatives.

The only real way to optimize for developer happiness is to optimize
aggressively for simplicity. The entire foundation of Ruby is a barrier to
that and it doesn't have the good tooling, interactivity or introspection of
something like Smalltalk to handle that.

------
Dirlewanger
I don't understand his problem with hash literals. Hash rockets are just ugly
and verbose and needed to go (through they're still needed for some object
types to be declared as keys).

The positional arguments I'm on-the-fence about. I enjoy them in Elixir, but
at the same time I wish it had a little more flexibility to name arguments.
And I like the clarity that named arguments provide.

The `then` alias is also a major improvement; `yield_self` is a confusing and
ugly combination of protected keywords.

~~~
jimbokun
"Hash rockets are just ugly and verbose"

Ugh, you make it sound like playing code golf and counting every character
automatically leads to the most readable code.

Replacing a two character operator with a one character operator, or whatever,
is not a significant win for developer productivity. More powerful abstraction
tools are what allow non linear productivity gains. Slightly different literal
syntax is more a bike shedding topic than anything that's going to help
programmers produce better software faster.

~~~
Dirlewanger
I contend it pretty much is an issue of bikeshedding. Still, it's less code,
and I don't really see how `{ key: 'value' }` is not preferred over `{ :key =>
'value' }`. Ok I'm done on this issue...

------
kureikain
The author starts with ` named block parameters`. But Clojure had this. I
always Ruby has similar thing. In Clojure you can do `%1` or `%2` similar to
`@1` `@2` in Ruby. So I guess the feature were inspired by Clojure. Even
Elixir has it. The author is also a Clojure developer so I found it's weird
that he hate that Ruby syntax.

However, at the same time, I totally agree that Ruby has so much more thing to
work and improve, not to worry about these thing. As a Ruby dev, I don't want
a new syntax to catch up with JavaScript where new syntax come up every weeks.

Ruby should focus more on type system, performance. Even some type hint like
PHP would be very helpful. Lots of Ruby gem kind of introduce type. Example in
Mongoid:

    
    
      class Person
        include Mongoid::Document
        field :first_name, type: String
        field :middle_name, type: String
        field :last_name, type: String
      end
    
    

I would love to have some type so we can use it directly.

Another weak point of Ruby is its module system :(. Some module system like
Python would be great where we can load thing and alias them to avoid
conflict.

~~~
lloeki
> In Clojure you can do `%1` or `%2` similar to `@1` `@2` in Ruby

I very much like the feature itself, esp. for one liners you can come up with
on a pry prompt. What I very much dislike though is the use of @ which is a
glorious hack if there is any since currently @ tokenizably resolves to
'instance variable' in many a brain (and @@ to class variable but those should
die since class variables can be implemented as instance variables of an
instance of Class which is both much more elegant and less prone to corner
cases, but I digress). In fact I'd very much be happy to use %1 as a syntax
since that would match the "%1" placeholders in strings right away. "%1" in
strings, \1 in regex for backrefs, $1 for regex groups, {%1} in blocks somehow
works as a metapattern, but reusing @1 vs @myvar is such a mismatch that it
brings a terrible cognitive dissonance (just see e.g how in [1, 2, 3].each {
@1 + @I } both @ have different scopes!).

I can see the argument coming (if it did not already happen) that "OMG this is
going to special case stuff in the parser so that the % method can be separate
from this new syntax! plus this may break existing code!" to which I reply %1
won't ever appear in the same place in the AST as a modulo operator with a
right hand integer argument and this is your job as a language implementor to
make the dev job easy, and it's crackpot anyway since that will already
special case the @ syntax in the parser. Simple is hard, bailing on
implementing the simple solution as a language implementor even if it's
internally tough is a copout.

------
peteforde
I was sad to see => aka "hashrocket" syntax go, and it still slips in
sometimes... but it is nice being able to use the same hash syntax in Ruby and
JS.

What I'm intrigued by is the author's suggestion that there's more to the
change than a relatively minor syntax change. Is there more to the story? I
always assumed that both syntaxes are functionally identical.

~~~
rlue
> What I'm intrigued by is the author's suggestion that there's more to the
> change than a relatively minor syntax change.

I don't remember him saying that about hash literals. All I caught was that he
doesn't like how it's limited to expressing only symbol-keyed hashes. Maybe I
missed something, though.

~~~
peteforde
That was exactly what I didn't pick up on, and you took for granted. I only
rarely use non-symbol keys, so it hadn't dawned on me that the new syntax was,
in fact, knee-capped.

------
olingern
Personally, even though `.then` resembles A+ promise-like syntax -- I find
that it feels more idiomatic than `yeild_self`. I remember Matz talking about
this at RubyKaigi, and I wondered how it would work in practice; however, I
enjoy that syntax much more than its predecessor.

Addressing some of the author's comments, I would agree with:

\- Endless ranges

\- The "@" syntax names.each { puts @1 }

I would love to see more dialogue on how these changes _could_ positively
affect the language. Also, if these are adopted widely, there will be the
inevitable Rubocop rule telling you that it prefers this syntax over the
"legacy." I love Rubocop, but sometimes I feel there's no end to the journey
to writing 'idomatic' ruby and the continued language sprawl definitely does
not help on this front.

------
riffraff
Shouldn't this

    
    
        h = Hash.new { @1[@2] = "Go Fish: #{@1}" }
    

Be

    
    
        h = Hash.new { @1[@2] = "Go Fish: #@1" }
    

For maximum syntax golf?

Or are positional arguments not working the same way as instance variables wrt
to interpolation?

------
jacobsenscott
I've been primarily a ruby programmer for the last 10 years. I remember when I
started to learn Ruby the "there's more than one way to do it" philosophy
really bothered me, and I thought it would cause lots of problems. But I just
haven't found that to be the case. Even though a lot of these language
additions don't add functionality they do make day to day programming more
pleasant. Maybe I just kind of think the same way as Matz.

I remember I thought &. was going to lead to loads of PHP style abuse, but I
haven't seen that. My initial reaction to the new implicit block parameters
was also "yuk" for all the reasons mentioned in the article. But I think they
will generally be used responsibly for very small blocks, where people would
typically just name their vars x, y, z anyway.

"There's more than one way to do it" did make learning a little harder, but
you spend much more time as an expert than as a beginner, so I don't think
languages should be optimized for beginners.

As for refinements, I have never used them, never seen them used, and I don't
even really remember what they are. I think they were to save us from the
evils of monkey patching. But in general the community has learned to monkey
patch fairly responsibly, and I've rarely had a problem with it, except with a
few fairly old gems.

As for new features that I think would really bring ruby to the next level -
better functional programming support, better concurrency support, and
optional typing would be fantastic (I know, hello Elixir. But I hear typespecs
in elixir are meh).

Functions are only "first class-ish" in ruby - the block/proc stuff was fairly
revolutionary to people coming from Java and C, but it is clunky compared to
most any other language with first class functions. Javascript should never do
something better than ruby.

Good concurrency primitives are also key for language adoption in 2019 - even
though simple process based concurrency is simple and safe for probably 80% to
90% of the apps out there - when people choose languages they want the one
that will handle 10,000 requests per second using 2 GB of RAM.

~~~
JohnBooty

        As for refinements, I have never used them, never 
        seen them used, and I don't even really remember 
        what they are. I think they were to save us from 
        the evils of monkey patching.
    

They're pretty cool. IMHO they could be considered a best practice whenever
you're reopening a class, whether it's for the purpose of monkey patching an
existing method or adding your own.

Rather than overriding, say, `String#upcase` on a _global_ basis you could
override it in some reduced scope, like within some specific class. This is
arguably not ideal, but I would say that it is more explicit and less
dangerous than a global monkey patch.

Or, if you have a use case for adding a bunch of new methods to `String`, you
can go ahead and add that `String#decorate_with_random_emoji` method you've
always dreamed of - but only within particular scopes, such as a particular
Rails presenter or something. I think this is often better than polluting the
`String` class globally, or having some utility class full of methods like
`MyAwesomeStringUtils.decorate_with_random_emoji(some_string)`.

In most cases I would say that these refinements belong in a mixin that
classes can explicitly opt into -- `include my_string_refinements` or
whatever.

~~~
jacobsenscott
Thanks. Maybe I'll take another look at them.

------
examancer
I learned some cool new features coming in Ruby 2.7 and I am very much looking
forward to them now.

The rest of this post is drivel, complaints, and ends with begging questions
answered in his opening bullets. How does this optimize ruby for happiness?
Flexibility and choice.

Backwards compatibility is maintained. You can write the same old ruby you
wrote before if you want to avoid change. I'm very happy to have some new
syntax tools in the toolbox.

------
int_19h
Numbered arguments for short lambdas is not a rare language feature, and of
them all, Ruby (and Perl) is exactly what I'd expect to have it.

------
ethagnawl
I like JavaScript's (old?) solution to the indexed argument problem: the
implicit `arguments` parameter. I haven't bothered looking into the rationale
for why that wasn't carried over into arrow functions, but I miss it when
debugging programs written using ES6.

I'd be interested to know if anything similar was considered during the
discussions around adding indexed arguments to Ruby.

~~~
hombre_fatal
Could you pitch an example where Javascript's `arguments` improves the code?
Especially wrt the positional arg syntax at hand?

The only use-case I've seen for `arguments` is to create confusing function
signatures with no formal arguments.

Your linter could prohibit its usage and your code would be better off.

Btw, `(...args) => args[0] + args[1]` works. No special `arguments` variable
needed. Not sure why you'd do that over `(x, y) => x + y` though.

~~~
ethagnawl
Besides debugging, I don't know that I've ever used the arguments parameter to
do anything useful. I've leaned on underscore/lodash/ramda when doing anything
involving clever involving partial application, shuffling arguments, etc. As I
mentioned, though, I like/d `arguments` (I don't write much JS these days)
because it gives you lots of debugging information with a simple call to
`console.log(arguments);` -- made even simpler courtesy of a Vim abbreviation
(`autocmd FileType javascript iabbrev adebugger console.log(arguments)`).

------
dasyatidprime
As for refinements, the use case I imagine is when you need to be defining a
method that _dispatches on the type of_ objects that are not “yours”,
especially where that dispatch plausibly needs to be extended with more types
by other code. (If it doesn't need to dispatch on type, you can just define a
function in a module and be done; if the dispatch never needs to be extended,
you can kinda do the same thing, but it's much uglier.) Serialization is the
most common case where I've run into this, where objects of different types
need to be serialized differently; indeed the [https://bugs.ruby-
lang.org/projects/ruby-trunk/wiki/Refineme...](https://bugs.ruby-
lang.org/projects/ruby-trunk/wiki/RefinementsSpec) gives “ToJSON” as an
example refinement.

A different way of handling this exists in CLOS: methods are defined on
generic functions, which are are namespaced in packages just like class names
are, but importantly, the class package and the generic package have no
pervasive special relationship: a class doesn't “own” methods. So I can
defgeneric extravagant-imperial-licentiousness:freeze and then define methods
for it on all sorts of types, and it won't clash with someone else's
jawbreakingly-simplistic-obdurate-numbness:freeze method. A consumer of either
or both methods can choose to import one of the symbols and/or refer to either
or both of them by their full names.

In Ruby, I've observed two “traditional” ways to do this: (1) add an ugly
decoration to the method name which can never be elided (which is what I did
in some internal projects, and then I added a prettier module function for
external consumption that just trampolined to that method); or, seemingly more
commonly and much worse, (2) ignore collisions, define whatever name you like
on whichever classes you like, assume that you have dominion over your
favorite short name and/or that the semantics are “obvious” and universal and
that no one will ever load a library that does it some other way on top of
yours and thereby break all the code depending on your version, and thereby,
when that sometimes happens, land the hapless integrator in the dreaded
“monkey patch hell”.

Refinements supposedly provide a better way to evade (2). I didn't get to play
with them enough to be sure that they do, and in particular ISTR this might
not actually let you have a fresh method name which can also be extended
elsewhere without requiring all consumers of the method name to be aware of
all the extension refinements, which if so seems like a disaster for serious
use. I feel like there's a better mechanism for this hiding somewhere in Ruby
design-space, but I don't know what it is.

------
kazinator
TXR Lisp envy.

    
    
      1> (mapcar (op list (cons @1 @2)) '(1 2 3) '(a b c))
      (((1 . a)) ((2 . b)) ((3 . c)))
    

[http://nongnu.org/txr/txr-manpage.html#N-038348D3](http://nongnu.org/txr/txr-
manpage.html#N-038348D3)

------
stevebmark
This is a good reminder as to why Ruby is often called "the bad parts of
Perl." I really appreciate other programming language ecosystems (almost any
modern ones besides Ruby) that have abandoned things like this as bad
practice, while Ruby continues to double down on it.

~~~
woodruffw
That's funny, I usually hear Ruby referred to as "the good parts of Perl" (and
Google searches for those phrases suggest the same[1]) -- there's no sigil
conjugation, objects are first class, and there are fewer magic
variables/idiomatic usages of magic variables. I agree with the author that
2.7's new block syntax is a step in the wrong direction (and that safe
navigation/method reference are a little uglier than they need to be), but I
think Ruby has otherwise done an exceptionally good job of taking the best
parts of Perl and combining them with the best parts of Smalltalk.

[1]: I only get 1 Google result for "the bad parts of perl" and about 1000 for
"the good parts of perl".

~~~
kenhwang
I definitely see Ruby as Perl's spiritual successor. I would say it's one of
the few languages other than Perl that can be considered "write optimized".
Ruby makes it very very easy to just write code that just works. Just, a lot
of code later you have huge monstrosity of rot that's almost impossible to
maintain; I think that happens with all large codebases, Ruby just gets there
faster.

~~~
rlue
> I definitely see Ruby as Perl's spiritual successor.

Matz has said this himself:

* "I chose the name of the language from the jewel name, influenced by Perl. Although I named Ruby rather by coincidence, I later realized that ruby comes right after pearl in several situations, including birthstones (pearl for June, ruby for July) and font sizes (Perl is 5-point, Ruby is 5.5-point). I thought that it only made sense to use Ruby as a name for a scripting language that was newer (and, hopefully, better) than Perl." ([https://lingualeo.com/tr/jungle/231625](https://lingualeo.com/tr/jungle/231625))

* "Ruby inherited the Perl philosophy of having more than one way to do the same thing. I inherited that philosophy from Larry Wall, who is my hero actually." ([https://www.artima.com/intv/ruby3.html](https://www.artima.com/intv/ruby3.html))

------
alexeiz
Looks like Tim Toady finally got his hands on Ruby.

------
coldtea
> _Here’s a list of changes and additions that I certainly never needed (or
> wanted):_

A, the classic "features before I came to use the language are nice and dandy,
features added after I've learnt it are bad" complain.

~~~
misterdoubt
It certainly reads that way. The author takes "programmer happiness" very
personally here.

