Major
Nice to have
Detail
In TL-Script können beliebige Werte in einem boolschen Kontext interpretiert werden. Dabei wird null, leere Collections und leere Strings wie false und alle anderen Werte wie true betrachtet.
Insbesondere liefert eine Or-Kette $x || $y || $z genau dann true, wenn einer der Werte ein von null, false oder leer verschiedener Wert ist.
Die Semantik eines solchen Ausdrucks soll zu einer Or-Fallback-Chain erweitert werden: Das Endergebnis einer solchen Chain soll nicht mehr zwangsläufig einer der Werte true, false oder null sein sondern der erste Wert in der Kette der von null, false oder leer verschieden ist. Sind alle Werte in der Kette null, false oder leer, dann soll das Ergebnis der letzte Wert in der Kette sein.
Da alle Werte in einem boolschen Kontext eine Interpretation besitzen, ändert sich an der Semantik nichts, wenn alle Eingaben vom Typ Boolean sind. Mit dieser Semantik lassen sich aber elegant Default-Werte (Fallbacks) für ansonsten leere Werte formulieren:
Statt
if($x.get(`my.module:MyType#myProp`) != null, $x.get(`my.module:MyType#myProp`), "Some default")
kann einfach
$x.get(`my.module:MyType#myProp`) || "Some default"
geschrieben werden. Dies lässt sich zu einer längeren Fallback-Chain erweitern, bei welcher der Ausdruck
$x.get(`my.module:MyType#myProp1`) || $x.get(`my.module:MyType#myProp2`) || ... || "Some default"
das erste von null, false oder leer verschiedene Ergebnis der Einzelzugriffe liefert, oder den angegebenen Default-Wert, wenn alle Ausdrücke zu null, false oder leer auswerten.
Insgesamt ergibt sich für boolsche Operationen die folgende Semantik:
assertEquals(Boolean.TRUE, execute(search("true"))); assertEquals(Boolean.TRUE, execute(search("!false"))); assertEquals(Boolean.TRUE, execute(search("false || true"))); assertEquals(Boolean.TRUE, execute(search("false or true"))); assertEquals(Boolean.TRUE, execute(search("true && true"))); assertEquals(Boolean.TRUE, execute(search("true and true"))); assertEquals(Boolean.TRUE, execute(search("toBoolean(true)"))); assertEquals(Boolean.TRUE, execute(search("toBoolean('some value')"))); assertEquals(Boolean.TRUE, execute(search("toBoolean(list(42))"))); assertEquals(Boolean.TRUE, execute(search("toBoolean(list(0))"))); assertEquals(Boolean.TRUE, execute(search("toBoolean(42)"))); assertEquals(Boolean.TRUE, execute(search("toBoolean(0)"))); assertEquals(Boolean.FALSE, execute(search("toBoolean(false)"))); assertEquals(Boolean.FALSE, execute(search("toBoolean('')"))); assertEquals(Boolean.FALSE, execute(search("toBoolean(null)"))); assertEquals(Boolean.FALSE, execute(search("toBoolean(list())"))); assertEquals(Boolean.TRUE, execute(search("null || true"))); assertEquals(Boolean.TRUE, execute(search("true || null"))); // This looks little asymmetric,... assertEquals(Boolean.FALSE, execute(search("null || false"))); assertEquals(null, execute(search("false || null"))); // ... but in a boolean context it behaves the same. assertEquals(Boolean.FALSE, execute(search("toBoolean(null || false)"))); assertEquals(Boolean.FALSE, execute(search("toBoolean(false || null)"))); assertEquals(null, execute(search("null || null"))); assertEquals(Boolean.FALSE, execute(search("null && true"))); assertEquals(Boolean.FALSE, execute(search("true && null"))); assertEquals(Boolean.FALSE, execute(search("false && null"))); assertEquals(Boolean.FALSE, execute(search("null && false"))); assertEquals(Boolean.FALSE, execute(search("null && null"))); assertEquals(Boolean.TRUE, execute(search("!null"))); assertEquals(Boolean.FALSE, execute(search("true && (null || false)"))); assertEquals(Boolean.FALSE, execute(search("true && (false || null)"))); assertEquals(Boolean.TRUE, execute(search("true && (true || null)"))); assertEquals(Boolean.TRUE, execute(search("true && (null || true)"))); // Empty things are treated like null. assertEquals(Boolean.TRUE, execute(search("list() == null"))); assertEquals(Boolean.TRUE, execute(search("'' == null")));
Der Operator toBoolean ist neu und konvertiert einen Wert explizit in einen der beiden boolschen Werte true oder `false.
Test
- test.com.top_logic.model.search.expr.TestSearchExpression.testOrChains()
- test.com.top_logic.model.search.expr.TestSearchExpression.testBooleanExpressions()