The language specification (Aug 19, 2015) states that an assert statement contains a parenthesized conditionalExpression. This feature changes assert to use a plain expression instead.
The motivation for having a conditionalExpression rather than a general expression in this syntactic location is not discussed in the specification, but it is likely to be a kind of safety device: A conditionalExpression covers only a subset of all expressions, and in particular it does not include assignments. An example which is often mentioned is that assert(x = 1) will be prevented syntactically, and the programmer may then note the error and change it to the more likely assert(x == 1).
However, the language specification takes different approaches in other, similar situations: An if statement, while statement, and do .. while statement all accept a general expression as the condition, whereas an argument to logical operators such as && and || must be an equalityExpression, and the argument to the negation operator ! must be a unaryExpression. The choices for logical operators are strongly motivated by the encoding of precedence rules in the grammar, but the choices for statements could as well have been conditionalExpression, had the intention been to avoid those well-known mistakes at the syntactic level.
It should be noted that when assert(x = e) is a mistake, it is relatively rarely the case that the type checks succeed: For x = e to be either of type bool or a function type taking no arguments and returning bool, e would have to have that type as well. This means that the problem is quite likely to be detected by the type checker, even if the grammar allows for a general expression. It should also be noted that no syntactic category can prevent side-effects in Dart, so the strict approach to assert which is taken in the specification does not help avoiding expressions with side-effects, it only prevents one example of side-effects. Finally, the work-around of using assert((x = e)) rather than assert(x = e) will be available if anyone insists on using such a construct.
Currently, the Dart tools treat assert(e) inconsistently: dart2js and the virtual machine parse e as an expression, and the analyzer parses e as a conditionalExpression.
The language team discussed several possible responses to this situation:
- The language specification could be enforced everywhere, i.e., all tools should then require a
conditionalExpressioninassertstatements, and no changes would be made to the treatment of conditions inif,while, anddo .. whilestatements. - The language specification could be changed such that
assertstatements would accept a general **expression. Again, the syntax forif,while, anddo..whilestatements would remain unchanged. - The language specification could be changed to require a
conditionalExpressioninassertstatements and inif,while, anddo..whilestatements.
We have chosen the second option, i.e., allowing an expression in assert statements.
The argument against the first option is that the reasons for having the more strict conditionalExpression in assert is weak in its own right, and no such strictness is enforced in other, similar situations. The argument against the third option is that it would be a major breaking change to use a different syntactic category in if, while, and do .. while statements, and the result would not be a strong protection against mistakes anyway. In contrast, the second option brings consistency, and the protection against mistakes is covered in a meaningful manner by the type system already.
Only one grammar rule is affected:
assertStatement: assert ‘(’ conditionalExpression ‘)’ ‘;’
is changed to
assertStatement: assert ‘(’ expression ‘)’ ‘;’
The description in the language specification (17.17, p125) starting 'The conditional expression e ..' and continuing to the end of the paragraph remains unchanged, except that the word 'conditional' is deleted.