Hacker News new | ask | show | jobs
by freedomben 1108 days ago
It's been really great watching Ruby over the last few years. I had the privilege of having dinner with Matz several years ago near the beginning of Ruby 3.0 work. I was giving a talk about Elixir at a Ruby conference, and he was interested in things I (as a self-professed fanboy of both languages) liked better about Elixir than Ruby. We talked for quite some time, and it became very clear to me that he knew that Ruby was stagnating and wanted to make some changes to keep it relevant (without wrecking the language). He was incredibly open-minded (and nice!) and was willing to listen to anyone who had things to say.

Flash forward several years, and the amount of changes in Ruby are huge! Ruby is as fit as ever for modern development, and I'm really happy about that.

1 comments

Pattern matching alone is a huge feature and an absolute delight to use when the opportunity presents itself.

I’d love to see where Ractor goes but I worry it will remain niche, like with Refinements.

Agreed. Pattern matching and pipe operator were the two that I hoped for most.

The pipe operator implementation proposal that they team came up with was wrong though and I'm glad they didn't do it. We don't need alternate syntax for `.`, we need ability to chain arguments together in a syntactically pleasant way in a functional style so we don't have to write `first(second(third(arg)))` we can write `arg |> third() |> second() |> first` which is much cleaner and reads left to right like it should

Ruby-idiomatic pipe operator is Object#then. After a lot of design proposals and discussions it is more or less evident no solution other than method would integrate naturally with the rest of the code. So it is just `arg.then{ third(_1)}.then{ second(_1)}.then{ first(_1)}`

Would've been a bit more concise with method references, almost introduced in 2.7, but alas.

(But, well, people tend to want "something that looks like operator, preferably something that looks exactly like |>" and reject every other possibility)

This would be more elegant if there was a better way to do `&object.method(:method_name, …)`. Unbound method support has been around for a long time but converting a method call with arguments to a prod is still not simple to do… unless you start currying methods and writing obscure code.
Yes, that's what I referred to. Before 2.7, object&.:method was almost merged (or rather merged and reverted) because Matz had second thoughts about its uglyness... Which is not completely untrue, but not having a concise way for referring to a method is irritating.

That still wouldn't have solved passing additional args, so maybe { object.method_name(_1, args)} is the next best thing. Though it perceives non-atomic due to wrapping block.

This already exists to some extent, with the >> operator and lambdas.

```

first = ->(x){some code...}

second = ->(x){some code...}

third = ->(x){some code...}

(third >> second >> first).call(arg)

```

I agree it's not as clean as what you propose, but much better imo than traditional nested calls (and Haskell's `.`).

I’ve had a lot of fun with Ruby’s support for functional paradigms but that stuff is unlikely to get through code review when the status quo tends towards ‘Clean Code’ style OOP over-abstraction.

Ruby being a type 2 lisp is a fun one - creating a class and and a factory function with the same name, with argument forwarding:

    class Animal; …; end
    def Animal(…); Animal.new(…); end
Refinements would be more useful if you could expose the refinements, but currently you can't.

    module HashExts
      refine Hash do
        def symbolize_values = transform_values { _1.to_sym }
      end
    end
      
    module Test
      using HashExts
      
      def self.new_h = Hash.new
    end
      
    puts Test.new_h.symbolize_values
    # => undefined method `symbolize_values' for {}:Hash (NoMethodError)
Yeah, I feel like there was a bit of an expectation mismatch around that. `using` makes a lot more semantic sense than `include` or `extend` in a lot of cases but it didn’t play out that way and we’re still living with the unusual convention of making ‘x-able’s and writing ‘concerns’. Not to mention that they were file-scoped and not lexical in their first version so had limited utility for library devs.

As far as I know the teething issues around refinements are ironed out but they remain an obscurity.