https://kotlinlang.org logo
#feed
Title
# feed
b

bloder

09/02/2019, 12:43 PM
I would like to share a project that I'm working on: https://github.com/bloderxd/Jota Jota is a declarative pattern matching solution for ADTs in Kotlin, it's in beta (there's some problems to fix yet), but feedbacks are already welcome!
m

Mehdi

09/02/2019, 4:36 PM
Thanks for sharing this. I wonder how this library helping to reduce the modification and help for easier extension? could you please provide more sample?
b

bloder

09/02/2019, 5:06 PM
It's already planned to provide more real world examples using Jota, the first that I have in mind is error handling with coroutines and ADTs, but the modification is reduced by not being necessary an addition of an explicit type checking just to handle it then in a normal case we would have something like this:
Copy code
val x = either("1")
when(x) {
  is Either.Left -> when(x.a) {
    is Error.ErrorA -> "Error A"
    is Error.ErrorB -> "Error B"
  }
is Either.Right -> "Success"
}
if we add more errors cases we need to explicitly modify our function that apply all those pattern matchings to support its handling like:
Copy code
...
is Error.ErrorC -> "Error C"
...
with Jota we can transform this modification in just extension only creating new functions:
Copy code
...
x = either("1")
handleEither(x)
}

private fun handleEither(@When either: Either.Right) = println("Success")

private fun handleEither(@When either: Either.Left) {
 println("Handling Error...")
 handleError(either.a)
}

private fun handleError(@When error: Error.ErrorA) = println("Error A")

private fun handleError(@When error: Error.ErrorB) = println("Error B")
then if we have more error types we just need to create a new function handling it:
Copy code
private fun handleError(@When error: Error.ErrorC) = println("Error C")
j

jmfayard

09/03/2019, 7:35 AM
The paragraph
Motivation
is misleading, no
else ->
branch is needed in Kotlin with a sealed class
p

purfakt

09/03/2019, 9:57 AM
I find the project interesting, but I don't quite get your example in the motivation section. If you call the same method on all of these branch, why use a
when
?
b

bloder

09/03/2019, 12:33 PM
Thank you for the feedbacks! I'll update the Motivation example with a real world example, The intention there was to provide a really simple and short sample to people understand what Jota is used for in an easy and a short way, but I see maybe it's confusing.
1
d

Dico

09/03/2019, 8:46 PM
Well, I think it's cool as an example of how the arrow meta thing can be used. I don't think it's useful, I think you're exaggerating the use case. Instead of having when cases, we now have implicitly called case functions. When extending a sealed class, you now need to add a function instead of a when case. The "problem" hasn't been solved. The solution to the problem you're trying to solve is probably to use virtual functions where possible.
But it's excellent as an example compiler plugin, assuming it works.
b

bloder

09/03/2019, 9:48 PM
Thank you for the feedback, the purpose of this is to avoid modification and increase the extension, when we have a regular case with a function that has a lot of explicit type checks and we need to check one more we need to modify that function with one more checking, in the end we could have a giant function just to check types and we're breaking an important best practice principle such open closed:
Copy code
fun run(action: Action) = when(action) {
  is Action.Success -> { // handle success }
  is Action.ErrorA -> { // handle error a }
  is Action.ErrorB -> { // handle error b }
  is Action.ErrorC -> { // handle error c }
  ...
  is Action.ErrorZ -> { // handle error z }
}
With a declarative pattern matching solution this can be avoided and replaced by creating regular functions with no need to modify a created one, with that we can create smaller and uncoupled solutions:
Copy code
fun run(action: Action) = applyAction(action)

fun applyAction(@When Action.Success) {} // handle success
fun applyAction(@When Action.ErrorA) {} // handle error a
fun applyAction(@When Action.ErrorB) {} // handle error b
fun applyAction(@When Action.ErrorC) {} // handle error c
...
fun applyAction(@When Action.ErrorZ) {} // handle error z
d

Dico

09/03/2019, 10:39 PM
The difference is adding new lines of code on the class level or in a very determinable place - a new case in a when. Adding a when case is a modification the same way as adding a function.
b

bloder

09/03/2019, 11:13 PM
I understand your point about function modification x class modification but actually what I want by creating this library is avoid this
very determinable place
, and what I mean by extension is actually creating new structs to handle solutions instead of lines of code in a struct (and I understand your point about consider a function inside a class as not a struct but a simple line of code but if it's considered probably we'd have a lot of verbose and complex solutions), in a real world example we'd have verbose and big functions just to type check and call its handling, instead of separate more all responsibilities by creating shorter structs.
d

Dico

09/04/2019, 11:47 AM
Oh yeah, you can put a function anywhere in the class, I can see the advantage you're going for then