circular dependency between identifiers - dart

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.
Why is the behavior of local and non-local variables different?
Why does recursion occur? Are variables all treated as getters/setters?
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?
For local variables, does the principle described above from C++ apply?
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.

In short:
Because local variables are declared during statement execution, which has ordering, and non-local variables are not.
Yes. Non-local variables are getters/setters.
Correct.
Yes. Local ariables can only be used after their declaration has been executed.
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

Related

Why dart type casting affects the original casted variable

I am learning dart programming language version 2.14.3 and came across an odd issue that I am unable to understand.
The following code doesn't compile obviously because isEven is only defined in int class.
void main() {
const num someNumber = 3;
print(someNumber.isEven);
}
However, casting someNumber to int and assigning the value to a different variable, solved the problem and the code compiles with print(someNumber.isEven); not changed. The following code compiles.
void main() {
const num someNumber = 3;
final someInt = someNumber as int;
print(someNumber.isEven);
}
Is this a bug in dart or a language feature that I am not aware of?
When you do:
final someInt = someNumber as int;
print(someNumber.isEven);
If the cast fails, an uncaught TypeError will be thrown and exit your function. Therefore, the compiler can logically deduce that, if print(someNumber.isEven) is reached, someNumber must be an int. Therefore, on lines that follow the cast, the original object is promoted to the casted type. (Note that only local variables can be promoted.) Put another way, the cast acts as a type assertion; you don't need the someInt variable:
someNumber as int;
print(someNumber.isEven);
This is the same principle by which ! (which is basically a non-null cast operator) can promote a local nullable variable to be non-nullable and avoid the need to pepper ! for subsequent accesses to the same variable.

Memory usage of pass by value vs. pass by reference

For the past few days am trying to learn if pass by value and pass by reference impact the memory differently. Googling this query, people kept repeating themselves about a copy being created in terms of pass by value and how the original value is affected in terms pass by reference. But I was wondering if someone could zero in on the memory part.
This question actually depends heavily on the particular language as some allow you to be explicit and define when you want to pass a variable by value and when by reference and some do it always the same way for different types of variables.
A quite popular type of behavior is to use passing by value (by default) for simple times: like int, string, long, float, double, bool etc.
Let us show the memory impact on a theoretical language:
int $myVariable = 5;
at this moment you have created a one variable in memory which takes the size required to store an integer (let us say 32 bits).
Now you want to pass it to a function:
function someFunction(int parameter)
{
printOnScreen(parameter);
}
so your code would look like:
function someFunction(int $parameter)
{
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
...rest of the code //Position C
Since simple types are passed by value the value is copied in memory to another storage place - therefore:
during Position A you have memory occupied by ONE int (with value 5);
during Position B you have memory occupied by TWO ints (with values of 5) as your $myVariable was copied in memory
during Position C you have again memory occupied by ONE int (with value of 5) as the second one was already destroyed as it was needed only for the time of execution of the function
This has some other implications: modifications on a variable passed by value DO NOT affect the original variable - for example:
function someFunction(int $parameter)
{
$parameter = $parameter + 1;
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
During position A you set value of 5 under variable $myVariable.
During position B you pass it BY VALUE to a function which adds 1 to your passed value. YET since it was a simple type, passed by value, it actually operates on a LOCAL variable, a COPY of your variable. Therefore position C will again write just 5 (your original variable as it was not modified).
Some languages allow you to be explicit and inform that you want to pass a reference and not the value itself using a special operator -for example &. So let us again follow the same example but with explicit info that we want a reference (in function's arguments
- note the &):
function someFunction(int &$parameter)
{
$parameter = $parameter + 1;
printOnScreen($parameter);
}
int $myVariable = 5; //Position A
someFunction($myVariable); //Position B
printOnScreen($myVariable); //Position C
This time operation and memory implications will be different.
During Position A an int is created (every variable is always consisted of two elements: place in memory and a pointer, an identifier which place is it. For ease of the process let us say that pointer is always one byte). So whenever you create a variable you actually create two things:
reserved place in memory for the VALUE (in this case 32 bits as it was an int)
pointer (8 bits [1 byte])
Now during position B, the function expects A POINTER to a memory place. Which means that it will locally, for itself create only a copy of the pointer (1 byte) and not copy the actual reserved place as the new pointer WILLL POINT to the same place as the original one. This means that during operation of the function you have:
TWO POINTERS to an int in memory
ONE place reserved for VALUE of the int
Both of those pointer POINT to the same VALUE
Which means that any modification of the value will affect both.
So looking at the same example position C will not print out also 6 as inside the function we have modified the value under the SAME POINTER as $myVariable.
For COMPLEX TYPES (objects) the default action in most programming environments is to pass the reference (pointer).
So for example - if you have a class:
class Person {
public string $name;
}
and create an instance of it and set a value:
$john = new Person();
$john->name = "John Malkovic";
and later pass it to a function:
function printName(Person $instanceOfPerson)
{
printOnScreen($instanceOfPerson);
}
in terms of memory it will again create only a new POINTER in memory (1 byte) which points to the same value. So having a code like this:
function printName(Person $instanceOfPerson)
{
printOnScreen($instanceOfPerson);
}
$john = new Person(); // position A
printName($john); // position B
...rest of the code // position C
during position A you have: 1 Person (which means 1 pointer [1 byte] to a place in memory which has size to store an object of class person)
during position B you have: 2 pointers [2 bytes] but STILL one place in memory to store an object of class person's value [instance]
during position C you have again situation from position A
I hope that this clarifies the topic for you - generally there is more to cover and what I have mentioned above is just a general explanation.
Pass-by-value and pass-by-reference are language semantics concepts; they don't imply anything about the implementation. Usually, languages that have pass-by-reference implement it by passing a pointer by value, and then when you read or write to the variable inside the function, the compiler translates it into reading or writing from a dereference of the pointer. So you can imagine, for example, if you have a function that takes a parameter by reference in C++:
struct Foo { int x; }
void bar(Foo &f) {
f.x = 42;
}
Foo a;
bar(a);
it is really syntactic sugar for something like:
struct Foo { int x; }
void bar(Foo *f_ptr) {
(*f_ptr).x = 42;
}
Foo a;
bar(&a);
And so passing by reference has the same cost as passing a pointer by value, which does involve a "copy", but it's the copy of a pointer, which is a few bytes, regardless of the size of the thing pointed to.
When you talk about pass-by-value doing a "copy", that doesn't really tell you much unless you know what exactly the variable or value passed represents in the language. For example, Java only has pass-by-value. But every type in Java is either a primitive type or a reference type, and the values of reference types are "reference", i.e. pointers to objects. So you can never have a value in Java (what a variable holds or what an expression evaluates to) which "is" an "object"; objects in Java can only be manipulated through these "references" (pointers to objects). So when you ask the cost of passing a object in Java, it's actually wrong because you cannot "pass" an object in Java; you can only pass references (pointers to objects), and the copy the happens for pass-by-value, is the copy of the pointer, which is a few bytes.
So the only case where you would actually copy a big structure when passing, is if you have a language where objects or structs are values directly (not behind a reference), and you do pass-by-reference of that object/struct type. So for example, in C++, you can have objects which are values directly, or you can have pointers to them, and you can pass them by value or by reference:
struct Foo { int x; }
void bar1(Foo f1) { } // pass Foo by value; this copies the entire size of Foo
void bar2(Foo *f2) { } // pass pointer by value; this copies the size of a pointer
void bar3(Foo &f3) { } // pass Foo by reference; this copies the size of a pointer
void bar4(Foo *&f4) { } // pass pointer by reference; this copies the size of a pointer
(Of course, each of those have different semantic meanings; for example, the last one allows the code inside the function to modify the pointer variable passed to point to somewhere else. But if you are concerned about the amount copied. Only the first one is different. In Java, effectively only the second one is possible.)

Why does lacking explicit type declaration in parameter work when function is used directly, but not when it is passed to another function?

Have this function defined in your module:
module Data
int inc(x) = x + 1;
Type this in the console:
rascal> import Data;
rascal> import List;
This works:
rascal> inc(1);
int: 2
But this does not:
rascal> list[int] y = [1,2,3];
rascal> mapper(y, inc);
|rascal://<path>|: insert into collection not supported on value and int
☞ Advice
But it works if inc(...)'s parameter type is declared:
int inc(int x) = x + 1;
So why does not having this type declaration work for using the inc(...) function directly, but not for passing that function to mapper(...)?
Because Rascal's type checker is still under development, you are not warned if you make a small mistake like forgetting to provide a type for a function parameter. It may still work, accidentally, in some circumstances but you are guaranteed to run into trouble somewhere as you've observed. The reason is that type inference for function parameters is simply not implemented as a feature. This is a language design decision with the intent of keeping error messages understandable.
So, this is not allowed:
int f(a) = a + 1;
And, it should be written like this:
int f(int a) = a + 1;
I consider it a bug that the interpreter doesn't complain about an untyped parameter. It is caused by the fact that we reuse the pattern matching code for both function parameters and inline patterns. [edit: issue has been registered at https://github.com/cwi-swat/rascal/issues/763]
In your case the example works because dynamically the type of the value is int and addition does not check the parameter types. The broken example breaks because the interpreter does checks the type of the function parameter at the call-site (which defaulted to value for the untyped parameter).

How to get the address of a global variable in Fortran at initialization?

In C, I can initialize a pointer type global variable in this way:
<<file.h>>
extern int dummy;
extern int* p;
<<file.c>>
int dummy;
int* p = &dummy;
The advantage is that p is a const at link time. I do not need to write an init function to initialize p. Since in my case, value of 'dummy' is never used, I only need its address p and I won't change p.
I want to know how to achieve this in Fortran, i.e., getting the address of a variable without execution time initialization. I did the following, but did not succeed.
module mod
use, intrinsic :: iso_c_binding, only: c_ptr, c_loc
integer, target :: dummy
type(c_ptr), bind(c, name="p") :: p = c_loc(dummy)
end module mod
The compiler says "Error: Intrinsic function 'c_loc' at (1) is not permitted in an initialization expression"
I need this feature since I have a variable declared in Fortran. I need its address in C (to be used as a global var), but I don't want to call any Fortran init routines.

How to do Integer division in Dart?

I have trouble with integer division in Dart as it gives me error: 'Breaking on exception: type 'double' is not a subtype of type 'int' of 'c'.'
Here's the following code:
int a = 500;
int b = 250;
int c;
c = a / b; // <-- Gives warning in Dart Editor, and throws an error in runtime.
As you see, I was expecting that the result should be 2, or say, even if division of 'a' or 'b' would have a result of a float/double value, it should be converted directly to integer value, instead of throwing error like that.
I have a workaround by using .round()/.ceil()/.floor(), but this won't suffice as in my program, this little operation is critical as it is called thousands of times in one game update (or you can say in requestAnimationFrame).
I have not found any other solution to this yet, any idea? Thanks.
Dart version: 1.0.0_r30798
That is because Dart uses double to represent all numbers in dart2js. You can get interesting results, if you play with that:
Code:
int a = 1;
a is int;
a is double;
Result:
true
true
Actually, it is recommended to use type num when it comes to numbers, unless you have strong reasons to make it int (in for loop, for example). If you want to keep using int, use truncating division like this:
int a = 500;
int b = 250;
int c;
c = a ~/ b;
Otherwise, I would recommend to utilize num type.
Integer division is
c = a ~/ b;
you could also use
c = (a / b).floor();
c = (a / b).ceil();
if you want to define how fractions should be handled.
Short Answer
Use c = a ~/ b.
Long Answer
According to the docs, int are numbers without a decimal point, while double are numbers with a decimal point.
Both double and int are subtypes of num.
When two integers are divided using the / operator, the result is evaluated into a double. And the c variable was initialized as an integer. There are at least two things you can do:
Use c = a ~/ b.
The ~/ operator returns an int.
Use var c;. This creates a dynamic variable that can be assigned to any type, including a double and int and String etc.
Truncating division operator
You can use the truncating division operator ~/ to get an integer result from a division operation:
4 ~/ 2; // 2 (int)
Division operator
The regular division operator / will always return a double value at runtime (see the docs):
for (var i = 4; i == 4; i = 3) {
i / 2; // 2 (double)
}
Runtime versus compile time
You might have noticed that I wrote a loop for the second example (for the regular division operator) instead of 4 / 2.
The reason for this is the following:
When an expression can be evaluated at compile time, it will be simplified at that stage and also be typed accordingly. The compiler would simply convert 4 / 2 to 2 at compile time, which is then obviously an int. The loop prevents the compiler from evaluating the expression.
As long as your division happens at runtime (i.e. with variables that cannot be predicted at compile time), the return types of the / (double) and ~/ (int) operators will be the types you will see for your expressions at runtime.
See this fun example for further reference.
Conclusion
Generally speaking, the regular division operator / always returns a double value and truncate divide can be used to get an int result instead.
Compiler optimization might, however, cause some funky results :)

Resources