Updownquark / Quick

Quark's User Interface Creation Kit
0 stars 0 forks source link

Implement functional reactive pattern in models #55

Closed Updownquark closed 9 years ago

Updownquark commented 10 years ago

Make an Observable interface that has a type, a value and the ability to add listeners. Make these composable. MuisModelValue should extend this. From muis xml, the user should be able to specify expressions that result in a composed observable that depends on many simple ones whose sources maybe model values and maybe attributes, styles, or other element properties. When any one of the sources change, the listeners fire through to the composed observable, which triggers the attribute change. This will involve re-implementing the model value parser and implementing observables for attributes, styles, etc.

Updownquark commented 10 years ago

Need to:

  1. Change muis models to deal with observables instead of MuisModelValue (not sure yet if that interface should go away or should extends Observable.
  2. Implement observables for
    • Attributes
    • Bounds properties
    • Parent
    • Maybe others (e.g. styles?)
  3. Re-implement the model value parser to parse expressions of composed observables
  4. Rewrite the models test to specify composed values in the muis file instead of all that horrendous converter code in the model class.
Updownquark commented 10 years ago

I'm kinda just splashing around here. I thought about using rxJava for the observables, but there's a few things I don't really like about it and I'm not sure it fits here. So I starting writing my own. I may backtrack and pull in rxJava later. For now, I want the ObservableValue<T> to extend Observable<ObservableValueEvent<T>> and go from there.

Updownquark commented 10 years ago

So I've thought more about rxJava and more firmly decided to not integrate it. Because...

  1. It doesn't support values. I suppose I could extend their Observable to have a value, but all their static methods that transform observables would return regular observables, so I'd have to re-implement them all anyway.
  2. rx.Observable is a class, not an interface. Not a big deal, but an interface seems nicer.
  3. Many of the transformations on rx.Observable are static methods instead of instance methods. Makes the code less clean.
  4. I'm thinking that I want the errors on observables to be more than just a callback, but an observable itself. This way, you can filter and combine the errors observables fire and do things with them. Also, observable values could have a stateful error observable value that returns the error state of the value.

I am disappointed to have to reimplement so much work they've done for me, but I can't see a clean way to avoid that.

Updownquark commented 10 years ago

Started to work on integrating rxJava into MUIS, but it appears rxJava's Observable class was specifically designed NOT to be extensible. So I can't just add values in and I kind of need dynamic type information in them as well. So for now, back to rolling my own rx architecture.

Updownquark commented 10 years ago

As noted, the initial phase of rx-ifying is done. The next step is to implement a parser for muis model values that can access not only model values but also observables on the element (attributes, etc.) and compose them and operate on them.

Updownquark commented 10 years ago

I thought of a new extension to this. Have a SettableValue interface which extends ObservableValue and exposes a setter for the value. Certain operations would also support settable composition. For example, a formatting method might also support parsing or the == boolean operator could support a setter (setting to true would assign the value to the other operand; setting to false would assign the value to a default value, also provided by the SettableValue interface). Using this interface, assignment operators could be supported by the model parser.

Updownquark commented 10 years ago

Need to jot down some ideas.

Updownquark commented 10 years ago

More thoughts:

The existing MuisProperty interface would change almost not at all. The model value parser interface (which will probably be renamed, since it'll be doing more now) would take a parsing environment, thereby allowing implementations to parse scoped information. A new abstract implementation would be created which provides the extended functionality mentioned above. There would be a document-scope property parser which knows about model values and maybe some other things, but then this abstract implementation would parse things that are more specific to the specific property. When the property is defined it would be initialized with additional parsing configurations and environment variables. A mechanism would also need to be provided for the implementation to evaluate the parsed items generated by the parser. The end value from the parsing will always be an ObservableValue.

Updownquark commented 9 years ago

There may be some bugs in here (see #58) but this is mostly done and working. I'm gonna call it good and move on to some more creative work and file bugs as I notice them.