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
conditionalExpression
inassert
statements, and no changes would be made to the treatment of conditions inif
,while
, anddo .. while
statements. - The language specification could be changed such that
assert
statements would accept a general **expression
. Again, the syntax forif
,while
, anddo
..while
statements would remain unchanged. - The language specification could be changed to require a
conditionalExpression
inassert
statements and inif
,while
, anddo
..while
statements.
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.