0

There is a discussion about dynamic and var before null-safety. Then what's the Object? between each of them?

  1. Is Object? == dynamic?
  2. How about var? and dynamic??
  3. Any difference between dynamic? and dynamic?

I see the official document about null-safety, but can't find the related topic.

Tokenyet
  • 4,063
  • 2
  • 27
  • 43

2 Answers2

5
  1. dynamic is a special type that disables static type-checking. You can attempt to call any method on a dynamic type. If the object turns out not to have such a method, then it will result in a runtime failure instead of a compile-time one.

    Object? is a base type suitable for referencing any object, including null. Unlike dynamic, it is statically type-checked, so you would get compile-time failures if you attempt to call most methods on it without explicitly checking the runtime type or without performing a cast.

  2. var? is not valid syntax. var is not a type; it declares a variable without explicitly specifying a type, allowing the type to be inferred.

    dynamic? is valid but is redundant. (See #3.)

  3. Variables of type dynamic can already include null, so adding a ? to make it nullable is redundant. The Dart analyzer will tell you so.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
2

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).

Mabsten
  • 1,570
  • 11
  • 16
  • 1
    I'd recommend strongly that you never write `dynamic?`. It's not more explicit than `dynamic`, just more verbose and potentially confusing to the reader. There is no history of using `dynamic` to mean a non-`null` object with dynamic access. – lrn Jul 29 '21 at 08:21
  • @lrn But then why admit the `dynamic?` syntax? We are talking about one of the main keywords of the language (regardless of whether some prefer to replace it with `Object?` and explicit type casts). Personally I had thought of some possible use case, for example to distinguish a parameter that can be valued with int, bool or String, from a parameter where the same types and also null are allowed; allowed types should be made explicit by the documentation, but `dynamic?` may remark that null is among the allowed types. – Mabsten Jul 29 '21 at 20:50
  • However you are right, there is no general convention for using `dynamic?` (And the few occurrences in packages curated by the Dart team have been removed, from what I have seen), so I will correct the answer. – Mabsten Jul 29 '21 at 20:51