-
Notifications
You must be signed in to change notification settings - Fork 101
Simpler, safer ViewEnvironment and ViewRegistry management. #631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
809914f
to
48b3f67
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have not finished reviewing because paused thinking about why we can't have the + operator come in via an interface. Just fiddling with the variance to see if I can get it to work a la
interface ViewEnvironmental
operator fun <T: ViewEnvironmental> ViewEnvironment.plus(value: T): ViewEnvironment =
this + ViewEnvironment(mapOf(value::class to value))
which currently doesn't compile due to the variance of value::class
@@ -1,4 +1,5 @@ | |||
@file:OptIn(WorkflowUiExperimentalApi::class) | |||
@file:Suppress("FunctionName") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which lint warning is this from and why do we have to suppress now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's complaining about the capitalized function name. We don't have to suppress it, the build was green. I just hate IDE warnings.
public infix fun ViewEnvironment.merge(registry: ViewRegistry): ViewEnvironment { | ||
val oldReg = this[ViewRegistry] | ||
|
||
val union = (oldReg.keys + registry.keys).asSequence() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, this is a dup of the merge() method above. Should call that from here.
`ViewEnvironment(Map<ViewEnvironmentKey<*>, Any>)` makes it easy to build a `ViewEnvironment` whose with values that don't match the type of the `ViewEnvironmentKey`s. We deprecate it with an eye toward making it non-public down the road. In its place we introduce `ViewEnvironment.EMPTY`, and guide people to use it and the type safe `plus` operators. We introduce a pattern of providing more `plus` operators with new environment value types. For `ViewRegistry`, in addition to the `plus` operator we provide a set of `merge` methods, which finish the long overdue job of making it simpler to mess with `ViewEnvironment` without stomping on `ViewRegistry` entries, and to override them. `EnvironmentScreen.withRegistry` and `.withEnvironment` use these. And a nit: changed the exception thrown by `ViewRegistry.plus` when duplicates are found from `IllegaleStateException` to `IllegalArgumentException` Fixes #395.
It's a fun problem space, isn't it? Really seems like I keep resisting the urge to create a general purpose mechanism for things to declare themselves mergable, b/c I strongly suspect that |
Blarg we'd be sacrificing one convenience/legibility helper for another. I think i'm rocking the boat too much here, but the idea would be to take your pattern of making the companion object the
I think i'm trying to get back to the Ok will stop trying to make this harder than it is 😊 |
48b3f67
to
55fcc3b
Compare
Latest force-push makes the tests green.
I'll add some explicit coverage for that, seems worth being formal about it. |
@steve-the-edwards PTAL, I've added a commit that adds the missing test coverage for that optimization, and adds a few more such |
9f8a150
to
e2b971c
Compare
Take care to use the existing instances when combining with empty ones, and add tests to preserve that optimization.
e2b971c
to
8d5da68
Compare
@WorkflowUiExperimentalApi | ||
public operator fun ViewRegistry.plus(binding: Entry<*>): ViewRegistry = | ||
this + ViewRegistry(binding) | ||
public infix fun ViewEnvironment.merge(registry: ViewRegistry): ViewEnvironment { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beware I think once we start having mixed typed operators things can sometimes get confusing - this is the case for CoroutineContext
which maps scope, dispatcher, name etc. in a very similar way to this. 90% of the time things just 'work' and work in a quick and satisfying way, but sometimes when reasoning about it it can get confusing how things overlap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was a bit concerned about that. But when I applied it across our app I saw a lot of boilerplate melt away, and didn't run into any problems.
I really wish the IDE was better about offering to import the .plus
method, though. Always have to paste that import in myself.
ViewEnvironment(Map<ViewEnvironmentKey<*>, Any>)
makes it easy to build aViewEnvironment
whose with values that don't match the type of theViewEnvironmentKey
s. We deprecate it with an eye toward making itnon-public down the road. In its place we introduce
ViewEnvironment.EMPTY
,and guide people to use it and the type safe
plus
operators.We introduce a pattern of providing more
plus
operators with new environmentvalue types.
For
ViewRegistry
, in addition to theplus
operator we provide a set ofmerge
methods, which finish the long overdue job of making it simpler tomess with
ViewEnvironment
without stomping onViewRegistry
entries, andto override them.
EnvironmentScreen.withRegistry
and.withEnvironment
usethese.
Fixes #395. Replaces #630, reverted due to accidental merge.