Iliyan Germanov
04/07/2023, 11:17 PMPositiveInt
, NotBlankString
and other constrained primitives type in Arrow.
• `PositiveDouble`: a value class that guarantees its value is positive and finite.
• `NonNegativeDouble`: >= 0 and finite.
• The same for Int
, Long
• `NotBlankString`: guarantees that a string is not blank
• NotBlankTrimmedString
like the above but also applies trimming
• Percent
: a float in [0f, 1f]
• ...
What are your thoughts? Apologies if that's already built and I haven't seen it.
Sample implementation (incomplete):
https://github.com/Ivy-Apps/ivy-wallet/tree/multiplatform/core/src/commonMain/kotlin/ivy/core/data/primitivesPavel
04/08/2023, 8:34 AMIliyan Germanov
04/08/2023, 8:43 AMsimon.vergauwen
04/08/2023, 8:53 AMIliyan Germanov
04/08/2023, 9:09 AMCLOVIS
04/08/2023, 9:14 AMsimon.vergauwen
04/08/2023, 9:50 AMCLOVIS
04/08/2023, 10:16 AMsimon.vergauwen
04/08/2023, 10:17 AMPavel
04/08/2023, 10:17 AMsimon.vergauwen
04/08/2023, 10:18 AMRaise
. https://github.com/konform-kt/konformCLOVIS
04/08/2023, 10:19 AMplusOrThrow
and create a companion Arrow compatibility layer that declares the real operators with using Raise? This way you still get the choice of using Arrow or notCLOVIS
04/08/2023, 10:20 AMsimon.vergauwen
04/08/2023, 10:20 AMCLOVIS
04/08/2023, 10:21 AMsimon.vergauwen
04/08/2023, 10:21 AMCLOVIS
04/08/2023, 10:22 AMPavel
04/08/2023, 10:22 AMa + b
which throws/fails on integer overflow instead of giving incorrect result.CLOVIS
04/08/2023, 10:25 AM// your-lib/src/...
value class Foo(...) {
fun plusOrThrow(other: Foo): Foo
fun plusOrNull(other: Foo): Foo?
}
// your-lib-arrow/src/...
context(Raise<...>)
operator fun Foo.plus(other: Foo): Foo
This way, users who don't want to use Arrow can (but have to be explicit about how they want failures), and users who like Arrow get the nicer codebase (= safer code is simpler to write)Pavel
04/08/2023, 10:30 AMIliyan Germanov
04/08/2023, 11:52 AMNotBlankTrimmedString
will always hold a string value that isn't blank and has no leading/trailing whitespaces.
When I see:
data class Person(val firstName: NotBlankTrimmedString, val lastName: NotBlankTrimmedString)
I know that I'll have valid firsName without doing validation if my criteria is not-blank AND trimmed.
I want to be able to create those primitives in two ways:
• PositiveDouble(3.14)
(unsafe) - crashes on invalid
• PositiveDouble.fromDouble(a+b)
- returns Option<PositiveDouble> / Raise / whatever
• Also:
• Operator overloads for +, -, ... that are type safe
• .map
to map its value
• PositiveDouble.toNonNegative()
Example implementation (limited)
https://github.com/Ivy-Apps/ivy-wallet/blob/multiplatform/core/src/commonMain/kotlin/ivy/core/data/primitives/PositiveDouble.kt
Example for properties for different types:
https://github.com/Ivy-Apps/ivy-wallet/tree/multiplatform/core/src/commonTest/kotlin/ivy/core/data/primitives
Goals:
• Guarantee that type the type invariant holds
• Easy to create and use
• No overheadCLOVIS
04/08/2023, 11:54 AMCLOVIS
04/08/2023, 11:54 AM(PositiveDoubleOrThrow()
)Iliyan Germanov
04/08/2023, 11:55 AMPositiveDouble.unsafe
seems more straightforward to me
When @simon.vergauwen creates a GitHub we can have a more formal discussion there. I'm new to libraries so I'm happy with whatever process/ideas you haveCLOVIS
04/08/2023, 12:15 PMunsafe
because it doesn't communicate how it fails, and is connoted with memory safety. Probably bike shedding though.simon.vergauwen
04/08/2023, 5:24 PMIliyan Germanov
04/08/2023, 5:29 PMIliyan Germanov
04/08/2023, 5:32 PMsimon.vergauwen
04/08/2023, 5:32 PMIliyan Germanov
04/08/2023, 5:33 PMIliyan Germanov
04/08/2023, 5:36 PMimplementation("io.arrow-kt:arrow-exact:1.2.0-RC")
Looks nice! Let's see what others think, my favorite of the proposed ones is definitely Exact.simon.vergauwen
04/08/2023, 5:37 PMIliyan Germanov
04/08/2023, 5:38 PMsimon.vergauwen
04/08/2023, 5:39 PMIliyan Germanov
04/08/2023, 5:56 PMYoussef Shoaib [MOD]
04/08/2023, 9:28 PMsimon.vergauwen
04/09/2023, 8:15 AM