As we’ve mentioned before, Sorbet is a gradual system: it can be turned on and off at will. This means the predictions makes statically can be wrong.
That’s why Sorbet also uses runtime checks: even if a static prediction was wrong, it will get checked during runtime, making things fail loudly and immediately, rather than silently and after the fact.
In this doc we’ll answer:
- What’s the runtime effect of ruby doc runtime error a to a method?
- Why do we want to have a runtime effect?
- What are our options if we don’t want ruby doc runtime error to affect the runtime?
Adding a method signature opts that method into runtime typechecks (in addition to opting it into more static checks). In this sense, is similar to libraries for adding runtime contracts.
Concretely, adding a wraps the method defined beneath it in a new method that:
- validates the types of arguments passed in against the types in the
- calls the original method
- validates the return type of the original method against what was declared
- returns what the original method returned
In this small example, we have a method defined to take an Integer, but we’re passing an Array at the call site. When we run on our example file, sorbet-runtime raises an exception because the signature was violated.
Why have runtime checks?
Runtime checks have been invaluable when developing Sorbet and rolling it exeption error cpu 2 out of memory in large Ruby codebases like Stripe’s. Type annotations in a codebase are near useless if developers don’t trust them (consider how often YARD annotations fall out of sync with the code… 😰).
Adding a to a method is only as good as the error e5 impresora canon pixma mp140 it lets make about a codebase. Wrong sigs are actively harmful. Specifically, when s in our codebase are wrong:
- we can’t use them to find code to refactor. Sorbet will think some code paths can never be reached when they actually can.
- they’re effectively as good as out-of-date documentation, with little added benefit over just comments.
- we could never use them to make Ruby code run faster, ruby doc runtime error. In the future, we hope to use Sorbet types to make Ruby faster, ruby doc runtime error, but s that lie will actually make code slower than no types at all.
By leveraging runtime checks, we can gain lots of confidence and trust in our type annotations:
- Automated test runs become tests of our type annotations!
- Our production observability and monitoring catch bad sigs early, before they propagate false assumptions throughout a codebase.
To drive these points home, let’s look at a concrete example:
→ View on sorbet.run
In this example, reports that there were no errors statically. But if we were to run this code with would returnwe’d try to add ruby doc runtime error to it, and Ruby would raise a NoMethodError for. By adding a tothe Sorbet runtime will raise an exception before even starting to execute the method. This makes typing errors from untyped code manifest early and loudly and right at the source, rather than silently, long after a sig was added, and far removed from this line of code.
Most people are either familiar with a completely typed language (Java, Go, etc.) or a completely untyped language like Ruby; a gradual type system can be very foreign at first. Including these runtime checks by default protects typed code from untyped code, making it easier to drive adoption of types in the long run.
Changing the runtime behavior
While having runtime checks is the default, it’s possible to change the behavior of the runtime system via configuration settings. These configuration settings live in under the module within the gem.
There kernel data inpage error 0x7a two main ways to change Sorbet’s runtime:
When the runtime checks fail, what to do in response.
To change this, we use in a method signature.
Whether the runtime checks run in the first place.
To change this, we use in a method signature.
In the next sections, we’ll give some examples of how to use both.
: Changing what happens on runtime errors
By adding to a sig and registering ruby doc runtime error callback, we can change what happens when a sig check fails. For example:
We defined our own meaning for with. Without doing this, has no effect. Because of this, can be completely customized within any codebase to change what it means to fail. For example at Stripe, we use to attach team ownership information to a failure.
The handler we wrote branches on whether was provided, which means the logging behavior is opt in. This is nice because it means the default behavior is still to make problems with types fail loudly and early, rather than silently as a log. If we wanted, we could have inverted this:
With this handler, the what offers attract terrorists is to log, and we can use to opt specific sigs into raising on failure.
We haven’t depicted it here, but the handler will ruby doc runtime error an array of every argument that was provided to for this sig—specifically there’s no restriction that must be given only one arg nor that the arg is a Symbol. For more on the various handlers, see Runtime Configuration.
: Whether to check in the first place
Careful! Opting out of runtime checks can significantly degrade the trustworthiness of type signatures. Only disable the runtime after understanding the tradeoffs. See Gradual Type Checking to learn more.
In our examples above withevery method call had the runtime type checks run to determine whether the handler should be called in the first place. This comes with an overhead, and we carefully audit and monitor the performance of as a result. The overhead of these checks are usually very small.
But in some cases, especially when calling certain methods in tight loops or other latency-sensitive paths, the overhead of even doing the checks (regardless of what happens on failure) is prohibitively expensive. To handle these cases, ruby doc runtime error, Sorbet offers which declares in what environments a sig should be checked:
If is omitted on a sig, the default is. The default checked level can also be configured. For example:
Writing this will make it so that any sig which does not have a call in it will behave as if the user had written. To prevent accidental misuse, will require that this setting is changed before any is evaluated at runtime.
Note: For to work correctly, checking in tests must be enabled in every entry point into the tests. To declare that a certain entry point is a test, run:
For example, this should probably be placed as the first line of any target, as well as any other entry point to a project’s tests. If this line is absent, sigs behave as if they had been .
Even withruby doc runtime error, there is some slight runtime overhead. The block for a above a method is not evaluated until the first time that method is called. But Sorbet can only know whether a sig is or not until the block is evaluated. So even if a sig is markedSorbet will still wrap the method. The first time the method is called, Sorbet will discover the and put back the original method.
Sometimes even this tiny amount of runtime metaprogramming is unnacceptable at runtime. To completely eliminate ruby doc runtime error runtime side effects when defining a signature, replace with when annotating methods:
Method signatures are the primary way that we add static and dynamic type checking in our code. Learn the available syntax advanced features of signatures.
Learn how to change or disable Sorbet’s runtime type checks via settings and callbacks.