`.h` files are not something to emulate! External interfaces should be generated by tools where needed.
`.h` files are not something to emulate! External interfaces should be generated by tools where needed.
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: Working at Square, have friends at Stripe, enjoy both type checkers.
    class Merchant
      attr_reader token: String
      attr_reader name: String
      attr_reader employees: Array[Employee]
      def initialize(token: String, name: String) -> void
         # actual method body
      end
      def each_employee: () { (Employee) -> void } -> void
                   | () -> Enumerator[Employee, void]
          # actual implementation body
      end
    end
The Ruby syntax is too complicated to allow for changes like this to be backwards-compatible.
For example, `attr_reader token: String` is valid ruby today – that's the same as `attr_reader(:token => String)` which somebody might be doing in the wild, since you can override `def self.attr_reader`.
Similarly, `def initialize(token: String` clashes with the definition of keyword arguments.
I am not able to spin that into "And besides it's better to force it to be in two files anyway!", I don't think it is, but I guess it's not so easy to do different.
I dunno. Massive breakages of backward compatibility in an established language may not be better than that.
Mind you, if we could write tests in .rbs then I guess .rbs could form the basis of a new ruby syntax without breaking compatibility with old code in .rb files.
    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
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
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.