You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
I brought this up in Slack but would like to continue the conversation here to open it to other folks that would like to participate.
The Next type is currently typealias'd to a Pair<Model, Effect<Msg>>. The usage of Pair comes from the desire to use the built in tuple types that the Kotlin language offers via generics and data class (Pair and Triple).
Unfortunately, unlike Elm's tuples which have a nice syntax for creation with parentheses (e.g. (1, 2, "a", "b")), Kotlin relies on constructors for its data classes with no short-hand replacement. To work around that, the language offers an infix functionto to aid in Pair's creation.
This leads to idiomatic Oolong code in the Update/Init functions looking somewhat like this:
val update:Update<Msg, Model> = { msg, model ->
model to none()
}
This syntax can be a little hard to decipher, especially as a novice reader of the code. It requires some knowledge of the Oolong type definitions to understand why this syntax is being used. The keyword to reads more like a mapping than a union (to me, at least), and I think there's an opportunity here to be more explicit with types and have a more readable syntax.
Describe the solution you'd like
Give an explicit type to Next and provide a more ergonomic infix operator for its creation to lean in to the Kotlin language features and tools.
Two steps to this solution:
Redefine Next to data class Next<Model, Msg>(val model: Model, val effect: Effect<Msg>)
Add a new infix function and: infix fun <Model, Msg> Model.and(effect: Effect<Msg>) = Next(this, effect)
This changes our above example to read like this:
val update:Update<Msg, Model> = { msg, model ->
model and none()
}
Advantages:
the code reads as "return the updated model and these effects", which I think is a very nice improvement
extensions on Next will not pollute the Pair type in case there were extensions that were Oolong-specific
deconstructing the Next type will have named fields instead of first and second
Cons:
lose access to any extensions on Pair
potentially breaking change to the type system
note: I'd expect that we provide a to infix for compatibility initially, but have that deprecated
@Deprecated(
message ="prefer `and` operator, `to` will be removed in a future update",
replaceWith =ReplaceWith("this.and(effect)")
)
infixfun <Model, Msg> Model.to(effect:Effect<Msg>) =Next(this, effect)
The problem that this doesn't solve is the syntax for the optional Effect case, I think ideally you'd be able to have a syntax that supports returning just the model or returning the model and effects, e.g.
val update:Update<Msg, Model> = { msg, model ->
model
}
Not sure what might be available for that solution (outside of a compiler plugin that allows for a more ergonomic tuple creation syntax)
Describe alternatives you've considered
with would be an acceptable alternative to and but it is already a reserved word in the Kotlin language
I opted against an infix operator (e.g. *) since that is not a standard Kotlin language feature and would likely be considered a bit obtuse in the way that to is today with the added negative of being less discoverable
Additional context
none
The text was updated successfully, but these errors were encountered:
I think a good first step while we consider alternatives, is to deprecate Next in favor of Pair. This is more in line with Elm using tuples and removes the unnecessary obfuscation. We may find that this clears up confusion about constructing the return type altogether. I've been experimenting with several alternatives, including a DSL.
I'll make a PR with this change so we can try it out.
Is your feature request related to a problem? Please describe.
I brought this up in Slack but would like to continue the conversation here to open it to other folks that would like to participate.
The
Next
type is currently typealias'd to aPair<Model, Effect<Msg>>
. The usage ofPair
comes from the desire to use the built in tuple types that the Kotlin language offers via generics and data class (Pair
andTriple
).Unfortunately, unlike Elm's tuples which have a nice syntax for creation with parentheses (e.g.
(1, 2, "a", "b")
), Kotlin relies on constructors for its data classes with no short-hand replacement. To work around that, the language offers an infix functionto
to aid inPair
's creation.This leads to idiomatic Oolong code in the
Update
/Init
functions looking somewhat like this:This syntax can be a little hard to decipher, especially as a novice reader of the code. It requires some knowledge of the Oolong type definitions to understand why this syntax is being used. The keyword
to
reads more like a mapping than a union (to me, at least), and I think there's an opportunity here to be more explicit with types and have a more readable syntax.Describe the solution you'd like
Give an explicit type to
Next
and provide a more ergonomic infix operator for its creation to lean in to the Kotlin language features and tools.Two steps to this solution:
Next
todata class Next<Model, Msg>(val model: Model, val effect: Effect<Msg>)
and
:infix fun <Model, Msg> Model.and(effect: Effect<Msg>) = Next(this, effect)
This changes our above example to read like this:
Advantages:
Next
will not pollute thePair
type in case there were extensions that were Oolong-specificNext
type will have named fields instead offirst
andsecond
Cons:
Pair
note: I'd expect that we provide a
to
infix for compatibility initially, but have that deprecatedThe problem that this doesn't solve is the syntax for the optional Effect case, I think ideally you'd be able to have a syntax that supports returning just the model or returning the model and effects, e.g.
Not sure what might be available for that solution (outside of a compiler plugin that allows for a more ergonomic tuple creation syntax)
Describe alternatives you've considered
with
would be an acceptable alternative toand
but it is already a reserved word in the Kotlin language*
) since that is not a standard Kotlin language feature and would likely be considered a bit obtuse in the way thatto
is today with the added negative of being less discoverableAdditional context
none
The text was updated successfully, but these errors were encountered: