When are expressions in a form recomputed?

Could we get more details concerning check action, please: (see TAB minutes from September.)

Gareth: When do checks run run?
● Collect: On swipe, but when jumping, at the end.
● Enketo: Unknown

Collect: What about field-list on same page? Return key or cursor movement out of field?
Next button = swipe? Also page backwards, e.g. after a jump before?
What is "at the end" exactly now? Finalisation?
If bulk finalisation, in which form is the (error) cursor positioned?

1 Like

Enketo generally recomputes dependent expressions on focus change. For example, if you leave focus of a question named foo, all expressions that reference foo will be recomputed. It does not have a single directed graph of expression relations like Collect does, though, so sometimes there are unexpected extra recalculations. Collect also has some cases with repeats where it will recalculate more than it strictly could. Both do a recalculation pass when a filled form is explicitly saved.

If there's specific behavior you'd like explained, it would be helpful to look at a concrete example.

For text fields, Collect recomputes dependent expressions after every character input. In general, it tries to keep things as up-to-date as possible within a field list so recomputation is immediate after a select change, etc.

Yes, they are treated identically.

Going backwards and jumping do not trigger recomputation in general. I believe there is an exception for filtered choice lists, though, which are recomputed when displayed.

I should have said "at form exit." There is a recomputation pass when exiting and saving a filled form, regardless of whether it's finalized or not. That has not changed.

Bulk finalization will be available from the Drafts screen. Filled forms that successfully finalize will move out of that listing. Filled forms that can't be finalized will stay in Drafts and will be marked as needing action. There will be an android popup (snackbar) showing the number of forms that were finalized and the number that weren't.

1 Like

Exit without save also does recalculations?
Recalculations are also done on load of form?
On save, finalisation and load are all calculations redone or only those with (new) changes in references?
In general, calculations are never filtered by relevant?
In general, a trigger reference filters (re-)calculations?

"Checks" are not always the same as explicit "calculations" (e.g. required)?
So, "recomputation" refers to more (or less) than re-"calculations"?


No, exit without save does nothing.

That's correct.

Load is always a full recomputation. Save and finalization are identical to each other. There is some complexity around what exactly is recomputed then that I don't know off the top of my head. I don't believe we have worked in that logic since I've been part of the project. If there's a specific form or behavior you want more details on, it would be helpful to start with that.

Correct, calculations are done even for non-relevant fields and are ready to be displayed as soon the fields become relevant. However, non-relevant fields always evaluate to blank (that's what the alignment between Enketo and Collect was about).

It's kind of the other way around. "Triggers" (e.g. https://docs.getodk.org/form-logic/#dynamic-defaults-from-form-data) are computed separately, only when the triggering expression changes. All other expressions may be recomputed at any time. In practice, the engines do try to limit recomputation as much as possible but I think the most useful mental model to have is that any expression could be re-evaluated at any time. If that's not desirable, a "trigger" or if or once should be used.

Sorry, I'm not using entirely consistent language. I don't intend to mean anything different between recomputation and recalculation. required and constraint are a bit different than calculates and relevance because they don't cascade. That is, they can't be used in further expressions and they only are related to exactly one field. That means engines can limit when they recompute them. My recollection is that Collect uses this knowledge to only evaluate when exiting the current screen when only one question is displayed.

Again, I think the general mental model to have is that every expression can be reevaluated at any time, except when using a "trigger". If there's specific behavior that doesn't feel right or that is different between Collect and Enketo, we should dig into those specifics.

1 Like

Thanks for the details! (Maybe the ODK/Enketo doc could also explain more?)

Sorry, from an IT view, this seems a bit foggy.
We had examples, where the (Enketo) behaviour was surprising too, like referencing a variable in repeat_count and going back and reduce this value. E.g. a sum after the loop e.g. was not updated: the "deleted" loop case was only hidden and still counted (before save).

1 Like

This points to some of the complexity around very precisely describing the recomputation behavior: it's not only about when recomputation happens, but also when the display layer is updated and/or how specific features are implemented. We really do our best to consider how different feature areas combine and to define expected behavior but there's a lot of functionality that users make very creative use of in their forms so sometimes we do miss things.

If you have a specific form that didn't feel like it did what you expected, we can look at it and either more specifically document what the expectations should be or consider improving the behavior. Regarding repeat count specifically, there has been extensive debate in the past around what should happen when the count is decreased. The tradeoff is between respecting the user's intention and providing guardrails against accidental data loss. There's some information about that in the docs: https://docs.getodk.org/form-repeats/#using-a-constraint-to-limit-repetitions

Hi @LN
Here a nice (new) example: https://community.kobotoolbox.org/t/default-number-is-not-appearing/45857/4. It also shows differences between Enketo and Collect: Cleaning for relevant and sum only through submission in Enketo, but immediately or on swipe in Collect! Also the time/behaviour of initial default setting seems different! (Even see navigation). I hope you will find time to have a deeper look, for Enketot and Collect.
(Hint: Enketo behaviour is here the same with page mode.)

Have you tried the form on https://getodk.org/xlsform/? We generally recommend that organizations deploying Enketo configure it to opt into aligning relevance behavior with Collect but we don't know who does and doesn't (see exclude non-relevant in https://enketo.github.io/enketo-express/tutorial-10-configure.html). At first glance it looks like Kobo might not.