Hacker News new | past | comments | ask | show | jobs | submit login

The fact IntelliSense and jump-to-source are supported at a very superficial level goes to show the heavy drawbacks of dynamic types.

Sorbet may fix things, but at that point, just use a language with more mature tooling around types, like Python or TypeScript.

Dynamic types offer dubious marginal benefits but bring tons of downsides. The demonstrations in this article reflect that.




I like coding in Ruby a lot more than Python or Typescript. From using the Ruby LSP in the article daily (though I am not on the team) I can say it works quite good and I have very few issues with navigating Ruby source. If I were very worried about types, going to Python or Typescript seems like not a very good solution. Python barely has more type support than Ruby, and Ruby is making a lot of gains in this area. Might as well go to an even more expressive and powerful language like F#, Haskell, Ocaml, Scala, or similar.


> Python barely has more type support than Ruby

That's not true. mypy and Pyright (the main type checkers) are very ahead of Ruby's Sorbet, and Python actually has proper ergonomic syntax to work with types, which Ruby doesn't. It's also seeing constant development to bring more powerful typing and syntax.

Also, typing has become part of the Python culture, which means most of the big libraries have type hints. It doesn't seem like that is the case with Ruby, where type hints aren't as prevalent. Even the core maintainers don't like the idea and want to keep it as dynamic as possible.


I've had the hardest time getting mypy to work well in vscode. Trying pyright with neovim now, curious how it goes.


Instead of Pyright use Based Pyright for anything that isn't Code, and in Code (not Codium) you can use Pylance instead.

https://github.com/DetachHead/basedpyright


pyright just requires the Microsoft Python extension. In my experience once you have that it works instantly.


I don't know Pyright, but is it still Python? It's probably fair to bring it as Sorbet is mentioned, if course. But you can't use Sorbet using a pure ruby interpreter, if I'm getting it correctly, and I guess it's the same for Pyright. It's that so?


Mypy/pyright aren’t interpreters. They’re basically just linters that you run against Python code to see any typing issues. I don’t mean that dismissively,they’re great tools.


Pyright and mypy are typecheckers, completely orthogonal to the interpreter. They work like linters that statically perform type checking. By default, Python's type hints are ignored at runtime (i.e. you can do `x: str = 2`, and the runtime doesn't care), but there are tools to perform runtime checks (e.g. beartype) and libraries that make use of types as metadata (e.g. dataclasses, Pydantic, FastAPI).


Ruby has practically no support in a basic tool like VS Code. (Love Ruby btw)


I've tried the VS Code(ium) Shopify Ruby LSP plugin, and it's just BAD.

Have you tried the 'solargraph' VS Code(ium) plugin? I've found it to be pretty good. If you haven't do give it a try, but do know that you need to build the YARD documentation for installed "gems" for Solargraph to not be dogshit.

As described here [0], you run 'yard gems' to build said documentation. Do note that the method of having this documentation always be generated doesn't seem to work with "gems" installed with Bundler. Very frustrating, that.

[0] <https://solargraph.org/guides/yard>


Thanks, will eventually give it a try.


Or the fact that people continue to do a lot of development in these languages would suggest that the benefits are more than marginal, and the lack of a few editor features is not such a terrible hindrance.


Strongly typed languages have a higher barrier of entry and require an engineering mindset. That's anecdotal but if I think of exceptionally competent people I've worked with on JS projects, all of them have spent time building and advocated for properly typed code bases.

The other camp "just hates it" because it "slows them down", as it seems they spend most of their time fighting the types but never get to the point where you get that huge return on investment.


I don't know, the ergonomics of the type system is not the same in all languages. A tool chain that report early useful feedbacks in a non cryptic sentences will certainly gains adoption quickly.

Unfortunately most of the time the result is at best needlessly cryptic, with zero thought about simplicity of use. Ruby has a reputation of taking care of this topic.


I've been working with types and malloc for years in C, then enter Java. No need to malloc anymore and everything worked. Great, goodbye C. Then enter Ruby, no need to write types anymore and everything worked. Great, goodbye Java.

That's the great picture. Looking into the details I've been working with Perl, JavaScript, Python plus many other less common languages. I always had a preference for languages that hide complexity away from me.

Code completion really doesn't matter much to me. I've been working for maybe ten years with an emacs package that remembered words and attempted to autocomplete with the most used suffix. It worked surprisingly well.


In my professional experience, types are a godsend for large, and/or long-running projects that have been worked on by many people over the years. They reduce complexity by informing you up-front of the shape of the data and/or objects that a function demands and produces.

If the type-checking system is decent, they also automatically catch a whole class of problems that will only show up at runtime, and may take years to surface. (Ask me about the error-handing code that detonated because it contained a typo in a Ruby class name, which was only discovered three years after it was introduced... when that code was actually exercised during an... exciting outage of a system it depended on.)


> types are a godsend for large, and/or long-running projects

Agreed. But that doesn't mean that every language needs to be statically-typed, which seems to be where we're heading nowadays.

IMO large and/or long-running projects should be written in languages with sound static type systems, not scripting languages with types tacked on. Conversely, I often work on projects which are neither large nor long-running - for those, a dynamically-typed scripting language works perfectly well.

> a typo in a Ruby class name, which was only discovered three years after it was introduced

So the code containing this typo was never tested? That's asking for trouble even if you have static typing.


> So the code containing this typo was never tested?

The code absolutely was tested. However, (obviously) not every possible path through the code was tested.

Given a long-enough timeline, you will NEVER remember to test every little thing. Given sufficient code complexity, it can be next to impossible to actually exercise every code path with hand-written tests.

That's one of the troubles with large projects written scripting languages like Ruby... you have to write an assload of tests to replace what you get for free in languages (even "loosely"-typed languages like Erlang) that have pre-runtime type-checking (whether or not it's provided by a compiler).

> Conversely, I often work on projects which are neither large nor long-running - for those, a dynamically-typed scripting language works perfectly well.

Oh yeah, for small things such languages are A-OK. I 1000% agree with that. The big problem (that you may never encounter because I bet that you're smarter than the average unending parade of Project Managers) is how often small projects are forced into becoming big projects, and then huge projects as time goes on.


I’d add to this that there’s a good reason the testing culture is so strong in ruby: you absolutely need to write tests for every last little 2-line method to make sure you did it right. With no compilation or type checking step, there’s no other way to know if your code is even valid.

Which means that IME a huge number of tests in my ruby code were doing things that a type checker does automatically: make sure that passing nil makes it return nil, making sure that passing an array does the right thing vs a string, etc etc etc.

I have very vivid memories of working in a large rails code base and having no idea whether my change would work until I actually exercised the code and realized I was completely messing up the contract that some method expected, so I had to slow down and write tests to validate my assumptions.

Fast forward to now, I work in a large Rust code base, and it seems like 99% of the time, if my code compiles, it works flawlessly the first time. So I concentrate on writing integration/functional tests, which give me a lot more bang for my buck than having to write hundreds of little unit tests. (I still write some unit tests, but the need for it is much less… the vast majority of things you’d write tests for in Ruby are things the type and borrow checkers handle for you in Rust.)


> ...there’s a good reason the testing culture is so strong in ruby:

"Strong" as in "You easily burn 10x more time writing tests as you do code... and not because it's difficult to think through how to write good tests"? If so, yes.

"Good"? Hell, no! That's a bad reason.

> ...a huge number of tests in my ruby code were doing things that a type checker does automatically...

The folks I work with demand that we don't write these tests, so they don't get written. Guess how often code detonates in production because of things a typechecker would have caught... despite the enormous volume of test code.

To be crystal clear, I totally agree with your statements in this comment. I started my "career" with C++ and I'm so damn glad I did. Had I started with Ruby and Rails, I would have come to the conclusion I was far too damn stupid for this field and left to become a lawyer.


“Good” in this context didn’t mean “this is a good situation”, but rather “if you’re using ruby, it would be very bad if you didn’t write tests”, and “bad if you don’t” can be roughly reworded as “good if you do”, at least if we’re presupposing that you have to be writing Ruby.


> Strongly typed languages have a higher barrier of entry

Agreed

> the other camp "just hates it" because it "slows them down"

I’ve no doubt there are some that fall into this category, but not everyone, not by a long shot.


Not everyone is at a point where they are greenfield picking a language for a new project. Sorbet was built by a large organization (Stripe IIRC) and is used effectively by organizations with large Rails codebases. I think Sorbet is a great way to maintain velocity on a large Ruby codebase after the initial velocity benefits of dynamic typing have ceased and the dynamic typing is actually a drain on velocity.


There is no strong evidence to back up your claims, just opinions.


> Sorbet may fix things

Sorbet is very slow for large codebases. I keep checking it from time to time, but the biggest service I'm dealing with just fails to run through the initialisation. And that's ignoring the idea that someone will have to clean up the result. Not holding my breath for it to be functional in LSP situations.


How large is large here? I'm using sorbet on fairly big project and it takes like 3 seconds to scan the entire codebase with "srb tc", and with their LSP in editor the diagnostics refresh almost immediately before I stop typing. That is, without even using Sorbet's cache


The problem is that Rails is the super power that keeps Ruby alive (in my personal opinion). I’d love to use a Typescript solution that has the power and opinionated style of Rails, but there’s nothing comparable. I think AdonisJS wants to be that, but it’s not battle-tested enough for me to feel comfortable relying on it for production projects.


It's really the other way around, Ruby is the superpower that makes Rails what it is. There are very few (if any) web frameworks comparable to Rails because Rails is only possible due to the dynamism and expressiveness provided by Ruby.


Can you provide some examples? At least from my point of view, Rails’s power comes from its opinionated convention over configuration approach and its batteries-included philosophy.

People talk about the DSLs and conciseness, but frankly those don’t make/break Rails for me.

I’m curious to know what part of Rails wouldn’t be possible in something like Javascript.


In terms of convention over configuration, Ruby's metaprogramming is crucial for the name-based class conventions that make Rails so convenient. For instance, if you have a class User with the attribute name, at runtime Rails dynamically adds methods to the User class, allowing you to do things like User.find_by_name("Alice"). Rails uses Ruby's metaprogramming capabilities to accomplish this.

The same is true for defining associations between models. Consider the following model:

   class User < ApplicationRecord
     belongs_to :organization
     scope :active, -> { where(active: true) }
   end
You mentioned that DSLs aren't important, but the DSL for defining associations is extremely convenient. Adding the belongs_to line defines numerous methods on the User class, allowing you to do things like User.last.organization. The scope line dynamically defines the active method, allowing you to call User.active, which executes the code in the provided block. There are also DSLs for defining routes and migrations, which are extremely important when using Rails.

Ruby's metaprogramming is also utilized in Rails controllers to load the correct code. For example, the index method in the UsersController knows to look for the views/users/index.html file because it can reflect on the method and the class to determine where to load the correct code using Rails' autoloader, Zeitwerk.

Ruby's open classes and monkey patching (something that should be done with extreme caution) allow ActiveSupport to add extremely useful methods to Ruby's base classes. This enables conveniences such as Date.today - 10.days or DateTime.now.beginning_of_day.

These are just a few examples that I can think of off the top of my head, but nearly every major convenience in Rails relies on the flexibility provided by Ruby. While it might be possible to reproduce many aspects of Rails in JavaScript, I don't believe you could replicate all of it with the same readability and intuitiveness that Rails offers.


>In terms of convention over configuration, Ruby's metaprogramming is crucial for the name-based class conventions that make Rails so convenient. For instance, if you have a class User with the attribute name, at runtime Rails dynamically adds methods to the User class, allowing you to do things like User.find_by_name("Alice"). Rails uses Ruby's metaprogramming capabilities to accomplish this.

This can be accomplished in statically typed languages too. For example, Java has an ORM called Cayenne that generates models based on database tables. You can get similar functionality and ensure you're not accidentally calling something like `find_by_nam`


ActiveRecord doesn't generate models based on database tables, it uses conventions on table and attribute names along with Ruby's metaprogramming capabilities to define behaviour on models automatically. From my understanding, Cayenne requires manual mapping of the database to your models, which is done via XML files that are either handwritten or generated by their GUI application and have to be regenerated on every database change. That's a far cry from the ease of use of ActiveRecord. How you value that ease of use versus your desire for static typing is up to you, but they’re not comparable from a functionality point of view.

And like I said above while you might be able to recreate some of Rails' functionality in other languages, you wouldn't be able to replicate all of it with the same fluidity and readability that you have in Rails




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: