Conditional ternary expressions

A conditional ternary expression uses the Boolean value of one expression to decide which of two other expressions to evaluate. A question mark (?) separates the conditional expression from the alternatives, and a colon (:) separates the alternatives from each other. In some programming languages, ternary expressions are known as using the conditional operator or ternary operator, which has three operands instead of two.

If your test is for a null value, you can use the null-safe default operator to produce even more concise code.

Syntax

conditionalExpression ? trueExpression : falseExpression

The second and third operands that follow the question mark (?) must be of compatible types.

At run time, Gosu evaluates the first operand, the conditional expression. If the conditional expression evaluates to true, Gosu evaluates the second operand, the expression that follows the question mark. Gosu ignores the third operand, the expression that follows the colon. Conversely, if the conditional expression evaluates to false, Gosu ignores the second operand, the true expression, and the evaluates the third operand, the false expression.

Examples

Ternary expression

Evaluation result at run time

x > y ? x : y

The smaller of the two values, x and y

print(myNumberVar > 10 ? "Bigger than 10" : "10 or less")
  • If the value of myNumberVar is greater than 10, Gosu prints Bigger than 10.
  • If the value of myNumberVar is 10 or less, Gosu prints 10 or less.

Ternary expression types at run time and compile time

At run time, the type of a ternary expression is the type of the true expression or the false expression, depending on the result of evaluating the conditional expression. The true and false expressions often, but not always, evaluate to the same type.

Important: If the true and false expression types evaluate to different runtime types, you must ensure that your code that uses the result checks the type before performing type-specific actions.

At compile time, if the true and false expressions are of different types, Gosu reconciles the type of the ternary expression to the type of their nearest common ancestor. Gosu requires that the types of the true and false expressions in a ternary expression be compatible so that Gosu can reconcile their types. If the expressions have no common ancestor, the type at compile time of the ternary expression is Object.

For example, consider the following ternary expression.

var ternaryResult = aContact.Status == "new" ? "hello" : false

In the example, the true expression is of type String and the false expression is of type Boolean. If at run time the contact is new, ternaryResult is of type String, and its value is hello. If the contact is not new, ternaryResult is of type Boolean, and its value is false. Although the true expression and the false expression are of different types, their types are compatible because String and Boolean both descend from Object. The following example explicitly sets the type to Object.

// The type of a ternary expression is the common acestor type of its true and false expressions. 
var ternaryResult : Object = aContact.Status == "new" ? "hello" : false

At run time, the type evaluation of the ternary expression and the ternaryResult variable depends on the current state of the system. Different type checking keywords produce different results. For example, if the contact in the following example is new, ternaryResult is of type String.

var ternaryResult = aContact.Status == "new" ? "hello" : false

print(ternaryResult typeis Object)
print(ternaryResult typeis String)
print(ternaryResult typeis Boolean)
print(typeof ternaryResult)
The preceding code produces the following output.
true
true
false
java.lang.String
If the contact in the example is not new, ternaryResult is of type Boolean. The preceding code produces the following output.
true
false
true
java.lang.Boolean

Ternary expression type of a null value

If the result of a ternary expression is null, the runtime type of the result is void.

The following example demonstrates this behavior:
var testNotNull = false ? null : 7
print ("Result is ${testNotNull} ... type = ${typeof testNotNull}")

var testNull = true ? null : 7
print ("Result is ${testNull} ... type = ${typeof testNull}")
The output is the following lines:
Result is 7 ... type = java.lang.Integer
Result is null ... type = void

Primitive type coercion and ternary expressions

If the true or false expression in a ternary expression is of a primitive type, such as int or boolean, Gosu first coerces the primitive type to its boxed version. For example, Gosu coerces the primitive type boolean to its boxed type Boolean. Then, Gosu searches the type hierarchy for a common ancestor type of both the true and false expressions.

The following examples use a primitive float type and a boxed Float type to demonstrate how a ternary expression evaluates these types:
var prim = 7 as float
var boxed : Float = prim

var r = false ? null : prim
print ("Result is ${r} ... type = ${typeof r}")

var r2 = false ? null : boxed
print ("Result is ${r2} ... type = ${typeof r2}")
Running the code shows that the type is java.lang.Float for the primitive and boxed expressions:
Result is 7 ... type = java.lang.Float
Result is 7 ... type = java.lang.Float

Nested use of ternary expressions

Gosu supports the nesting of ternary expressions. The second and third operands, the true and false expressions, can themselves be ternary expressions. The ternary operator is syntactically right-associative.

For example, the nested ternary expression a ? b : c ? d : e ? f : g evaluates with the explicit order of precedence a ? b : (c ? d : (e ? f : g)). At run time, the ternary expression reduces to one of the expressions bdf, or g.

See also