Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
ego_script [2026/08/07 03:51]
hermann
ego_script [2026/08/31 15:12] (current)
hermann
Line 104: Line 104:
 </​code>​ </​code>​
  
-For ''​String''​ ports that contain line breaks or double-quote characters, use the extended form ''​$"​DELIMITER(content)DELIMITER"''​. The content is everything between the opening ''​(''​ and the closing ''​)'',​ and the DELIMITER — any sequence of characters placed between the ''​%%"​%%''​ and the ''​('',​ including empty — makes the closing ''​)"''​ unambiguous. The delimiter must be identical on both sides. ​This extended form is **only accepted by ''​String''​ ports**:+[[code_type|Code]] ports also accept this basic ''"​text"''​ form, but interpret it differently from the types above: rather than validating the text itself, the content is decoded as base64 to produce the script — see the note below. 
 + 
 +For ''​String''​ ports that contain line breaks or double-quote characters, use the extended form ''​$"​DELIMITER(content)DELIMITER"''​. The content is everything between the opening ''​(''​ and the closing ''​)'',​ and the DELIMITER — any sequence of characters placed between the ''​%%"​%%''​ and the ''​('',​ including empty — makes the closing ''​)"''​ unambiguous. The delimiter must be identical on both sides. ​[[code_type|Code]] ports accept this same extended form directly too, using the content as the literal script text with no encoding involved — see [[code_type|Code Type]] for the full grammar. No other port type accepts it:
  
 <​code>​ <​code>​
Line 156: Line 158:
 Here ''​[ 2->1 0.05 ]''​ is a structured constant representing a transition matrix with a 5% rate from class 2 to class 1. Here ''​[ 2->1 0.05 ]''​ is a structured constant representing a transition matrix with a 5% rate from class 2 to class 1.
  
-> **Note:​** ​''​Code'' ​— the type used for expression inputs such as the Python code in [[Calculate Python Expression]] — is not a text constant. Code values are stored as base64 in the underlying scriptmaking them impractical to write directly. When port expects a ''​Code''​ valuesupply a ''​String'' ​carrier functor containing ​the expression ​text; the automatic ​''​String → Code'' ​conversion handles ​the rest.+> **Note:​** ​[[code_type|Code]] — the type used for expression inputs such as the Python code in [[calculate_python_expression|Calculate Python Expression]] — has its own literal syntaxparsed ​directly ​rather than through ​conversionand accepts two forms: the extended ​''​$"​DELIMITER(content)DELIMITER"​'' ​form described above, taken directly as the script'​s ​text with no encoding involvedand the basic double-quoted ​''​"​text"​'' ​form, whose content is instead decoded as base64 to produce the script. See [[code_type|Code Type]] for the full grammar and examples of both forms.
  
 ==== Positional syntax ==== ==== Positional syntax ====
Line 221: Line 223:
 </​code>​ </​code>​
  
-Any output can be replaced with ''​_'' ​to discard ​it when only some outputs are needed.+When only some of a functor'​s outputs are wanted, the rest can simply be left out of the block entirely — nominal syntax binds by name, so there'​s no position to hold open the way [[#​positional_syntax|positional syntax]] requires. An unwanted ​output can also be bound to ''​_'' ​instead of omitted; this changes nothing about execution, ​it only makes explicit, at the call site, that the output was considered and deliberately discarded rather than overlooked.
  
 So inputs read ''​portName = value''​ while outputs read ''​variable = portName''​. The two directions are summarized below: So inputs read ''​portName = value''​ while outputs read ''​variable = portName''​. The two directions are summarized below:
Line 288: Line 290:
   * **Loops.** Several containers repeat their contents. [[Repeat]] runs them a fixed number of times; [[For]] iterates over a numeric range; [[For Each]] iterates over the rows of a table; [[For Each Category]] iterates over the categories of a map; [[For Each Region]] iterates over the regions of a map; and [[While]] and [[Do While]] repeat for as long as a condition holds.   * **Loops.** Several containers repeat their contents. [[Repeat]] runs them a fixed number of times; [[For]] iterates over a numeric range; [[For Each]] iterates over the rows of a table; [[For Each Category]] iterates over the categories of a map; [[For Each Region]] iterates over the regions of a map; and [[While]] and [[Do While]] repeat for as long as a condition holds.
   * **Region management.** [[Region Manager]] establishes a region context and runs its contents once for that context, exposing the region to the functors inside it.   * **Region management.** [[Region Manager]] establishes a region context and runs its contents once for that context, exposing the region to the functors inside it.
-  * **Error handling.** [[Skip On Error]] and [[Skip All On Error]] execute their contained functors while capturing and ignoring any error that occurs. Both accept a ''​trapAndIgnoreErrors''​ boolean input — when set to false, they behave as a plain ''​Group''​ and errors are not suppressed. Both also produce an ''​executionCompletedSucessfully''​ output that can be tested by subsequent functors. The two differ in what happens to results already produced when an error is raised: [[Skip On Error]] preserves the outputs of any functors that completed successfully before the error; [[Skip All On Error]] discards all of them. They are typically paired with a junction outside the container to react to the outcome — see [[#​error-handling_pattern|Error-handling pattern]] below.+  * **Error handling.** [[Skip On Error]] and [[Skip All On Error]] execute their contained functors while capturing and ignoring any error that occurs. Both accept a ''​trapAndIgnoreErrors''​ boolean input — when set to false, they behave as a plain ''​Group''​ and errors are not suppressed. Both also produce an ''​executionCompletedSuccessfully''​ output that can be tested by subsequent functors. The two differ in what happens to results already produced when an error is raised: [[Skip On Error]] preserves the outputs of any functors that completed successfully before the error; [[Skip All On Error]] discards all of them. They are typically paired with a junction outside the container to react to the outcome — see [[#​error-handling_pattern|Error-handling pattern]] below.
  
 The [[#​calculator_functor_shorthand|calculator functors]] described later in this section are also containers: each holds the expression it evaluates, and in its verbose form holds a block of operand definitions. The [[#​calculator_functor_shorthand|calculator functors]] described later in this section are also containers: each holds the expression it evaluates, and in its verbose form holds a block of operand definitions.
Line 352: Line 354:
 </​code>​ </​code>​
  
-> **Note:** Sequence ports are only needed when two containers have no natural data dependency between them — if one container already produces a value that the other consumes, the ordering is already established and no sequencing port is required. Before sequence ports were available, models used a **forced-dependency pattern** — creating a dummy data value inside one container and consuming it inside another to manufacture an artificial data dependency. This idiom still appears in older scripts but is now a last resort, used only for functors that do not expose ''​sequenceInput''​ and ''​sequenceOutput''​ ports (such as [[Skip On Error]] and [[Skip All On Error]], which instead expose an ''​executionCompletedSucessfully''​ boolean output that can serve the same purpose).+> **Note:** Sequence ports are only needed when two containers have no natural data dependency between them — if one container already produces a value that the other consumes, the ordering is already established and no sequencing port is required. Before sequence ports were available, models used a **forced-dependency pattern** — creating a dummy data value inside one container and consuming it inside another to manufacture an artificial data dependency. This idiom still appears in older scripts but is now a last resort, used only for functors that do not expose ''​sequenceInput''​ and ''​sequenceOutput''​ ports (such as [[Skip On Error]] and [[Skip All On Error]], which instead expose an ''​executionCompletedSuccessfully''​ boolean output that can serve the same purpose).
  
 ==== Internal output ports ==== ==== Internal output ports ====
Line 500: Line 502:
 </​code>​ </​code>​
  
-When only a pass/fail signal is needed — not an actual fallback value — a junction is unnecessary:​ [[Skip All On Error]] already reports success or failure directly through its own ''​executionCompletedSucessfully''​ output, with no sentinel or junction required:+When only a pass/fail signal is needed — not an actual fallback value — a junction is unnecessary:​ [[Skip All On Error]] already reports success or failure directly through its own ''​executionCompletedSuccessfully''​ output, with no sentinel or junction required:
  
 <​code>​ <​code>​
Line 512: Line 514:
 [[Skip On Error]] behaves differently:​ instead of discarding all results, it preserves the outputs of any functors that had already completed when the error was raised. Substituting it into the paired-loading example above would be a mistake: since ''​loadedMap''​ and ''​loadedWeights''​ have no data dependency on each other — see [[#​functors_variables_and_binding|Functors,​ variables, and binding]] for that execution-order rule stated generally — nothing guarantees which of the two, if either, has already completed by the time the other'​s error is raised. The outcome would be a race: a real map could end up paired with default weights, or the reverse, unpredictably from run to run. [[Skip All On Error]] sidesteps that race entirely — it discards both regardless of which one failed or how far the other had gotten — which is exactly what "​succeed together or not at all" requires. [[Skip On Error]] instead earns its place when partial results are genuinely fine to keep on their own — see below. [[Skip On Error]] behaves differently:​ instead of discarding all results, it preserves the outputs of any functors that had already completed when the error was raised. Substituting it into the paired-loading example above would be a mistake: since ''​loadedMap''​ and ''​loadedWeights''​ have no data dependency on each other — see [[#​functors_variables_and_binding|Functors,​ variables, and binding]] for that execution-order rule stated generally — nothing guarantees which of the two, if either, has already completed by the time the other'​s error is raised. The outcome would be a race: a real map could end up paired with default weights, or the reverse, unpredictably from run to run. [[Skip All On Error]] sidesteps that race entirely — it discards both regardless of which one failed or how far the other had gotten — which is exactly what "​succeed together or not at all" requires. [[Skip On Error]] instead earns its place when partial results are genuinely fine to keep on their own — see below.
  
-Whatever [[Skip On Error]] preserves is what each branch has to work with. If the branches only need to pick between two values — the case in the [[manipulating_tables_and_lookup_tables#​printing_a_table_with_a_generic_format|generic printer]] above — a junction is the simplest tool. But when the branches need to carry out different logic rather than just hand a value onward, [[If Then]]/[[If Not Then]] can test [[Skip On Error]]'​s own ''​executionCompletedSucessfully''​ output directly — no separate sentinel needed, unlike the paired-loading [[Skip All On Error]] pattern above. This example attempts to load an optional mask map; if it loads, the matching branch has the mask itself to work with, and if it's missing or fails to load, the other branch proceeds without one:+Whatever [[Skip On Error]] preserves is what each branch has to work with. If the branches only need to pick between two values — the case in the [[manipulating_tables_and_lookup_tables#​printing_a_table_with_a_generic_format|generic printer]] above — a junction is the simplest tool. But when the branches need to carry out different logic rather than just hand a value onward, [[If Then]]/[[If Not Then]] can test [[Skip On Error]]'​s own ''​executionCompletedSuccessfully''​ output directly — no separate sentinel needed, unlike the paired-loading [[Skip All On Error]] pattern above. This example attempts to load an optional mask map; if it loads, the matching branch has the mask itself to work with, and if it's missing or fails to load, the other branch proceeds without one:
  
 <​code>​ <​code>​
Line 1114: Line 1116:
 | **Use abbreviated syntax for Calculate family functors** | Whether the ''​Calculate''​ family is written using the shorthand symbol (''#'',​ ''##'',​ ''​%'',​ etc.) or the full functor name. See the [[#​calculator_functor_shorthand|Calculator functor shorthand]] section for details. | | **Use abbreviated syntax for Calculate family functors** | Whether the ''​Calculate''​ family is written using the shorthand symbol (''#'',​ ''##'',​ ''​%'',​ etc.) or the full functor name. See the [[#​calculator_functor_shorthand|Calculator functor shorthand]] section for details. |
 | **Preferred number of columns before wrapping comments** | The line width at which the generator wraps long comment text. | | **Preferred number of columns before wrapping comments** | The line width at which the generator wraps long comment text. |
-