3

Ever since... well, the dawn of Apex Code, I've always presumed that the ternary operator evaluated both the true and false branches as part of its operation. Today, while playing around with them, I realized that only one branch is evaluated.

As a trivial example:

Integer a() {
    System.debug('a was called');
    return 5;
}
Integer b() {
    System.debug('b was called');
    return 10;
}
Integer c = Math.random()>=0.5? a(): b();

However, I was rather pleasantly surprised when I found that there was only one debug statement being called.

Going one step further, I then tested this on a set of queries:

Account a = Math.random()>=0.5?
    [SELECT Name FROM Account WHERE Name='Foo']:
    [SELECT Name FROM Account WHERE Name='Bar'];
System.assertEquals(1, Limits.getQueries());

This actually worked; only one query was used, as the other wasn't even evaluated.

In other words, ternary operators are exactly as described:

Ternary operator (Right associative). This operator acts as a short-hand for if-then-else statements. If x, a Boolean, is true, y is the result. Otherwise z is the result. Note that x cannot be null.

They're actually short-hand for if-then-else, even down to the fact that only one branch is evaluated!

However, the documentation doesn't explicitly call this out that I can tell. Can we rely on this behavior? Is there a place where this behavior is explicitly documented?

4
  • Not sure if you not checked them but same behaviour mentioned in docs as well developer.salesforce.com/docs/atlas.en-us.apexcode.meta/… Commented Sep 28, 2016 at 16:12
  • 4
    I'm not sure how you expect anyone to answer; you've basically already answered your own question. The operator functions exactly as described, and exactly like you'd expect.
    – Adrian Larson
    Commented Sep 28, 2016 at 17:19
  • 1
    Maybe stating what led to your presumption that both branches would be evaluated would provoke a better answer? Commented Sep 28, 2016 at 18:24
  • 2
    Ancient history: VB had an iif(b, t, f) which was actually a function so t and f were both evaluated and then passed to the function which then returned one of them depending on the value of b.
    – Keith C
    Commented Sep 28, 2016 at 18:30

2 Answers 2

1

I'm not sure what you're looking for, as the documentation seems to tell us exactly what the behavior should be, and that matches up with what we've observed. These two methods should be equivalent:

Integer x = 42, y = 0;
Integer evaluateTernary(Boolean input)
{
    return input ? x : y;
}
Integer evaluateIfThenElse(Boolean input)
{
    if (input) return x;
    else return y;
}

If you want to hold Salesforce to it, you could install this test class as a canary:

@IsTest
class TernaryContract
{
    class UnexpectedEvaluationException extends Exception {}

    static Id evaluate() { return UserInfo.getUserId(); }
    static Id noEvaluate()
    {
        throw new UnexpectedEvaluationException();
        return evaluate();
    }

    static testMethod void testTruthyEvaluation()
    {
        Test.startTest();
            Id evaluation = true ? evaluate() : noEvaluate();
        Test.stopTest();

        system.assertEquals(UserInfo.getUserId(), evaluation,
                            'The truthy value should be used');
    }
    static testMethod void testFalsyEvaluation()
    {
        Test.startTest();
            Id evaluation = false ? noEvaluate() : evaluate();
        Test.stopTest();

        system.assertEquals(UserInfo.getUserId(), evaluation,
                            'The truthy value should be used');
    }
}
7

I guess that the description of ternaries that you mention is the only available doc in Salesforce. However, AFAIK apex is based on Java so I assume that Java doc reference can also be applied to apex ternaries. This doc refers to ternaries as a shorthand of if-then-else as well with an extra example and explanation:

result = someCondition ? value1 : value2;

this operator should be read as: "If someCondition is true, assign the value of value1 to result. Otherwise, assign the value of value2 to result."

Plus, some reasons to use it:

Use the ?: operator instead of an if-then-else statement if it makes your code more readable; for example, when the expressions are compact and without side-effects (such as assignments).

But, in general, ternary operators are supported in different languages like C or C#, and, as far as I can tell, they are documented almost the same way, implicitly making out that only one branch is evaluated.

2
  • That last bit of the second quote almost seems to hint that they might both evaluate though. Otherwise, why would you care about the side-effects?
    – Adrian Larson
    Commented Sep 28, 2016 at 18:15
  • To be honest, I was wondering the same thing
    – Joca
    Commented Sep 28, 2016 at 18:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .