3: About dynamic
vs dynamic?
: they are the same.
Since dynamic
also represents nullable types, for the compiler it is the same of dynamic?
.
From Why operator ==(Object other) accepts a nullable argument?:
You can also see the analyzer and runtime will call it dynamic even if we check the signature of a method declared to return dynamic?:
void main() {
print(test.runtimeType); //runtimeType of the test function: () => dynamic
}
dynamic? test() { }
In fact a hint of the dart linter reports as 'unnecessary' the use of ?
in dynamic?
(as in Null?
):
The '?' is unnecessary because 'dynamic' is nullable without it. (unnecessary_question_mark).
Personally, I don't understand why dynamic?
Is only reported by a hint (which many people, myself included, don't notice) keeping it valid as a syntax.
1: A variable declared with Object?
type behaves like all other normal variables whose type is specified, such as String?
etc. Since every class -apart Null
(the type of null
)- is a subclass of Object (and since in Dart there are no primitive values as opposed to objects, unlike in Java; in Dart also null
, int
and bool
are objects. But forget this clarification, if you don't know Java), a variable declared with Object?
can contain any value. But the compiler will only allow access -after a null check- to the properties of Object (toString()
, ==()
, runtimeType
, etc).
A variable declared with dynamic
(or dynamic?
, see point 3) instead allows access to any public member: the compiler will not perform any checks (unless the property begins with an underscore _
, because in that case it is clear that it is not public); if you try to access a non-existent member you will instead have an error at runtime Note1. Furthermore, with dynamic
we also renounce null safety: dynamic
is equivalent to dynamic?
(in practice the question mark can be considered implicit, it is as if it were always there).
2: using var
, or final
-if you want an immutable reference- without declare the type, the compiler check the value assigned to the variable (in fact the omission of the type is not allowed if the variable is not initialized immediately) and treats the variable as if it were declared with that type.
dynamic
at runtime:
One use of 'dynamic' that can lead to confusion is with generic classes, because dynamic
as parametric type exists also at runtime:
with
dynamic obj = true;
obj at runtime has bool
type, but with
List list = [bool];
list at runtime has List<dynamic>
type.
However, using
var list2 = [true];
the parametric type is inferred correctly (list2 has List<bool>
runtimeType).
Note1 More precisely, a invocation such as myDynamicVariable.nonexistentMember
cause an invocation of the noSuchMethod()
method on the object; noSuchMethod()
can also be overridden and not throw any exception; but this is a rare practice, in Dart 2).