Hi! I'm currently working on an Arrow integration ...
# arrow
j
Hi! I'm currently working on an Arrow integration for #akkurate, my validation library. Currently, to run the validation, you write
validate(someDataClass)
, which returns a ValidationResult. I want my users to be able to smoothly incorporate the validation result with Arrow's typed results. Here are the current ideas I had. toEither()
Copy code
val result = validate(someDataClass)
val either: Either<ConstraintViolation, SomeDataClass> = result.toEither()

val eitherMessage = either.fold(
    ifLeft = { "Failure: $it" },
    ifRight = { "Success: $it" },
)
In case of failure,
it
is the first ConstraintViolation encountered In case of success,
it
is the value being validated toEitherNonEmptySet()
Copy code
val result = validate(someDataClass)
val either: Either<NonEmptySet<ConstraintViolation>, SomeDataClass> = result.toEitherNonEmptySet()

val eitherMessage = either.fold(
    ifLeft = { "Failure: $it" },
    ifRight = { "Success: $it" },
)
In case of failure,
it
is a
NonEmptySet<ConstraintViolation>
In case of success,
it
is the value being validated bind()
Copy code
val either: Either<NonEmptySet<ConstraintViolation>, SomeDataClass> = either {
    val result = validate(someDataClass)
    bind(result)
}

val eitherMessage = either.fold(
    ifLeft = { "Failure: $it" },
    ifRight = { "Success: $it" },
)
In case of failure,
it
is a
NonEmptySet<ConstraintViolation>
In case of success,
it
is the value being validated I'm not a frequent user of Arrow, I would really appreciate what you think about this API. One thing that already bothers me, is how
toEither
defaults to a single violation constraint (unless explicitely using
toEitherNonEmptySet
), meanwhile
bind
raises multiple violation constraints. What do you think about this?
s
given that
ValidationResult
has a
Set
of errors in case of failure..... I would expect
fun <A> ValidationResult.toEither(): Either<NonEmptySet<ConstraintViolation>, A> = TODO()
as the only function. Once you have an
Either
you can use the
either
syntax normally..... Next level would be to create your own DSL for
ValidationResult
e.g. https://arrow-kt.io/learn/typed-errors/own-error-types/
a
since Akkurate follows the idea that you can get more than one violation, I think the best option would be to make
toEither()
return
NonEmptyList<ConstraintViolation>
j
I think you're both right, and it will simplify the API 🙂
Next level would be to create your own DSL for
ValidationResult
e.g. https://arrow-kt.io/learn/typed-errors/own-error-types/
I already read the guide about creating your own DSL, but I'm not sure I see the point?
a
that
toEither
+
bind
is everything you need to integrate Akkurate
👍 1
j
what the custom DSL could bring?
a
providing a custom DSL would mean that users would be able to use the Raise DSL to create ValidationResult... however, since the point of Akkurate is to provide its own DSL, I think this would be very confusing for users
👍 1
j
great, that was also my conclusion after reading the article!
a
what I would love to see, though, is a combination of running Akkurate + bind, so I can use that DSL directlty on my Arrow Raise blocks:
Copy code
either {
  ... do something ...
  val validatedTitle = akkurate(title) {
    it.isNotEmpty() otherwise { "Missing title" }
  }
}
essentially if would amount to
Copy code
fun <A> Raise<...> akkurate(subject: A, validator: Validatable<ValueType>.() -> Unit): A = 
  Validator<A>(validator)(subject).bind()
❤️ 3
j
That's a really interesting approach, I like it 🤩 I will think of the implications if I provide this in the library, so it probably won't be available day one, but I will definitely think about it!
a
btw, if you create this bridge, please let us know so we can update the Arrow website, and mention it in the typed errors section
j
you mean on this page? https://arrow-kt.io/libraries/
a
j
Good to know, thanks! I will let you know once the bridge is released 🙂