Skip to content(if available)orjump to list(if available)

Do I not like Ruby anymore? (2024)

Do I not like Ruby anymore? (2024)

45 comments

·August 26, 2025

pmkary

Back when autocompletion and stuff were only available in Visual Studio/Xcode/Other bug IDEs, I was forced to use Ruby and fell in love with it. It didn't matter what I used as my editor was Sublime. But when VSCode came and language features became democratized, I never touched a type-less language again. Why should someone opt for a language with absolutely no features where one can have autocompletion, typechecking, deep data type exploration, jumping to definitions and implementations? I really think it's a bad choice of Ruby not to care for types. And well we now have Crystal which again makes me question why Ruby? And it’s a shame no language is as beautiful as Ruby, not in features choices, design elegance, balance, beauty of the syntax, joy of programming mindset, not even in the name and logo. I wished Matz rethinked this part.

frou_dh

Static type signatures are inevitable. You can see this by how the Ruby documentation has to make up silly adhoc notation like "→ array_of_strings", "→ matchdata or nil" etc.

(Random example): https://docs.ruby-lang.org/en/3.4/String.html#method-i-lines

zarzavat

This was always true, to be honest. Statically typed languages have always been better. Free IDEs such as Eclipse have been available for a long time. Good JVM languages such as Scala have been available for a long time.

If only the Ruby ecosystem had adopted Scala instead of Ruby, with cutesy books and eccentric underscored personalities, history might have been different.

theshrike79

LSP (Language Server Protocol) was the final nail in the coffin of Emacs for me.

VSCode was "good enough" for pretty much every language with LSP at that point, I did't even bother with Jetbrains ides outside of work after that.

And when Obsidian replaced org-mode for me, I deleted my .emacs directory from my dotfiles repository.

themafia

> LSP (Language Server Protocol) was the final nail in the coffin of Emacs for me.

It was the opposite for me. Emacs + LSP + many other common conveniences all bind together so beautifully and efficiently that I can't imagine using any other IDE at this point.

javaunsafe2019

Fully agree. Had to work in the past with ruby. Loved it but type errors during runtime where a thing and therefore I would never use ruby in production again.

I use kotlin nowadays…

benrutter

I'm a python developer, and a big fan of the features with gradual typing etc. This article really highlights for me though, how python has very much changed from the language it was even 5 years ago.

Initially, the celebrated feature of python was that it allowed easy and fast development for newcomers. There was a joke a long the lines, "I learned python, it was a great weekend".

As much as I like python's type system (and wouldn't want to see them ever go way!), part of me wonders if moving into a world where hello-world can look like this, is a world where python is no longer the "lean in a weekend" language:

     from typing import Annotated
     import typer
     
     app = typer.Typer()
     
     @app.command()
     def main(
          name: Annotated[str, typer.Option("--name", "-n")],
     ) -> None:
         """Prints out 'HELLO {name}!!' (name upper cased) to the console"""
         print(f"HELLO {name:upper}!!")
     
     if __name__ == "__name__":
         app()
(obviously the example is silly, and I know this is a lot more than you need to do, hopefully you get my point though!)

pinoy420

[dead]

ckdot

Typescript is a workaround. It exists because web apps got more complex and browsers only support JavaScript. So developers need to stick to JavaScript, but they need typing, therefore TypeScript has been implemented. It’s an exception where it made sense to do so. For all other languages: if you use some dynamic language and you need typing, either wait until the language supports types natively (PHP‘s approach) or „just“ change the language. The additional complexity of an additional typing layer is huge. The complexity of TypeScript - and in general JavaScript‘s ecosystem - is incredibly huge. The biggest issue we have in software development is not that a language isn’t elegant, or you can’t write some some in 3 instead of 15 lines… the biggest problem is complexity. Developers too often forget about that. They focus on things that don’t matter. Ruby vs Python? It doesn’t make a real difference for web apps. If you want a language and ecosystem with low complexity try Go. It’s not perfect. It’s not elegant. Or PHP, which has a lot of drawbacks, but overall less complexity. I don’t say Go or PHP are the best languages out there, but you should try them to get a picture - to decide for yourself what’s important and what not.

melvinroest

This post reminds me of something.

During my first Introduction to Programming course at university, I was taught Java. One thing that I found very troubling is that it wasn't easy, or possible in many cases, to change the programming language. Sure, you can write new functions or methods or classes, but I can't change the keyword for an if-statement. I also remember the TA saying "why would you want that?" I caught myself thinking "if we can program a computer, then why can't we program a language?"

15 years later, I still have this issue a bit, except I made my peace with it. It is what it is. There are some exceptions though! Such as: Lisp, Smalltalk and similar languages. It's in part why I have worked for a company that professionally programmed in Pharo (a Smalltalk descendant [2]). I remember hacking a very crude way for runtime type checking in Pharo [1], just for fun.

I'm not a Ruby programmer, all I know is that Ruby has some things that are identical to Smalltalk. But my question to the author would be: if you long for things like keyword arguments, type hints and namespaces why don't you program it in the Ruby language yourself?

Or is that really hard, like most other languages?

[1] https://youtu.be/FeFrt-kdvms?si=vlFPIkGuVceztVuW&t=2678

[2] Fun fact, I learned about Lisp, Smalltalk and Pharo through HN! So I know most of you know but I suspect some don't.

lmm

The language is the easy part. Getting tool support for your language change is the hard part. Getting the library ecosystem to adopt it is even harder.

I think that's why extremely flexible languages have seen limited adoption - if your language is more of a language construction kit where everyone can implement their own functionality, everyone has to implement their own tool support (or, more likely, live without any) and there's a limit to how far you can go with that. The best languages find the sweet spot where they give you enough flexibility to implement most reasonable programs, but are still constrained enough that tools can understand and work with all possible code.

dale_glass

Too much change isn't good though. There's value in consistent basics. I've seen people doing things like:

    #define BEGIN {
    #define END }
because they liked Pascal, and that way lies madness.

zelphirkalt

Lets not equate silly and possibly dysfunctional string substitution macros with macros in higher level languages, which let you inspect and act according to the structure of the AST.

Ygg2

> that way lies madness.

Flashbacks to scala operator PTSD.

No. I don't want to use ++<>^^%% operator! I am not a number! I'm a man!

KolmogorovComp

Scala3 fortunately fixed those.

zelphirkalt

> I also remember the TA saying "why would you want that?"

Is a typical response of someone without the background and without the imagination. It may well be, that doing Java-only for too long robs one of both. An alternative response could have been: "What a fascinating idea! How would you apply that? / What would you do with that?"

I am happy for you, that you found the exceptions and that your picture of the computer programming world is not as incomplete and bleak as that of the TA back then.

sfn42

So your suggestion to the TA is to ask literally the exact same question but slightly different?

jibal

One question is encouraging, the other is discouraging. That matters a lot in an educational setting.

And they aren't the exact same question.

cess11

There is metaprogramming support in Java, but it's not as inviting and friendly as hygienic macros or Ruby patching. The obvious example is reflection, with which you can do a lot of bizarre things, some of which are useful sometimes. Another is annotations, which is heavily used by libraries in a way similar to how macros are used in certain Lisp like languages.

https://www.baeldung.com/java-reflection

https://www.baeldung.com/java-annotation-processing-builder

Then you've got the byte code itself, and there be dragons: <https://aphyr.com/posts/341-hexing-the-technical-interview>

While you rarely see byte code shenanigans in Java code bases, it's how some other languages on the JVM achieve things like runtime metaprogramming.

manuelfcreis

I fully agree to the points here, even as a full time ruby lover. Jumping around different languages over the past 10 years really shows staleness in Ruby as a language, even if the ecosystem tries to keep up.

The ergonomics of ruby still have me very much liking the language as it fits how I think, but there are a lot of good developments in the usual neighbors, and I see myself picking up both Python and JS ever more for small projects.

khoury

Ruby fully typed would be awesome imo, but I know that goes against a lot of the fundamentals in the language. I just like the syntax and expressiveness of it, but coming from typescript, its just such a bad DX having to work in a large Ruby codebase.

postexitus

Ruby is a joy to program in. But Python is a workhorse. Ruby is Miata MX-5. Python is Toyota Corolla.

sushibowl

I'm sort of the inverse of this author: I have always liked Python and disliked Ruby. It's true though that python has changed a lot, and it's a mixed bag IMHO. I think every language feature python has added can have a reasonable argument made for its existence, however collectively it kind of makes the language burgeon under the weight of its own complexity. "one way to do it" really hasn't been a hard goal for the language for a while.

I'm really charmed by ML style languages nowadays. I think python has built a lot of kludges to compensate for the fact that functions, assignments, loops, and conditionals are not expressions. You get comprehensions, lambdas, conditional expressions, the walrus operator... most statements have an expression equivalent now.

it seems like, initially, Guido was of the opinion that in most cases you should just write the statement and not try "to cram everything in-line," so to speak. However it can't be denied that there are cases where the in-line version just looks nice. On the other hand now you have a statement and an expression that is slightly different syntactically but equivalent semantically, and you have to learn both. Rust avoids this nicely by just making everything an expression, but you do get some semicolon-related awkwardness as a result.

zelphirkalt

I feel similar about "weight" in Python. Some people can really overdo it with the type annotations, wanting to annotate every little variable inside any procedure, even if as a human it is quite easy to infer its type and for the type checker the type is already clear. It adds so much clutter and at the end of the day I think: "Why aren't you just writing Java instead?" and that's probably where that notion originates from.

I used to be like that. When I did Java. I used to think to myself: "Oh neat! Everything has its place. interfaces, abstract classes, classes, methods, anonymous classes, ... everything fits neatly together."

That was before I learned more Python and realized: "Hey wait a moment, things that require me to write elaborate classes in Java are just a little bit of syntax in Python. For example decorators!" And slowly switched to Python.

Now it seems many Java-ers have come to Python, but without changing their mindset. Collectively they make it harder to enjoy using Python, because at workspaces they will mandate the most extreme views towards type annotations, turning Python into a Java dialect in some regards. But without the speed of Java. I have had feedback for a take-home assignment from an application process, where someone in all seriousness complained about me not using type annotations for what amounted to a single page of code(, and for using explanatory comments, when I was not given any guarantees of being able to talk with someone about the code - lol, the audacity).

Part of the problem is how people learn programming. Many people learn it at university, by using Java, and now think everything must work like Java. I mean, Java is honest about types, but it can also be annoying. Has gotten better though. But that message has not arrived yet at what I call the "Java-er mindset" when it comes to writing type annotations. In general languages or their type checkers have become quite good at inferring types.

kirurik

I am not an experienced programmer, but I liked python because of the dynamic typing, but tbh no type hints are a nightmare (as I used to use python). These days I gravitate towards using type hints unless I am using an ipynb because it looks clean, but it can be a little much, it can look quite ugly. Not every usecase needs type hints is what I've learned.

brainzap

I feel the samw, happy that Python is improving and getting more good tooling

IshKebab

Yeah Python with uv and Pyright is downright tolerable. As long as you don't care at all about performance anyway (and can guarantee that you never will in future).

wewewedxfgdf

It's the never ending "end"s that bother me about Ruby.

    class Mess
    def chaos(x)
        if x > 0
        [1,2,3].each do |i|
            case i
            when 1
            if i.odd?
                puts "odd"
            else
                puts "even"
            end
            when 2
            begin
                puts "trying"
            rescue
                puts "failed"
            end
            else
            puts "other"
            end
        end
        else
        puts "negative"
        end
    end
    end
Clear away all those ends and the program logic pops out. Much fresher!

    class Mess:
        def chaos(self, x):
            if x > 0:
                for i in [1, 2, 3]:
                    match i:
                        case 1:
                            if i % 2 == 1:
                                print("odd")
                            else:
                                print("even")
                        case 2:
                            try:
                                print("trying")
                            except:
                                print("failed")
                        case _:
                            print("other")
            else:
                print("negative")

Alifatisk

The indent in your Ruby code is a bit weird

    class Mess
      def chaos(x)
        if x > 0
          [1, 2, 3].each do |i|
            case i
            when 1
              if i.odd?
                puts "odd"
              else
                puts "even"
              end
            when 2
              begin
                puts "trying"
              rescue
                puts "failed"
              end
            else
              puts "other"
            end
          end
        else
          puts "negative"
        end
      end
    end

I would have done it this way instead

    class Mess
      def chaos(x)
        if x > 0
          [1, 2, 3].each do |i|
            case i
            when 1
              puts i.odd? ? "odd" : "even"
            when 2
              puts "trying"
            else
              puts "other"
            end
          end
        else
          puts "negative"
        end
      end
    end
Or if you allow me to create a separate private method

    class Mess
      def chaos(x)
        return puts "negative" unless x > 0
    
        [1, 2, 3].each { |i| handle_item(i) }
      end

      private
      def handle_item(i)
        case i
        when 1 then puts(i.odd? ? "odd" : "even")
        when 2 then puts "trying"
        else        puts "other"
        end
      end
    end

devoutsalsa

I'd love Python if it weren't for whitespace. I wanna cut/paste code into a REPL, and Python makes that difficult.

null

[deleted]

PaulRobinson

I mean, that's a horrific piece of Ruby that doesn't do much, and you've not indented it properly.

Of course you can get all this down to a single line with ; demarcation.

And your `.each` could use `{ ... }` syntax, just like C or Java or... you know, everything else.

But sure, whitespace is better, or whatever it is you prefer.

ZephyrBlu

I'm confused by this post because I think Sorbet satisfies basically all the things the author wants, and my experience with Sorbet has been really good!

schappim

What looks like stagnation to Steen is actually [1] Matz’s remarkable foresight that provided stability and developer happiness.

Steen’s not wrong that Python evolved and Ruby moved slower, but he’s wrong to call Ruby stagnant or irrelevant. Just think what we've enjoyed in recent times: YJIT and MJIT massively improved runtime performance, ractors, the various type system efforts (RBS/Sorbet etc) that give gradual typing without cluttering the language etc.

Ruby’s priorities (ergonomics, DSLs, stability) are different[2] from Python’s (standardisation, academia/data). It’s a matter of taste and domain, not superiority.

[1] I'm stealing a point DHH made on Lex's podcast. https://www.youtube.com/watch?v=vagyIcmIGOQ

[2] I'm once again parroting DHH/Matz

drob518

My reaction to that part of the post was, “Well, it seems like Python needed to evolve while Ruby was better-designed from the beginning. That’s a failing of Python, not of Ruby.” Language stability is a good thing, which is why I prefer Clojure myself. I know enough Python and Ruby to be dangerous. I’m certainly no expert in either one. That said, Python always struck me as a bit of a hack, but people seemed to resonate with the “indentation is significant” syntax, whereas Ruby felt like it was better designed, taking “everything is an object” to its natural conclusion, similar to Smalltalk, but suffering from performance issues because that means lots of more heavyweight message dispatch.

nurettin

Ruby has a unified interface for select/map/reduce over all containers. They do lazy calculations if specified. You can chain expressions simply by appending them at the end without scrolling to the back of the expression. That is objectively better than lisp and python.

Sure, you can always rewrite to match that style with macros in lisp and generators in python, but they weren't meant to be used that way.

Sad thing about ruby is how they failed to do typing. I love python's typing module. I think it is the single best thing about python and I wouldn't touch python with a pole if it didn't have that module.