←back to thread

511 points mootrichard | 3 comments | | HN request time: 0.002s | source
Show context
setpatchaddress ◴[] No.23990944[source]
I'm really puzzled by the decision to use a separate file for this. The stated justification ("it doesn't require changing Ruby code") doesn't make sense, and my personal experience with languages with external type specifications is strongly negative. It's an unbelievable pain to keep multiple interface files in sync over time.

`.h` files are not something to emulate! External interfaces should be generated by tools where needed.

replies(5): >>23991001 #>>23991013 #>>23991258 #>>23991289 #>>23994203 #
rattray ◴[] No.23991258[source]
FWIW, you can use inline syntax with Sorbet[0], one of the two typecheckers that will work with the RBS format (the other being Steep, which does not have inline syntax).

Here's a full example, complete with a typo, based on the example in the blog post: https://bit.ly/3hMEMSp

Here's a truncated excerpt to get the basic idea across:

    # typed: true

    class Merchant
      extend T::Sig

      sig {returns(String)}
      attr_reader :name

      sig {returns(T::Array[Employee])}
      attr_reader :employees

      sig {params(token: String, name: String).void}
      def initialize(token, name)
        @token = token
        @name = name
      end

    end
Disclaimer, I used Sorbet while I was an employee at Stripe. I found it to be a terrific typechecker. It's also just absurdly fast (most of the time).

[0] https://sorbet.org

replies(4): >>23991351 #>>23991577 #>>23992070 #>>23995882 #
1. kibibyte ◴[] No.23995882[source]
One thing I never really figured out with Sorbet is how it would work if I wanted to distribute a gem with type checked code. A typed gem would necessarily have to depend on the sorbet gem. Wouldn't this mean library users have no choice but to opt into type checks always being run in this library? (Is this why sorbet-runtime exists?)
replies(2): >>23995957 #>>23996248 #
2. vidarh ◴[] No.23995957[source]
You can sort that out easily by doing something like:

    module T
       module Sig
         def sig *args
         end
       end
       # You'd need to stub out a few more things here.
    end

    begin
      require 'sorbet-runtime'
    rescue LoadError
    end
Basically as far as what I can tell from just having briefly looked at Sorbet, you could quite easily stub out the bare minimum to allow people to choose whether to pull in the full thing or not. It'd be nice if they provided a gem that did that.
3. rattray ◴[] No.23996248[source]
Yeah, the gem would depend on sorbet-runtime, and the library author could configure sorbet to not run any checks in production if desired (or to have any errors log instead of throw).

You can configure things like this globally and/or for each method call.

Eg;

    # turn off all runtime checks
    T::Configuration.default_checked_level = :never

    # turn off runtime checks for one method
    sig {returns(String).checked(:never)}
    def foo; :wont-raise; end
Docs are here: https://sorbet.org/docs/runtime#runtime-checked-sigs

Personally if I were authoring a gem I'd leave the runtime checks on except in hot paths, so my users get quick feedback when they pass the wrong thing.

In any case, the library author can get the benefits of static and runtime typing, and their users will get nice static typing if they use sorbet. Users also get nice runtime typing for the library if the author chooses to leave it on for them. The overhead is usually small.