Skip to content

Instantly share code, notes, and snippets.

@lrhn
Last active August 24, 2016 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lrhn/45bdae95e017ebbf7a84bfbe26dffcae to your computer and use it in GitHub Desktop.
Save lrhn/45bdae95e017ebbf7a84bfbe26dffcae to your computer and use it in GitHub Desktop.
Dart Assert in Initializer List - Design Document

Asserts in Initializer List

Lasse Nielsen (@lrhn)

Status: Experimental

(See: http://github.com/dart-lang/sdk/issues/24841, http://github.com/dart-lang/sdk/issues/27141)

In some cases, you want to validate your inputs before creating an instance, even in a const constructor. To allow that, we plan to test the possibility of allowing assert statements in the initializer list of a generative constructor.

We will start by implementing it in the VM behind a flag, with at least syntax support from the analyzer and possibly the formatter.

Syntax

The syntax will be changed to allow an assert statement without trailing semicolon (just the assert(expression)) to appear as an item in the initializer list. Example:

   C(x, y) : this.foo = x, assert(x < y), this.bar = y;

The assert can occur anywhere in the list where an initializing assignment can.

Semantics

The initializer list assert works the same way as an assert in a function body (with special treatment for asserts in a const constructor's initializer list, see next section). The assert expression is evaluated in the initializer list scope, which does not have access to this. The behavior is effectively:

  1. evaluate the expression (in the initializer list scope) to a result, o.
  2. If o implements Function, call it with zero arguments and let r be the return value,
  3. otherwise let r = o.
  4. Perform boolean conversion on r. This throws if r is not an instance of bool.
  5. if r isn't true, the assertion throws an AssertionError.

Here step 2 and 4 may throw before reaching step 5, in which case that is the effect of the assert.

The assert statement is evaluated at its position in the initializer list, relative to the left-to-right evaluation of initializer list entries.

As usual, assert statements have no effect unless asserts are enabled (e.g., by running in checked mode).

Const Semantics

If the constructor is a const constructor, the expression in the assert must be a potentially compile-time constant expression. If it isn't, it is a compile-time error, the same way a non-potentially compile-time constant initializer expression is.

Further, the expression should not evaluate to a function, since we can't call functions at compile time. We can't prevent it from evaluating to a function, but the function cannot not be called. To account for this, the behavior above is changed for const constructor initializer list asserts:

Step 2 above is dropped for an assert in a const constructor initializer list.

The change is entirely syntax driven - an assert inside a const constructor initializer list does not test whether the expression is a function, not even when the constructor is invoked using new. This change from the current specification is needed because asserts previously couldn't occur in a (potentially) const context.

During a const constructor invocation (that is, when the const constructor is invoked using the "const" prefix), if the assert fails, either due to boolean conversion when r is not a boolean value or due to assertion failure when r is false, it is treated like any other compile-time throw, and it causes a compile-time error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment