Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I had written a code contracts library for Ruby about 10 years ago [1]. I stopped working on it, mainly because it only provided runtime type checking, and I wanted static type checking. Nowadays my main language is typescript. I miss ruby, but can't give up the static typing that typescript provides. I really wish Ruby had a type system with the same level of support. VSCode has phenomenal TS support, and there's a community adding types to projects [2]. This is something I'd like for Ruby also.

> An integral part of this informality is relying on Matz’s taste and intuition for everything that affects the language’s core.

I think a more defined process would mean a better future for Ruby and Ruby developers.

- [1] https://github.com/egonschiele/contracts.ruby

- [2] https://github.com/DefinitelyTyped/DefinitelyTyped



> it only provided runtime type checking

That's the big nail in the coffin. Except for RBS and Steep, I don't know of any that does/did static type checking.

And yup, Sorbet's static type check is very partial to the point they recommend enabling runtime type checking.

Also in its usage, Sorbet needs to _evaluate_ files. Too bad if one of them was a script that included `FileUtils.rm_rf`. Ok I'm going overboard (maybe?), but Sorbet is not stable in face of code that has side effects when the file contents is evaluated.


> Also in its usage, Sorbet needs to _evaluate_ files.

Are you saying this in the context of static analysis or runtime analysis? I’m pretty sure Sorbet does not need to eval files for static analysis.

> Ok I'm going overboard (maybe?)

You are going overboard. I like both TS and Sorbet. Neither type system will protect you from running malicious code on your computer.


This:

  cat > foo.rb <<'EOF'
  module Foo
    File.open('oops', 'wb') { |f| f << "hello\n" }
  end
  EOF
  
  srb rbi init
  
  ls -1 oops # => oops
It's not even about malicious code, it's about blanket eval'ing a whole tree of rb files, which may contain anything from mistakes to legit but side-effectful code.

Neither of those have such side effects:

  rbs prototype rb foo.rb
  rbs prototype rbi foo.rb
  typeprof foo.rb



So many JS projects are switching to TS, but AFAIK the same isn't happening within Ruby, which reduces some of the type-checking benefit.

Also, this is subjective but I don't like the syntax.

> Sorbet is 100% compatible with Ruby. It type checks normal method definitions, and introduces backwards-compatible syntax for method signatures.

I would have preferred if they had introduced a compile step the way typescript does, and provided a TS-like syntax. I find the current version hard to read.


> So many JS projects are switching to TS, but AFAIK the same isn't happening within Ruby

The sheer propagation of JS might have something to do with the big push to have some kind of typing. From my own experience, if I see ruby I know I can either re-write it or find an alternative in TS/JS.

The ubiquity of JS makes it more accessible, but I'm still trying to find reasons why one would choose Ruby.. I'm always a 'right tool for the job' but I don't know what the niche is.

Edit : My pedant in me :

> compile step the way typescript doe

Typescript transpiles to JS. I don't 'believe' there is a compilation step.


> > compile step the way typescript [does]

> Typescript transpiles to JS. I don't 'believe' there is a compilation step.

This is a common misconception. Transpiling is not something distinct from compiling. "Transpiler" is just a trendy name for a certain subset of compilers. Just because it compiles to another "high level" language doesn't mean it's not a compiler.

Every "transpiler" is a compiler.

Sources:

On BIX in the 1980s, when the only implementation of C++ was Cfront, which translated to C, I asked Bjarne Stroustrup if it was a preprocessor. He told me quite emphatically, "No, Cfront is a compiler." (I don't think the term "transpiler" was in common use at that time.)

The Wikipedia article on Cfront agrees:

> Cfront was the original compiler for C++ (then known as "C with Classes") from around 1983, which converted C++ to C

https://en.wikipedia.org/wiki/Cfront

More recently, and relevant to this discussion, the TypeScript team specifically calls tsc a compiler:

> Let’s get acquainted with our new friend tsc, the TypeScript compiler.

https://www.typescriptlang.org/docs/handbook/2/basic-types.h...

In fact, if you search that page for "pil", you will find nine references to "compile" and none for "transpile".


This is probably the best comment I've ever received here.

I've always seen them as different, but as you lay out, they're all doing the same thing in the end.. Thanks for making me a little more aware!


TS has a way to attach type annotations (.d.ts files) on top of existing JS code base, thus allowing for gradual migration and relatively peaceful coexistence. Same with Python: you can add type definitions on top of existing untyped code, as a separate package. In either case, types can be provided by a third party, e.g. yourself if you want to use a particular library and it still lacks typing support.

Does Sorbet offer something comparable? That would make adoption easier.


> Does Sorbet offer something comparable?

Yes, RBI files.


The problem (as TFA points out) is that most of the available options (including "a TS-like syntax") are already valid Ruby code.

I do agree with your first point that the lack of adoption of Sorbet among library maintainers negates some of the benefit of the type system (compared to TS). Seeing all those `T.untyped`'s in generated RBI files is a little scary :D.


> So many JS projects are switching to TS, but AFAIK the same isn’t happening within Ruby

TS has been around a lot longer than Sorbet and even moreso a lot longer than RBS.


Thank you for creating contracts! I used it quite heavily in the past. While the lack of static checking was definitely a pain point, I kind of worked around it by having heavy unit test coverage for invalid types. In some ways, it functioned like a literate programming style for asserts.

Nowadays, I almost exclusively write things in TypeScript, and yes, the type system there brings so much peace of mind.

Doing a community-driven approach like DefinitelyTyped for third-party libs in Ruby seems like it'd be much harder than JS. The culture around metaprogramming and complex overloads seems like it'd be insanely difficult to type.


I’m glad you liked it! It’s great to hear from a user. The run time asserts were better than nothing. Contracts made errors easier to debug, because I knew how my app hadn’t failed. Typescript has been awesome for refactoring. If I change something, I just need to follow the type errors.


I'm genuinely curious, why do you miss Ruby, or why would you prefer it overall over TS ?

When I was playing around with ruby for any significant sized projects, I found it became unmaintainable. Granted I was most definitely using it wrong, but apart from that, I didn't see the appeal.


I used to hate Ruby.

Last year I spent 10 months alone on a Rails app. I decided to buy in. Do things the Ruby/Rails way. Read books on how to think about OO in Ruby. TDD everything.

I can’t quite say what changed. But now Ruby is my favourite language.

It is almost encourages you to write clean code but it doesn’t force you to. It lets you make mistakes. It treats you like a grown up.

TS, Java, etc. They treat you like a child who can’t be trusted to do things right.

Yes, this means you can end up with some horrifying god awful Ruby code. But it also means you can end up with some truly beautiful abstractions.

I think the very things that prevent you from creating unmaintainable messes are the things that prevent you from writing incredible pieces of software.

That’s probably why they miss Ruby


I don't mean to pick on your comment specifically, but I really dislike the notion that someone who appreciates, prefers, or relies on static types and a more strict compiler or toolchain is somehow not a grown-up.

[Edit]: Added a missing word


I don’t know that that’s GP’s assertion at all.

I feel similarly re: Java and Ruby. But I also love Rust which relies on static types and one of the strictest compilers in existence.

But there’s something I can’t quite put my finger on where—yeah—Java and Golang (in my mind) force me into a boxed-in world where I’m not trusted to make good decisions about abstractions, but Rust and Ruby encourage me to do so.


Yeah I totally get that. Not really the best framing.

A slightly better framing is they languages within stricter static types put up guardrails. They’re meant to keep you safe. Sometimes they also make it hard for you from going where you want to go.

Don’t get me wrong i like static languages too. TS is one of my favourites. My time with Java was good. Just trying to give a different perspective on Ruby


Whether you ‘are a grown up’ is a completely separate thing from whether you are being treated like a grown up.


> I think the very things that prevent you from creating unmaintainable messes are the things that prevent you from writing incredible pieces of software.

I actually can't argue with that. Thanks for a great brief breakdown.


> TS, Java, etc. They treat you like a child who can’t be trusted to do things right.

This is totally Java, but TypeScript? Practically every error can be turned off in the config or in a comment, and the type system is a veritable arsenal of powerful footguns.


Any chance I could ask for books you found especially useful in Ruby buy-in?


Sandi Metz and Avdi Grimm are the people I mostly read.

Practical Object Oriented Design in Ruby by Sandi. She has a lot of great talks on YouTube as well.


This is 100% me


My two cents:

1. 2. 3. 4. 5. standard library

6. consistency with OOP *

7. "everything is English language". I find good Ruby readable just like books **

* Ruby is the best translation of "everything is an object" imho

** evil Ruby is the Perl side of the moon, but it's easy to ignore it

> When I was playing around with ruby for any significant sized projects, I found it became unmaintainable

Ruby requires tons of discipline, as it has obscure meta-programming powers that are meant to be used for DSL libraries, while usually Ruby beginners spam them understating their make your codebase unmaintainable.


Agreed. Ruby is the epitome of “with great power comes great responsibility”.

I have inarguably written some of the absolutely most elegant solutions of my entire career in it. But without good discipline, experience, and understanding you can absolutely make a horrifying mess of unrivaled proportion.

Unfortunately when you work on real world projects where most devs are relatively junior (or otherwise inexperienced with Ruby) or on projects where there have been multiple cooks who didn’t necessarily share the same underlying mindset about the project, you end up with more of the latter than the former.

But for small, consistent teams of experienced Ruby engineers? It can be incredible.


One reason is blocks. I wish other languages had blocks. Swift has them, and it means you can write some very readable DSLs. Tbh I'm happy with Typescript, but Ruby was my language of choice for years.


I still use and love that contracts library, so thank you. Sure, it’s not the same as static typing, but for me it’s broadly better. To take a simple example, static typing can’t guarantee an argument is a natural number, as opposed to an (edit: integer).


Static typing can guarantee that if you design your static typing system to allow it. Take a look at Rust's NonZero types for example.

Languages with dependent types can do even more. Of course that is much more complicated and at some point you can only check the type at runtime.

But the idea that static type checking is worse than runtime type checking because it can't do all the checks is idiotic. You're throwing out the static benefits for no reason.

You should use static types as much as possible, and runtime checking where that isn't enough.


Thanks, I’m so glad you like it. I loved contracts 10 years ago. If Ruby was simpler language, I would have taken a stab at building static type checker.




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

Search: