-
Notifications
You must be signed in to change notification settings - Fork 225
Writing Signatures Best Practices
void means the value returned from a method/block is expected to be discarded. For example, if the method does not expect to return something, the signature should be () -> void.
def save!
record.save_or_raise_exception # The method uses the return value for nothing.
record.reload # #reload returns self, but there is no reason/intention to do so.
endSo is it on block types.
class Foo
def each: () { (foo) -> void } -> self
endbot means it returns nothing. We recommend not writing bot.
NilClass means an instance of NilClass. We recommend using nil for more precise type checks.
bool is different from true | false. It allows to be any type to be compatible with Ruby's truth value semantics.
If you intentionally require the value to be true or false, you can write true | false.
We believe it happens not very often.
And provably it mostly appears in co-variant (out) positions.
(When you are writing true | false in contra-variant (in) positions, it might be refactored.)
See also: https://github.com/ruby/ruby-signature/issues/133 (no conclusion yet.)
RBS syntax allows to do type level computation using literal types (true, :symbol, "string", 123).
Because true & nil and true & false only returns false and other cases always returns true, we may want to write it in signatures.
class TrueClass
def &: (nil) -> false
| (false) -> false
| (untyped) -> true
end
We don't recommend writing these. For example, some type checkers, Steep at least, cannot handle this case. It may return true for a value of type String?, which may be false.
So, the general advice is:
- If you write type level optimization using literal types, add base cases using instance types (or equivalent) too.
class TrueClass
def &: (nil) -> false
| (false) -> false
| (untyped) -> bool
end