Skip to content

Living with Matrix

Kenneth Tilton edited this page Apr 17, 2023 · 5 revisions

A home for Flutter/MX war stories tied to Matrix gotchas.

It is all about me

Problem: After an innocuous change, the immediate problem was:

The following _CastError was thrown building mainReifyirmorq$1-[#c840e](dirty, state:
mainReify2we0cb$1#e5bbb):
type 'Null' is not a subtype of type 'String' in type cast

The relevant error-causing widget was:
  mainReifyirmorq$1-[#c840e]
  mainReifyirmorq$1:file:///Users/kennethtilton/dev/dart/flutter-mx/lib/cljd-out/tiltontec/main.dart:69:18

When the exception was thrown, this was the stack:
#0      make_app.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:matrix/cljd-out/tiltontec/example/x26-tex-sandbox.dart:2158:121)
#1      calculate_and_link (package:matrix/cljd-out/tiltontec/cell/evaluate.dart:460:33)
#2      calculate_and_set (package:matrix/cljd-out/tiltontec/cell/evaluate.dart:520:45)

"Null string" is rather vague, but example/x26-tex-sandbox.dart:2158:121 narrowed it down nicely to:

(let []
  ;; wow, this works.
  (mget me :value))

This code had been working fine for a while, so what was the innocuous change?

Cause: The involved widget had itself been wrapped in (w/IgnorePointer ...). I had changed that to use the f/mx proxy (fx/ignore-pointer....).

What is wrong with that? See that "wow" comment? A bit of the surrounding code:

(tk/TeXViewDocument (let []
                      ;; wow this works
                      (mget me :value))
  .style (tk/TeXViewStyle...etc

This code is using native (CLJ)Dart widgets. The "wow" is just about how cool is lexical scope, because me actually referred to the nearest Flutter/MX widget, where the desired :value lived, not the apparent TexViewDocument owner object.

What went wrong was that switching to fx/ignore-pointer made that the nearest me, and that is not where the desired math string valued lived. An upcoming patch will make (mget me :value) fail if there is no :value property, but that would not really be a fix: what if we gave the ignore-pointer widget a :value? A switch to mpar would work now, but Flutter is widget-wrap happy, so the next refinement might break us again. So we solve the problem more robustly:

(tk/TeXViewDocument (let []
                      ;; wow this works
                      (mget (md/fmuinc :tex-pair) :value))
  .style (tk/TeXViewStyle...etc

Now changes to the ancestors of our TexView will not throw off our search for the raw TeX string. But...

Why fmuinc instead of the usual fmu? The 'inc' is for "inclusive". The fmu utility searches up from but not including the provided node. Why does that matter if we now have the intervening ignore-pointer? Because we might eliminate that someday to get pointer events, then me would be the :tex-pair-named widget.

Moral

Lexical scope combined with Matrix management of the anaphor me are a very large part of why the Matrix D/X is so seamless, and being able to code Dart widgets in line with f/mx widgets means borrowing CLJDart code much easier, but if we want to leverage f/mx values and properties in our CLJDart code, make sure we know who "me" is.