qqg911
qqg911

Reputation: 1

circular dependency between identifiers

I'm learning dart, I have questions. Used google translator. I apologize for possible inaccuracies.

class A {
  // no errors when compile code
  static int x = y;
  static int y = x;
}

void main() {
  /* compile error
  int a = b;
  int b = a;
  */
  print(y);
  print(x);
}

// no errors when compile code
int x = y;
int y = x;

If non-top-level identifiers are used, then the same principle as in c/c++ is used. If identifier a uses identifier b, then identifier b must be higher in the code.

But for top-level identifiers, the situation is somehow different. Probably, this was done for convenience in the case of a cyclic relationship between functions, classes, that is, strange situations. An example of a situation is this. If two variables refer to each other, then an error occurs and a recursive initialization attempt occurs. That is, the variables behave like functions that call each other.

  1. Why is the behavior of local and non-local variables different?
  2. Why does recursion occur? Are variables all treated as getters/setters?
  3. At the top level of the code, identifiers can refer to each other, while the order of their description in the file does not matter?
  4. For local variables, does the principle described above from C++ apply?
  5. For static class members, the same logic applies as for top-level variables?

If you assign a value to the x variable inside main, then there will be no error due to recursion, in this case, apparently, the original initializer is ignored.

main() {
  x = 1;
  print(x);
  print(y);
}

int x = y;
int y = x;

If it does not make it difficult to answer the question, indicate its number.

Upvotes: 0

Views: 92

Answers (1)

lrn
lrn

Reputation: 71773

In short:

  1. Because local variables are declared during statement execution, which has ordering, and non-local variables are not.

  2. Yes. Non-local variables are getters/setters.

  3. Correct.

  4. Yes. Local ariables can only be used after their declaration has been executed.

  5. Yes.

In general, you cannot read a variable before it has been initialized. What that means depends on the variable.

A local variable is initialized when statement execution reaches the declaration. That means that you cannot refer to local variables until after the declaration. A non-nullable local variable with no initializer expression (like int x;) is not initialized when it's executed. You must assign to it before you can read it. It's usually possible for static analysis to figure out whether a variable has been initialized, and that makes it a compile-time error to access the variable before it's definitely assigned. (Parameters are local variables which are always initialized when the function is entered, so they are simpler.)

Outside of statement code, there is no order to execution, which is why local and non-local variables behave differently.

Global (top-level/static, which are treated the same) variables with initializer expressions (Foo x = somethingFoo();) are initialized lazily when they are first read or written to. The ordering of these declarations do not matter. If the variable has no initializer, it must be nullable, and is treated as having = null as initializer (unless late).

Instance variables are initialized when the object is created, by the constructor initializer list, which means they are always initialized when you have a reference to the object.

A local or instance variable marked late is lazily initialized when read or written, just as top-level variables. If it has no initializer expression, it's a run-time error to read before the variable has been written.

All non-local variables are treated as a pair of a getter and setter (unless final and non-late, then it's just the getter).

Here is a quick summary of the ways to declare variables:

Variable Type Initialized Can assign
Parameter int x on function entry Any time
final int x on function entry Never
Local int x ; When definitely assigned to. Any time
int? x ; When executed, to null. Any time
int x =4; When executed, to 4 Any time
final int x ; When definitely assigned. When definitely unassigned.
final int x =4; When executed, to 4 Never
late int x ; When assigned. Any time
late int x =4; When read (to 4) or assigned. Any time
late final int x ; When assigned. Any time, throws if already assigned.
late final int x =4; When read, to 4 Never
Static or top-level static int x ; INVALID
static int? x ; When read, to null, or assigned. Any time.
static int x =4; When read or assigned. Any time
static final int x ; INVALID
static final int x =4; When read or assigned. Never
static late int x ; When assigned. Any time, throws if not assigned.
static late int x =4; When read (to 4) or assigned. Any time, throws if not assigned.
static late final int x ; When assigned. Any time, throws if already assigned.
static late final int x =4; When read, to 4 Never
Instance int x ; By constructor. Any time
int? x ; By constructor, to null if not otherwise. Any time
int x =4; By construction. Any time
final int x ; By constructor. Never
final int? x ; By constructor, to null if not otherwise. Never
final int x =4; By construction. Never
late int x ; By constructor or when assigned Any time, throws if not assigned
late int x =4; By constructor, when read or when assigned Any time, throws if not assigned.
late final int x ; By constructor or when assigned. Any time, throws if already assigned
late final int x =4; When read. Never

Example code showing this: https://dartpad.dev/?id=c239a391f58e69684f77dda9d4922dac

Upvotes: 1

Related Questions