whats the difference between `require(x)` and `che...
# getting-started
u
whats the difference between
require(x)
and
check(x)
?
e
require
a precondition - throws
IllegalArgumentException
check
an invariant - throws
IllegalStateException
u
hm..what would you use to validate api response that a returned list is not empty?
e
do you think of it an an input to your program, or as a part of your system?
u
im mapping from api object to my domain object, so ...input? im not asserting the state of a system no
d
require
and
check
are both preconditions assertions. However their intent are different.
require
denotes of a functional assertion, where you verify incoming parameters. You will use
require
to verify parameters of a function or a constructor (inside an
init
block).
check
denotes a state assertion, where you verify state changes of your system. You will use
check
to verify whether a state-changing call on an object still maintains its invariants. A way to remember this is indeed the thrown exception.
u
I see the point but im having trouble mapping it onto my problem -> I have a pure function (foo.toBar()) that does the checks, and discards such responses that have broken data
m
check
is also used to see if an object is in a valid state for the operation it is trying to do (no state changed required) I wouldn't use either of these functions for transforming data from an api object to domain objects. Instead the api object should be validated as good and report a API validation error if not. That could be part of the mapper and then the mapper should report that it can throw that specific error. I see
check
and
require
as things to detect bugs in my code and not an API failure. But in general if
foo
cannot complete
toBar
based on its state, that is a
IllegalStateException
, if it cannot do it based on argument passed to
toBar
then it is an
IllegalArgumentException
.
👍 1
d
I agree with @Michael Krussel. To emphasize what's been said. Ask yourself if
foo
should really be in its current state, or whether you should have `check`ed its state sooner. If `foo`'s current state is a valid state for a
Foo
but is not conformant to what can be transformed to a
Bar
, then maybe defining
Foo::toBar
is not the right design. You could have a factory that takes `Foo`s as an argument and then can
require
that theses
Foo
have a valid shape to build a
Bar
.
u
well, its incoming data from api, so edge of the system, its checking just the inherent correctnes of the data, not against some state of the system basically checking title is not empty, etc
e
honestly sounds like you should return a custom API error
u
aint nobody got time for that, nobody will check against it anyways, system only cares it passed or not, and the logged stacktrace is the most valuable thing about this for debugging
😆 1
e
if the exception doesn't matter then just pick one and go with it, they both give you the same stacktrace
d
As it is input to your system, then it's a
require
. Maybe the constraints of your system are tighter than what's allowed in your data source.
u
yea, it's just i'd probably call this an assert in other languages; and in kotlin its 2, so I wanted to check whats the supposed semantics, since both check param and then throw
e
things such as "non-empty field" might belong in the parser anyhow, such as https://www.apollographql.com/blog/graphql-validation-using-directives (although possibly poor example as #C01A6KM1SBZ doesn't support those AFAIK)
u
true
d
We also have
assert
but then it's an
Error
, not an
Exception
... 😆 An thrown Exception is something that can happen because of external conditions. A thrown Error is something that should not happen in a program. (Error would be a panic in Rust for instance, where Exception would be handled with a Result.) And I know it's confusing because now we will have Error types which are really meant to model "normal" erroneous responses, whereas all exceptions will (ideally) be used for panics.
u
I always liked
error(..)
, but then looking inside its illegal state, so == require 😄
e
assert
behavior depends on compile-time and run-time arguments, so I don't think it's ever a good choice
u
yea.. but I like that its color highlighted haha, atleast in python it is
u
I never understood why asserts are not welcome at runtime, isnt it supposed to protect the invariants? why are there mulitple "weights" of checks
e
blob shrug
hysterical raisins historical reasons probably
it's not like Python is that different -
python -O
skips assertions. the default is just the inverse of Java
u
yea but overall, why would someone want to disable them come production
e
gottagofast
u
yea go fast as to be so far away from the original issue that the stacktrace of the crash make no sense and just hand wave 😄
d
Asserts are meant to crash/panic your program. Exceptions are meant to be caught.
v
Asserts that you need to enable with
-ea
are intended to do additional checks to find program bugs during test execution which you don't want to execute at runtime to save performance afaiu.
c
yea but overall, why would someone want to disable them come production
In the old days, software was very slow so checking repeatedly for the same things was expensive. One of the original reasons why Java has the reputation of being slow is that it checks for array indexes on each access.
assert
was meant as a way developers can have very extensive sanity checks everywhere in the program that are then disabled in production to avoid a performance impact. It's similar to how Rust will check for overflows in development but will UB in production
Nowadays, the server I'm working on spends ~10% of its time in logging statements, and I don't care, because it's fast anyway