-
Notifications
You must be signed in to change notification settings - Fork 217
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.
end
So is it on block types.
class Foo
def each: () { (foo) -> void } -> self
end
bot
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