Skip to content
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

Support for Maps of dynamic bindings #546

Closed
LyndonGingerich opened this issue Nov 16, 2022 · 8 comments
Closed

Support for Maps of dynamic bindings #546

LyndonGingerich opened this issue Nov 16, 2022 · 8 comments

Comments

@LyndonGingerich
Copy link
Contributor

Currently, dynamic bindings are defined in lists. But lists have no way to require key uniqueness. If users could define their bindings in Map<string, string -> Binding<_,_>> instead, they could guarantee binding name uniqueness. Would this be worth implementing?

@marner2
Copy link
Collaborator

marner2 commented Nov 16, 2022

What would it look like in F#? Can you provide an example for creating a dictionary of bindings?

@LyndonGingerich
Copy link
Contributor Author

[ "GetItem", Binding.oneWay Item.get
  "Throw", Binding.cmd (failwith "oops")
  "Count", Binding.twoWay (Count.get, Msg.SetCount) ]
|> Map.ofList

Probably something like this. It would discard subsequent bindings with identical names. Of course, maybe people should receive errors when they define bindings with duplicate names. A type checker would be far superior.

@LyndonGingerich
Copy link
Contributor Author

LyndonGingerich commented Nov 16, 2022

If that's too ugly, it shouldn't be incredibly hard to write a CE to work like this instead:

Map {
  "GetItem", Binding.oneWay Item.get
  "Throw", Binding.cmd (failwith "oops")
  "Count", Binding.twoWay (Count.get, Msg.SetCount)
}

Maybe it could even do key uniqueness checking.

@TysonMN
Copy link
Member

TysonMN commented Nov 17, 2022

Currently, dynamic bindings are defined in lists. But lists have no way to require key uniqueness. If users could define their bindings in Map<string, string -> Binding<_,_>> instead, they could guarantee binding name uniqueness. Would this be worth implementing?

I don't see how this helps. In both cases, uniqueness is checked at runtime. That uniqueness is checked at runtime for the map is obvious. Less clear is that the code currently checks for uniqueness, but it does. If a duplicate is found, then it logs an error saying that the first binding will be used and the duplicate will be ignored. Then these bindings are stored in a map.

More interesting is getting this uniqueness to be enforced at compile-time. A dynamic binding can by dynamic in both the name and (what is internally called) the binding data. However, I think every binding I have ever created used a statically known name (that is, a string literal). This makes sense because the views, which also contain the binding names, are static.

So my first thought in this direction is to give the bindings via a record. The field names would be the binding names and the value for each field would be the binding data. However, this seems worse because now we lost compile-time "anti-uniqueness" of the binding data types. The must all be the same, which is enforced by using a list, and also gives good error messages when they don't match.

@TysonMN
Copy link
Member

TysonMN commented Nov 17, 2022

Maybe the static binding approach @marner2 is creating enforces both binding names uniqueness and binding data type anti-uniqueness at compile-time.

@LyndonGingerich
Copy link
Contributor Author

So my first thought in this direction is to give the bindings via a record. The field names would be the binding names and the value for each field would be the binding data. However, this seems worse because now we lost compile-time "anti-uniqueness" of the binding data types. The must all be the same, which is enforced by using a list, and also gives good error messages when they don't match.

I don't understand your objections. Is this your intended proposal?

{ GetItem: BindingData<App, 'msg, Item>
  DoThing: BindingData<App, AppMsg, 't>
  GetOtherItem: BindingData<App, 'msg, OtherItem> }

@TysonMN
Copy link
Member

TysonMN commented Nov 17, 2022

Consider a list of bindings.

let bindings : List<Binding<Model, Msg>> = [
    "binding1" |> BindingData.oneWay(fun m -> m.data1)
    "binding1" |> BindingData.oneWay(fun m -> m.data2)
]
  • The advantage is that the compiler ensures that every binding has the same type (e.g. Binding<Model, Msg>).
  • The disadvantage is that the compiler does not ensure that the binding names are unique (e.g. binding1 is a duplicate binding name).

Consider a record of bindings.

type MyBindings = {
  binding1: BindingData<Model1, Msg1>
  binding2: BindingData<Model2, Msg2>
}

Even without considering an instance of MyBindings, we can already make these conclusions.

  • The advantage is that the compiler ensures that the binding names are unique (e.g. binding1 and binding2 are different).
  • The disadvantage is that the complier does not ensure that all bindings have the same type (e.g. BindingData<Model1, Msg1> and BindingData<Model2, Msg2> are not the same).

@LyndonGingerich LyndonGingerich closed this as not planned Won't fix, can't repro, duplicate, stale Nov 17, 2022
@TysonMN
Copy link
Member

TysonMN commented Nov 18, 2022

Here is an exceedingly interesting related blog post:

CONSTRUCTIVE VS PREDICATIVE DATA by Hillel Wayne
https://www.hillelwayne.com/post/constructive/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants