I have this code :
void main() {
RethinkDb r = RethinkDb();
Connection connection;
UserService sut;
setUp(() async {
connection = await r.connect(host: "127.0.0.1", port: 28015);
await createDb(r, connection);
sut = UserService(r, connection); // second line
});
test('creates a new user documenet in database', () async {
final user = User(
userName: 'test',
photoUrl: 'url',
active: true,
lastSeen: DateTime.now(),
);
final userWithId = await sut.connect(user); // first line
expect(userWithId.id, isNotEmpty);
});
}
I'm having an error on "first line" that says that the sut
variable must be initialized, but when you look at "second line", you can see that the sut
is indeed initialized, and the setUp()
function is called before the test()
.
There are cases where you don't need to explicitly use late
even with non-nullable variables with no initial value. For example:
void main() {
int x;
x = 42;
print(x);
}
or:
import 'dart:math';
void main() {
int x;
if (Random().nextBool()) {
x = 1;
} else {
x = 0;
}
print(x);
}
In those cases, through control flow analysis, the compiler can guarantee that all code paths result in x
being initialized before it's used.
but when you look at "second line", you can see that the
sut
is indeed initialized, and thesetUp()
function is called before thetest()
.
The problem is that the semantics of setUp()
being called before test()
(or more precisely, that setUp
's callback is executed before test
's callback) is the behavior described by the test framework, not by the language. It's non-trivial for the compiler to determine that the setUp
callback is guaranteed to be executed before the test
callback. Determining that would involve performing flow analysis on the implementations of those functions (and of any functions they call, and so on), which could be prohibitively expensive.
That's the whole reason why the late
keyword exists: to tell the compiler that you know more than it does. Using late
means that you personally guarantee that the variable will be initialized before it's used.