Better support / recipe for Null-Pattern of none collection based stores
See original GitHub issueKey Question
How are you supposed to model nullable objects within fritz2’s store concept?
Problems
Think of selecting single items from a list, for example within our DataTable component. But there might be other situations, where you have some type T
and want to create a store of T
s combined with the situation, that you want to know, whether the store holds a value or you are forced to handle nullable values (because of the surrounding infrastucture like a single selection).
Consider a simple model
data class Person(
val id: Int,
val name: String,
val birthday: LocalDate,
)
Then you have a problem to use the sub-store mechanisms (to be more precise: the generated lenses):
// create / get a nullable store:
val store = storeOf<Person?>(null)
// some forms / tags you want to bind to a value of ``Person`` -> need a ``SubStore``
val name = store.sub(L.Person.name) // won't compile, as generated Lens is ``Lens<Person, String>``
// and not ``Lens<Person?, String>``!
// craft by hand:
val nameLens = buildLens<FinalPerson?, String>(
"name",
{ p -> p?.name ?: "" /* provide neutral representation */ },
{ p, t -> p?.copy(name= t) }
) // works, but cumbersome and bypasses the "sense" of a framework
val nameStore= store.sub(nameLens)
This is cumbersome! It could be fixed, if there would be an overloaded version of buildLens
, that would accept a neutral element for the getter and if the LensesAnnotationProcessor
would support nullable T
s.
Another option is to choose a different model approach and to integrate the Null-Pattern manually into the model itself:
data class Person(
val id: Int,
val name: String,
val birthday: LocalDate,
) {
val isNull = id == 0 // define some "null"-object based upon special data constellations
// could also add a factory function within the companion like ``newEmpty()`` or ``asNull`` or alike
}
A kind of variation would be to implement a generic container like an Optional<T>
, as other languages prefer, to support the null-pattern.
This is possible, but it bypasses the chosen way of Kotlin how to deal with null-pattern!
Imho we need a better support for this problem - whether through our framework itself or by giving a clear advice to our users, how to deal with this situation!
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
I also had problems with nullable properties and found other ways of dealing with it. It might be an alternative approach to the above proposal.
In Kotlin we have following approaches to deal with null values: Safe calls: person?.name -> if person is null, name gets null Not-Null: person!!.name -> if person is null, it will throw an exception Elvis operator: person?.name? : “” -> if person is null, we use “” for name
To prevent NPEs i think Not-Null should be avoided, but we need something like Safe Calls and Elvis Operators for Lenses.
As alternative to safe calls i use a function like this:
so we can use
For the Elvis Operator i have a function like this:
Which is basically a two way elvis operator. We can use to have a non-nullable name-substore:
Is orDefault the right name?
As I was closely involved in the current approach, I am a bit biased towards naming 😉
Should notNull and orDefault be public api or just the subs?
Question: Are there use cases of lenses without using
sub
? If not, there would be no value in provding them as public functions imho.What about
format
s? At which point they have to be applied if there is the need for both:notNull
/orDefault
combined somehow with fomrating (lenses)? Without public access, the format has to be applied before the lifting. Is that the common / only useful approach? (If not this is even worse, as you cannot rely on the “automatic” specialsub
overloads / variants in that case…