(a little)

MVCoconut

(more)

Tinkerbell

tink_core

  • Future
  • Promise
  • Signal
  • etc.

(this one we already know)

tink_state

Observable state primitives

  • Observable
  • State
  • Observable.auto
  • ObservableArray, ObservableMap

tink_state: Observable

abstract Observable<T> {
  // readable value
  var value(get, never):T;

  // a way to bind/unbind value change callbacks
  function bind(handler:Callback<T>):CallbackLink;

  // magic \o/ (more on this later)
  static function auto<X>(f:()->X):Observable<X>;
}

tink_state: State

abstract State<T> to Observable<T> { // also is an Observable
  // writable value
  var value(get, set):T;

  // created with initial value
  function new(value:T):Void;

  // also bindable
  function bind(handler:Callback<T>):CallbackLink;
}
  • Any state is also an observable, but not every observable is a state.
  • One could also say that states are read-write versions of observables.

tink_state: Observable.auto

// Some observable state
var messages = new ObservableArray([
	{isRead: new State(true)},
	{isRead: new State(false)},
	{isRead: new State(false)},
]);

// Observable from a "computation"
var unreadCount = Observable.auto(() -> {
	var count = 0;
	for (message in messages) {
		if (!message.isRead.value) {
			count++;
		}
	}
	return count;
});

// Example
trace(unreadCount.value); // 2

messages.push({isRead: new State(false)});
messages.push({isRead: new State(false)});
messages[1].isRead.value = true;

trace(unreadCount.value); // 3

(no macros involved, just smart invalidation management)

tink_state: performance

  • State wraps values in small objects
  • Reading values:
    • Simple State: just a field read
    • Computable Observable (e.g. Observable.auto): cached computations
  • Changing values simply sets observable to the "invalid" state and notifies subscribers.
  • Bindings are delayed and batched

tink_state: goodies

  • ObservableArray
  • ObservableMap
  • Promised (Loading/Done/Failed)
  • Comparators
  • Guards
  • Composition
  • Transformation
  • Debugging tools

coconut.data

  • Observable models, based on tink_state
  • Ergonomics for common use cases
  • Statically enforced observability

coconut.data

Macro-built model classes

class Player implements Model {
  @:constant var id:Int;
  @:editable var name:String;
}
class Player implements Model {
  @:isVar public var id(get, never):Int;
  public var name(get, set):String;
  
  public final observables:{id:Observable<Int>, name:State<String>};

  final __coco_name:State<String>;

  public function new(__coco_init:{name:String, id:Int}) {
    this.id = __coco_init.id;
    this.__coco_name = new State(__coco_init.name);
  }

  inline function get_id() {
    return this.id;
  }

  inline function get_name() {
    return this.__coco_name.value;
  }

  function set_name(param:String) {
    this.__coco_name.set(param);
    return param;
  }
}

source

output (simplified)

coconut.ui

  • Reactive UIs for coconut.data models
  • Similar ideas to React (and friends)
  • tink_state powered invalidation
  • JSX-style markup DSL via tink_hxx
  • Pluggable renderers, cross-platform
class Totals extends View {
  @:attribute var count:Int;

  function render() '
    <TextField text=${"You have " + count + " resources"}/>
  ';
}

coconut.ui: features

  • attributes
  • states
  • children
  • references
  • life cycle callbacks
  • implicit attributes
  • lazyness
  • batching

tink and coconut

By Dan Korostelev

tink and coconut

  • 970