struct definition with var instead of const in zig language - zig

I am now learning zig language. I have seen definitions of structs with const keyword like
const X = struct {
n: i32,
};
My understanding is that const is a kind of complementary to var, the latter allows change, the former does not. But what would mean defining struct with var?
var Y = struct {
n: i32,
};
Is this legal? I compiles, so yes, it is. But what is the meaning and use of this?

That compiles because zig is lazy evaluated. Because Y is not used, the compiler
doesn't check it.
When you reference it, the compiler throw an error:
Try this code
var Y = struct {
n: i32,
};
comptime {
#compileLog(Y);
}
error: variable of type 'type' must be constant
var Y = struct {
^
var is to declare variables. When you use var in a global scope, that creates a global variable.
In your case,
var Y = struct {
n: i32,
};
Declares Y as a variable of infered type. In this case, Y is a variable of type type.
In zig, there is comptime-only types, that is the case of type. A value where the type is comptime-only type only can live inside the compiler, you can't create the value in runtime1. So, the compiler needs always to comptime-known the value.
So, because Y is a global variable. You can modify it in runtime. That is the reason for the error. The value of Y cannot be generated/stored by the binary.
If only lives in the compiler, works
Try this code
comptime {
var Y = struct {
n: i32,
};
Y = struct {
count: u32,
};
const concrete = Y { .count = 10 };
#compileLog(concrete.count);
}
| 10
Appendix
1 For example, consider
Try this code
const std = #import("std");
fn compilerKnown(arg: []const u8) type {
return u64;
}
pub fn main() !void {
var runtimeValue = "hello world";
std.debug.print("{}\n", .{ compilerKnown(runtimeValue) });
}
error: unable to evaluate constant expression
std.debug.print("{}\n", .{ compilerKnown(runtimeValue) });
^
This is an error because zig try to compile the function compilerKnown into the binary, but the type type is comptime-only, so is unable to generate the binary. In particular, cannot generate the machine code for return u64.

Related

Type error when using List<int> variable as an argument to a List<double> method parameter

I'm learning the dart language, and I encountered this problem with lists.
I created a sum function to calculate the sum of a list, here is the code:
double sum(List<double> elements) {
var el = 0.0;
for (var elem in elements) {
el += elem;
}
return el;
}
And I call it from the main menu in 2 ways:
void main(List<String> args) {
var sm = sum([1, 3, 4, 6]);
print(sm)
}
And it worked fine. But when I try to use a middle variable:
var test = [1, 3, 4, 6];
var sm = sum(test);
print(sm);
I get an error :
Error: The argument type 'List<int>' can't be assigned to the parameter type
'List<double>'.
functions.dart:5
- 'List' is from 'dart:core'.
var sm = sum(test);
^
I know that i have to use List as i'm using list of int but it appears that that function I made could work with both types, double and int, but i can't understand the problem when I use a middle variable?
In your first example the list of int literals is automatically converted to double, which is a new feature of Dart 2.1. (source) - int literals get converted automatically to doubles in a double context:
var sm = sum([1, 3, 4, 6]);
Before that, you would experience a compilation error and would have to explicitly provide a double list as a parameter:
var sm = sum([1.0, 3.0, 4.0, 6.0]);
On your second example however, you are implicitly defining a List<int> variable, which cannot be passed as a List<double> parameter.

Why a const list can't be used in a string literal when it can't be modified in any way?

void main() {
const list = [1, 2, 3];
const string = 'This is a $list'; // Error
}
When I can't assign list a new value and modify any of its elements, why can't I then use the list in my string literal?
Dart doesn't have a concept of saying that a method call can be evaluated at compilation time (in contrast to constexpr in C++). Therefore Dart cannot guarantee that calling a method on a const object returns another const object, and that includes the implicit call to .toString() when doing string interpolation.
For example, this is perfectly legal:
import 'dart:math';
final random = Random();
class Foo {
const Foo();
// Returns a string that is clearly not a compile-time constant.
#override
String toString() => random.nextInt(100).toString();
}
void main() {
const foo = Foo();
print('$foo');
const list = [foo, foo, foo];
print('$list');
}
Note that this doesn't apply to .toString() implementations for some built-in types (e.g. null, numeric, string, and boolean types) since they are known to produce constant values and because Dart does not allow creating derived classes from those types, so they cannot be overridden to do shenanigans like the above example.
It's an interesting question, because some const things can be interpolated into const strings. I checked out the Language Tour, and it gives this example, which is very close to your question:
// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
The explanation given is that
Literal strings are compile-time constants, as long as any
interpolated expression is a compile-time constant that evaluates to
null or a numeric, string, or boolean value.
They don't explain why (what the technical reasons are, or the motivations for making the language work this way), but it's clear that a const list does not evaluate to "null or a numeric, string, or boolean value." So it just doesn't matter that your list is const—the string resulting from interpolation with that will not be a compile-time constant, so you can't use const with that string.

Why can a variable declared using 'var' be null in null-safe dart?

I'm copying this from the docs
// In null-safe Dart, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo();
But I'm running the code below in a null-safe dartpad, and it compiles.
void main() {
var x = null;
print(x);
}
Is this a documentation error or am I missing something?
Your example are not close to what the documentation are trying to explain. Try this instead:
void main() {
var x = 42;
x = null; // Error: A value of type 'Null' can't be assigned to a variable of type 'int' - line 3
print(x);
}
The reason is that var x = 42 is "Inferred to be an int" and not int?.
In your example, what happens is that var x = null are resolved so x are seen as the type dynamic since Dart have no clue about what type you are trying to use. Since dynamic can have the value null you are good to go.

What is the "const" keyword used for in Dart?

Can someone explain to me how/when/why to use const keyword, or it is just "a way to declare a constant variable"? If so, what's the difference between this :
int x = 5;
and
const int x = 5;
Could you guys please give me an example?
const means compile time constant. The expression value must be known at compile time. const modifies "values".
From news.dartlang.org,
"const" has a meaning that's a bit more complex and subtle in Dart.
const modifies values. You can use it when creating collections,
like const [1, 2, 3], and when constructing objects (instead of new)
like const Point(2, 3). Here, const means that the object's entire
deep state can be determined entirely at compile time and that the
object will be frozen and completely immutable.
if you use
const x = 5 then variable x can be used in a cosnt collection like
const aConstCollection = const [x];
if you don't use const, and just use x = 5 then
const aConstCollection = const [x]; is illegal.
More examples from www.dartlang.org
class SomeClass {
static final someConstant = 123;
static final aConstList = const [someConstant]; //NOT allowed
}
class SomeClass {
static const someConstant = 123; // OK
static final startTime = new DateTime.now(); // OK too
static const aConstList = const [someConstant]; // also OK
}
Here are some facts about const values:
The value must be known at compile time.
const x = 5; // OK
Anything that is calculated at runtime can't be const.
const x = 5.toDouble(); // Not OK
A const value means that it's deeply constant, that is, every one of its members is constant recursively.
const x = [5.0, 5.0]; // OK
const x = [5.0, 5.toDouble()]; // Not OK
You can create const constructors. That means that it is possible to create const values from the class.
class MyConstClass {
final int x;
const MyConstClass(this.x);
}
const myValue = MyConstClass(5); // OK
const values are canonical instances. That means that there is only a single instance no matter how many you declare.
main() {
const a = MyConstClass(5);
const b = MyConstClass(5);
print(a == b); // true
}
class MyConstClass {
final int x;
const MyConstClass(this.x);
}
If you have a class member that is const, you must also mark it as static. static means it belongs to the class. Since there is only ever one instance of const values, it wouldn't make sense for it to not be static.
class MyConstClass {
static const x = 5;
}
See also
Dart Const Tutorial – All You Need to Know (Const Expressions, Canonical Instances and More)

Difference between "var" and "dynamic" type in Dart?

According to this article:
As you might know, dynamic (as it is now called) is the stand-in type when a static type annotation is not provided.
So, what is the difference between dynamic and var? When to use?
dynamic is a type underlying all Dart objects. You shouldn't need to explicitly use it in most cases.
var is a keyword, meaning "I don't care to notate what the type is here." Dart will replace the var keyword with the initializer type, or leave it dynamic by default if there is no initializer.
Use var if you expect a variable assignment to change during its lifetime:
var msg = "Hello world.";
msg = "Hello world again.";
Use final if you expect a variable assignment to remain the same during its lifetime:
final msg = "Hello world.";
Using final (liberally) will help you catch situations where you accidentally change the assignment of a variable when you didn't mean to.
Note that there is a fine distinction between final and const when it comes to objects. final does not necessarily make the object itself immutable, whereas const does:
// can add/remove from this list, but cannot assign a new list to fruit.
final fruit = ["apple", "pear", "orange"];
fruit.add("grape");
// cannot mutate the list or assign a new list to cars.
final cars = const ["Honda", "Toyota", "Ford"];
// const requires a constant assignment, whereas final will accept both:
const names = const ["John", "Jane", "Jack"];
dynamic: can change TYPE of the variable, & can change VALUE of the variable later in code.
var: can't change TYPE of the variable, but can change VALUE of the variable later in code.
final: can't change TYPE of the variable, & can't change VALUE of the variable later in code.
dynamic v = 123; // v is of type int.
v = 456; // changing value of v from 123 to 456.
v = 'abc'; // changing type of v from int to String.
var v = 123; // v is of type int.
v = 456; // changing value of v from 123 to 456.
v = 'abc'; // ERROR: can't change type of v from int to String.
final v = 123; // v is of type int.
v = 456; // ERROR: can't change value of v from 123 to 456.
v = 'abc'; // ERROR: can't change type of v from int to String.
try this in DartPad:
void main() {
dynamic x = 'hal';
x = 123;
print(x);
var a = 'hal';
a = 123;
print(a);
}
you can change the type of x, but not a.
var, like final, is used to declare a variable. It is not a type at all.
Dart is smart enough to know the exact type in most situations. For example, the following two statements are equivalent:
String a = "abc"; // type of variable is String
var a = "abc"; // a simple and equivalent (and also recommended) way
// to declare a variable for string types
On the other hand, dynamic is a special type indicating it can be any type (aka class). For example, by casting an object to dynamic, you can invoke any method (assuming there is one).
(foo as dynamic).whatever(); //valid. compiler won't check if whatever() exists
(foo as var).whatever(); //illegal. var is not a type
var a ;
a = 123;
print(a is int);
print(a);
a = 'hal';
print(a is String);
When defined without initial value, var is dynamic
var b = 321;
print(b is int);
print(b);
//b = 'hal'; //error
print(b is String);
When defined with initial value, var is int in this case.
To clarify some of the previous answers, when you're declaring a variable as dynamic, it's type changes depending on what you assign to it. When you're declaring a var, the type is set once it's assigned something, and it cannot be changed after that.
For example, the following code:
dynamic foo = 'foo';
print('foo is ${foo.runtimeType} ($foo)');
foo = 123;
print('foo is ${foo.runtimeType} ($foo)');
will return the following result when run in DartPad:
foo is String (foo)
foo is int (123)
But the following code won't even compile:
var bar = 'bar';
print('bar is ${bar.runtimeType} ($bar)');
bar = 123; // <-- Won't compile, because bar is a String
print('bar is ${bar.runtimeType} ($bar)');
Long story short - use dynamic if you want a non-typed variable, use var when you want a typed variable with whatever type you assign to it.
Looking at the previous answers I hope this can clarify/summarize everything:
There are the keywords var, final, and const. These are to declare a variable (to indicate its existence) (Side note: Declaration vs Initialization)
Then there are types like String, int, List, dynamic, etc. (The type indicates what kind of value the variable should hold, this is for type safety)
Usually, we declare a variable by explicitly stating its type:
String a; // a is now a String type
int b; // b is now an int type
But we can also use the var keyword. By default, this sets the type of the variable to whatever it is initialized with. (This is called type inference)
var a = "hello"; // a is now a String type
var b = 5; // b is now an int type
Now what happens when you try to declare a variable with the var keyword, but don't initialize a value? How is it supposed to infer a type? Well, there is also a type called dynamic. This is different than the usual String or int in the sense that it allows for the variable to be assigned a value of any type (Usually there will be an error).
String a = "hello"; // a is now a String type
// var a = "hello"; // Alternative way; same as the line above because its type is inferred to be String
a = 5 // error: A value of type 'int' can't be assigned to a variable of type 'String'
dynamic b; // b is now a dynamic type
b = "hello"; // still a dynamic type, but now its value is of type String (You can use b.runtimeType to check)
b = 5; // dynamic type, but now its value is of type int
So to address the original confusion regarding the quote from the article,
As you might know, dynamic (as it is now called) is the stand-in type when a static type annotation is not provided.
It just means that if you don't explicitly state its type (you use var to declare a variable) and do so without initialization, it simply infers its type as dynamic:
var b; // b is now a dynamic type, the following will not have any errors.
b = "hello";
b = 5;
b = true;
Other notes:
Not sure why people started talking about final and const, but I think the accepted answer here explains it well if you want to know more.
dynamic a; and var a; is effectively the same: They both declare a variable of dynamic type.
Two ways of checking the type of a variable is using the is operator and using .runtimeType which works differently. See the following example:
dynamic b; // b is now a dynamic type, no value
print(b is dynamic); // true
print(b is Null); // true
print(b is String); // false
print(b is int); // false
print(b.runtimeType); // Null
b = "hello"; // dynamic type, String value
print(b is dynamic); // true
print(b is Null); // false
print(b is String); // true
print(b is int); // false
print(b.runtimeType); // String
b = 5; // dynamic type, int value
print(b is dynamic); // true
print(b is Null); // false
print(b is String); // false
print(b is int); // true
print(b.runtimeType); // int
One of aspect than can consider in comparison dynamic vs var is taking into account behavior when using var declaration with initialization at the same time there is not possibility to change type which in case of dynamic is.
But dynamic vs var is not the question what I would ask.
I would ask more what is difference between dynamic vs Object.
Here is a DO annotate with Object instead of dynamic to indicate any object is allowed.
It is hard to feel it at the beginning, but dynamic I would relate to generic type argument.
Both in dynamic and var,the variable can hold data of any data type, i.e., int , float,string,etc
If a variable is declared as a dynamic and if even initialised, its type can change over time.Try this code in https://dartpad.dev/
void main() {
dynamic x = 'abc';
x = 12345;
print(x);
}
If you declare variable as a var, once assigned type can not change.
void main() {
var x = 'abc';
x = 12345;
print(x);
}
The above code will result in the error stating that A value of type 'int' can't be assigned to a variable of type 'String' - line 3
BUT, if you state a var without initializing, it becomes a dynamic:
void main() {
var x ;
x = 'abc';
x=12345;
print(x);
}
A dynamic variable can change his type and a var type can't be changed.
For example :
var myVar = 'hello';
dynamic myDynamicVar = 'hello';
myVar = 123; // not possible
myDynamicVar = 123; // possible
dynamic is a data type that indicates all data types in dart
var is a variable declaration way like "final" that takes the data type of its value
If you use var you can't change the data type of the variable. But if you use dynamic you can change it freely.
for ex.
dynamic x = 12; // type: integer
x= "Hello world"; // type: string
This will work with no issues if you do the same using var instead of dynamic you will get an error since you can't change the data type because it is automatically assigned to the variable when initialized.
dynamic: can change the TYPE of the variable, & can change the VALUE of the variable later in the code.
var: can't change the TYPE of the variable, but can change the VALUE of the variable later in code

Resources