Precondition functions in Kotlin - good practices
Asked Answered
M

4

23

Being a newbie Kotlin coder, I wonder, if there are some good practices or even language constructs for declaring pre-conditions in functions.

In Java I have been using Guava's Preconditions checking utilities:

https://github.com/google/guava/wiki/PreconditionsExplained

After some further investigation I came across the require function:

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/require.html

Is this what is generally used for checking preconditions on functions?

Moderate answered 16/7, 2017 at 17:14 Comment(0)
A
16

Of course. You can find all of the preconditions in Preconditions.kt. In addition to the require function, there are requireNotNull, check & checkNotNull functions.

Since the documentation describes it poorly in Kotlin, but you can see the Objects#requireNonNull documentation in jdk as further.

Checks that the specified object reference is not null. This method is designed primarily for doing parameter validation in methods and constructors.

Alaster answered 16/7, 2017 at 17:27 Comment(1)
Is this for compile safety, runtime safety?Multiphase
C
3

I use assert() and require() from the stdlib.

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/assert.html https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/require.html

Cephalothorax answered 16/7, 2017 at 19:42 Comment(3)
Hi, assert is designed for debug purpose rather than precondition.Alaster
Frankly, I don't see a difference. I prefer assert because I can also use it in the middle of a method, but ultimately the choice depends on the exception I want to get.Cephalothorax
java assert feature is disabled by default. which means assert doesn't guarentee is always enabled. so you will make your api brittle and critical. On the other hand, you can think of the assert is already existed in Kotlin, why did Kotlin introduce another one require?Alaster
S
0

Actually, 'require' appears to not be inherited - that is, if a subclass overrides a function that has a 'require' statement, the 'require' in the parent function is not enforced. A true precondition would also apply in the case of a redefinition of the inherited function, so (IMO) 'require' does not truly provide full precondition-checking functionality.

(I say "appears" because, being new to kotlin, I've learned this by a simple experiment using inheritance - and it's possible I'm wrong - e.g., there's a bug in the compiler causing incorrect behavior, or I've done something wrong in compiling/setup. I don't think this possibility is likely, though.)

Sheply answered 23/3, 2018 at 2:27 Comment(7)
If a programmer overrides a function in a subclass, it is their responsibility to reapply the precondition in the overriding function - or indeed relax it if appropriate. See en.wikipedia.org/wiki/…Cysticercus
If by "reapply", you mean re-implement, I'm afraid you misunderstood the text in the wikipedia article you referred to. Take a look at this paragraph from the same article (titled "..."): "In the presence of inheritance, the routines inherited by descendant classes (subclasses) do so with their preconditions in force. This means that any implementations or redefinitions of inherited routines also have to be written to comply with their inherited contract. Preconditions can be modified in redefined routines, but they may only be weakened."Sheply
In other words, no intervention on the part of the programmer implementing the function (or procedure) is needed or desired, unless the programmer explicitly weakens the precondition. If she/he does nothing, the same precondition as in the parent class holds.Sheply
So, what exactly do you mean by "'require' appears to not be inherited"? If you inherit a function in a subclass, that means you don't redefine that function. And if you don't redefine it, its precondition will remain intact. If you_do_ redefine it, i.e. you override it, then the quoted phrase "also have to be written to comply with their inherited contract" applies, i.e. you have to write the precondition in the overridden function.Cysticercus
@Cysticercus Inheriting a precondition means that overrides of a function automatically have that precondition, too.Lisabeth
@Lisabeth I guess this is true for languages like Ada and Eiffel, which have Design By Contract as a language feature, and preconditions form part of a function's signature. On the other hand, in Kotlin, require is nothing more than a normal function that is called as part of your function's body.Cysticercus
@Cysticercus DbC is defined to have pre/postconditions inherited. And it's an important property: it means that if your code gets handed in a subclass of what it expects, it can still rely on the conditions from the declared class because any subclass will have them, too. Kotlin's require has just assertion semantics, it's not actually DbC despite the name.Lisabeth
S
0

Yes, it seems that toolforger is right about 'require'. I just searched for "require" as a keyword at https://kotlinlang.org and couldn't find it, nor as a documented function. It appears to be undocumented (unless the doc for require is hidden somewhere I couldn't find); and, of course, that means we cannot count on it to implement the standard DBC "require" behavior, and so the logical assumption is that it is simply the equivalent to "assert" in C.

Sheply answered 1/1, 2023 at 16:55 Comment(3)
I missed voddan's answer (from years ago) when I posted, where he points to the documentation for require. So, yes, it is essentially "assert" with another name, rather than the DBC require semantics.Sheply
The documentation is at kotlinlang.org/api/latest/jvm/stdlib/kotlin/require.html. It differs from assert in that, unlike assert (which is only enabled if you put -ea on the command line), require is always enabled. The require function is just a handy and succinct way to write if (!...) throw IllegalArgumentException(...).Cysticercus
k314159: Excellent, precise clarification. Thanks.Sheply

© 2022 - 2024 — McMap. All rights reserved.