From 88c2e9122e2de4911993ecd0ea615c637e9cc96f Mon Sep 17 00:00:00 2001 From: Pieter Hijma Date: Thu, 30 Oct 2025 13:31:47 +0100 Subject: [PATCH] Doc: Improve the Expression Framework topic --- src/App/core-app.dox | 81 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/src/App/core-app.dox b/src/App/core-app.dox index 672fbf243b..695b7658b3 100644 --- a/src/App/core-app.dox +++ b/src/App/core-app.dox @@ -227,7 +227,11 @@ * recomputed. Since properties may depend on other document objects, for * example because of the @ref App::DocumentObject::ExpressionEngine * "ExpressionEngine" property, these document objects have to be computed - * first. Managing the order of recomputation is managed by the @ref + * first. For more information on the role of expressions in recomputing + * document objects, see topic @ref SecExpressionsDocumentObjectRecompute + * "Expressions Framework". + * + * Managing the order of recomputation is managed by the @ref * App::Document "Document" which calls the @ref * App::DocumentObject::recompute() "recompute()" on the document object. To * signal that a document object needs to be recomputed, the document object @@ -251,7 +255,7 @@ * Vice versa, if a property of an object is changed, the InList indicates * which other objects depend on it and need to be recomputed. * - * So, as mentioned above, links define dependencies between document objects + * So, as mentioned above, links define dependencies between document objects. * These dependencies are recorded by means of setting the value of a @ref * App::PropertyLink "PropertyLink" (and similar properties) in a document * object `Obj` to a document object `Value`. Within @ref @@ -466,7 +470,78 @@ /** * @defgroup ExpressionFramework Expressions framework * @ingroup APP - * @brief The expression system allows users to write expressions and formulas that produce values + * @brief A system that allows users to write expressions and formulas that produce values. + * + * One of the differences between @ref DocumentObjectGroup "DocumentObjects" + * and @ref DocumentGroup "Documents" as @ref PropertyFramework + * "PropertyContainers" is that document objects support expressions whereas + * documents do not. %Document objects have a special hidden property called + * @ref App::DocumentObject::ExpressionEngine "ExpressionEngine" of type @ref + * App::PropertyExpressionEngine "PropertyExpressionEngine" that contains a + * mapping from @ref App::ObjectIdentifier "ObjectIdentifier" to @ref + * App::Expression "Expression". An object identifier defines the property + * inside the document object that will hold the result of the expression. We + * can also say that the expression is bound to the property that the object + * identifier identifies. + * + * Expressions can be as simple as `2 + 3`, but typically they reference other + * document objects and their properties, such as `Box001.Length` or even + * document objects in other documents such as `myDocument#Box001.Length`. + * + * Since expressions can reference other document objects, they effectively + * link to other document objects, potentially in other documents, and as such, + * a @ref App::PropertyExpressionEngine "PropertyExpressionEngine" inherits + * from the property external link container @ref App::PropertyXLinkContainer + * "PropertyXLinkContainer". + * + * @section SecExpressionsDocumentObjectRecompute The role of expressions in recomputing Documents + * + * For a high level overview of how document objects recompute, see topics @ref + * DependencyGraph "Document" and @ref SecDocumentObjectRecompute "Document + * Objects". On a recompute of a document object, the expressions in the + * expression engine are first evaluated by calling the @ref + * App::PropertyExpressionEngine::execute "PropertyExpressionEngine::execute()" + * function. This function obtains the values of the properties it references + * and evaluates the expression to a value that is stored in the property to + * which the expression is bound to. + * + * Now that the properties of the document objects have been updated according + * to the expressions, the document object can call @ref + * App::DocumentObject::execute "DocumentObject::execute()" to update its + * internal properties. + * + * After this execute of the document objects, the expression engine is + * executed again, but now only for the output properties ensuring that + * expressions that depend on properties of the document object itself that are + * set by @ref App::DocumentObject::execute "DocumentObject::execute()" are + * also updated. + * + * This process makes clear why it is important that there is a well-defined + * dependency graph and a topological order of document objects in terms of + * their dependencies as was discussed in topic @ref DependencyGraph + * "Document": If a document object is executed and references a property of + * another document object, we need to make sure that that document object has + * fully recomputed as we would compute a stale value of the property + * otherwise. Similarly, objects that refer to properties of a recently + * recomputed document object, need to be certain that the properties of this + * object have the latest value. As such, it is not possible to have a cyclic + * dependency between document objects as they would continuously update + * themselves. + * + * @section SecExpressionVisitors Expression Visitors + * + * Some actions require that expressions are updated. For example, when a document + * is relabeled, expressions that refer to the old name must be updated to + * refer to the new name. + * + * For this purpose, the visitor pattern is used. An expression visitor is derived + * from @ref App::ExpressionVisitor "ExpressionVisitor" and implements the + * virtual function @ref App::ExpressionVisitor::visit "visit()". This + * function is called for each node in the expression tree. + * + * There are two types of visitors: ones that gather information, for example a + * list of object identifiers in the expression, and ones that modify the + * expression, for example in case a document is relabeled. */ /**