catala icon indicating copy to clipboard operation
catala copied to clipboard

Fix: force the evaluation of all boolean expression clauses

Open EmileRolley opened this issue 3 years ago • 2 comments

While refactoring the log event structure in #280, I found that generated raw log events by compiled catala programs differ from the interpreter log trace.

It appears that it comes from the laziness of the and and or operators in OCaml, resulting that when evaluating the expression x and f y if x == false then the whole expression is evaluated to false without calling f with y.

Example on tests_allocations_familiales.catala_fr with the scope Test1

Example of raw events retrieved from the OCaml program:

[161/528] Parsing event: VariableDefinition([ AllocationsFamiliales, droit_ouvert_forfaitaire, input ], _)
[162/528] Parsing event: BeginCall([ AllocationsFamiliales, droit_ouvert_forfaitaire ])
[163/528] Parsing event: DecisionTaken(_)
[164/528] Parsing event: VariableDefinition([ AllocationsFamiliales, droit_ouvert_forfaitaire, output ], _)
[165/528] Parsing event: EndCall([ AllocationsFamiliales, droit_ouvert_forfaitaire ])

The corresponding log events from the interpreter -- the call to PrestationsFamiliales.conditions_hors_âge is missing in the OCaml program log trace.

[LOG]     →  AllocationsFamiliales.droit_ouvert_forfaitaire
[LOG]       ≔  AllocationsFamiliales.droit_ouvert_forfaitaire.input: Enfant {"identifiant"= 1; "obligation_scolaire"= Pendant (); "rémuneration_mensuelle"= 0.00 €; "date_de_naissance"= 2007-01-01; "âge"= 13; "prise_en_charge"= EffectiveEtPermanente (); "a_déjà_ouvert_droit_aux_allocations_familiales"= true; "bénéficie_titre_personnel_aide_personnelle_logement"= false}
[LOG]       →  PrestationsFamiliales.conditions_hors_âge
[LOG]         ≔  PrestationsFamiliales.conditions_hors_âge.input: Enfant {"identifiant"= 1; "obligation_scolaire"= Pendant (); "rémuneration_mensuelle"= 0.00 €; "date_de_naissance"= 2007-01-01; "âge"= 13; "prise_en_charge"= EffectiveEtPermanente (); "a_déjà_ouvert_droit_aux_allocations_familiales"= true; "bénéficie_titre_personnel_aide_personnelle_logement"= false}
[LOG]         ☛ Definition applied:
[LOG]         ≔  PrestationsFamiliales.conditions_hors_âge.output: true
[LOG]       ←  PrestationsFamiliales.conditions_hors_âge
[LOG]       ☛ Definition applied:
[LOG]       ≔  AllocationsFamiliales.droit_ouvert_forfaitaire.output: false
[LOG]     ←  AllocationsFamiliales.droit_ouvert_forfaitaire

Solutions

In order to keep the same behavior between all targeted languages, we should force the evaluation of all clauses. To do this there are two main ways:

  1. Using let-bindings.
  2. Overiding and and or operators.

EmileRolley avatar Jun 22 '22 09:06 EmileRolley

Decision : we provide two different compilation mode for boolean operators. By default and with the --trace mode activated, boolean operators are eager and all their arguments need to be evaluated. This behavior should be propagated to all backends with let-encapsulated arguments to the lazy operators in the backends.If --trace mode is deactivated (with or without -O), then the semantics of the boolean operators is lazy.

The rationale is that we only care about side-effects for the tracing mode.

denismerigoux avatar Jul 05 '22 14:07 denismerigoux