GraphiteEditor / Graphite

2D vector & raster editor that melds traditional layers & tools with a modern node-based, non-destructive, procedural workflow.
https://graphite.rs
Apache License 2.0
7.3k stars 386 forks source link

Contravariance for node inputs with automatic coercion #1741

Closed TrueDoctor closed 1 month ago

TrueDoctor commented 1 month ago

RFC: Contravariance for node inputs with automatic coercion: Current Status: Currently the types supplied to functions are treated as invariant. If node A is chained with node B and B expects an input of T → V, the type of node A has to be exactly T → V. Suggested Changes: Node inputs should be allowed to be contravariant. That means if the signature of A can be T' → V as long as T' ∝ T (With ∝ denoting the subtyping relation) = as long as T is more general than T'. We then need to define a subtyping relation to have () to be the root of that relation. In practice that means that any node which expects T → V can also take a node with () -> V as input. Implementation: For the implementation we have to consider two things: the type checking and the type coercion. It should be pretty easy to extend the type checking to support contravariant function arguments. Type coercion is a bit tricker, when using rustc for compilation we could just express this relationship using traits but due to the dynamic execution that is infeasible as it would lead to a type explosion for the node implementations. Instead we'll have to insert explicit nodes to perform the conversion which work much like the cull node does currently. Performance Impact: When compiling with rustc this does not cause any runtime overhead. When linking the graph dynamically, it add the cost of calling an extra node. The compilation overhead is expected to be minimal. Open questions: How do we communicate this to the user / developer? When a chain A - B - C of nodes is created and A, C are resolution aware and B is not resolution aware, the typesystem would complain that the link between A and B is invalid even though node B itself is the problem, somewhat obfuscating the error. Alternatives: