class X extends Y {
X(int a, int b) : super(a,b);
}
Can someone give me an explanation about the syntax meaning of the colon :?
This feature in Dart is called "initializer list".
It allows you to initialize fields of your class, make assertions and call the super constructor.
This means that it is not the same as the constructor body. As I said, you can only initialize variables and only access static members. You cannot call any (non-static) methods.
The benefit is that you can also initialize final variables, which you cannot do in the constructor body. You also have access to all parameters that are passed to the constructor, which you do not have when initializing the parameters directly in the parentheses.
Additionally, you can use class fields on the left-hand of an assignment with the same name as a parameter on the right-hand side that refers to a parameter. Dart will automatically use the class field on the left-hand side.
Here is an example:
class X {
final int number;
X(number) : number = number ?? 0;
}
The code above assigns the parameter named number to the final field this.number if it is non-null and otherwise it assigns 0. This means that the left-hand number of the assignment actually refers to this.number. Now, you can even make an assertion that will never fail (and is redundant because of that, but I want to explain how everything works together):
class X {
final int number;
X(number): number = number ?? 0, assert(number != null);
}
Learn more.
It's ok to access non static member in initializer list.
class Point {
num x, y;
Point(this.x, this.y);
Point.origin(): this.x = 10, this.y = 10;
}
main() {
Point p = Point.origin();
print(p.x); // 10
}
Related
Let's say I have this class:
class Class<T extends num> {
const Class(this.n);
final T n;
#override
String toString() {
return 'Class<$T>(n: $n<${n.runtimeType}>)';
}
}
When I run this code:
for (final n in <num>[0.3, 2, -4]) {
final instance = Class(n);
print('$instance');
}
final instance = Class(1);
print('$instance');
I get this output:
Class<num>(n: 0.3<double>)
Class<num>(n: 2<int>)
Class<num>(n: -4<int>)
Class<int>(n: 1<int>)
Why doesn't Dart use the actual type of the number? Why use the List generic?
Type arguments for generics (and similarly, type inference) are handled at compilation-time. They can use only statically known times, not runtime types. For example, Class<n.runtimeType> is not valid.
When you iterate over your List<num>, each element n is statically known only to be a num, so Class(n) is inferred to be Class<num>.
When you use Class(1), 1 is an int literal, so the type of the expression is inferred to be Class<int>.
I'm a beginner learning dart from the book dart apprentice and I reached where they were discussing constructors in dart classes, the book was implying that constructors create instances of the class which I understood but I needed more info about constructors. So I googled and some results repeated what was already in the book about it being used to create instances of a class while others also showed that it's used to instantiate class properties, but my problem is with the other answer which I found that they are used to instantiate properties of a class, but my question is: I instantiate all class properties when I create the class by declaring the property variables, like this:
class UserClass{
userClassProperty = "";
anotherUserClassProperty = ""; }
why is the constructor also needed to instantiate class properties?
Often, values are unique to every class instance.
Consider the following example:
class Point {
final int x;
final int y;
const Point(this.x, this.y);
double get distanceToOrigin => sqrt(x * x + y * y);
}
If the x and y values were defined inside the class, it would be pretty useless. Instead, different Point objects can be instantiated with different values, which means the same code can be used for different situations.
Ok, so constructors instantiate or start a class by collecting all the data the class needs to start to start working. Constructors are so important that the dart compiler provides one even if you don't explicitly create one. For example, you create a class for mammals like this :
class Mammal{
String name = "cat";
int numberOfLegs = 2;
}
Although you don't explicitly add a constructor the dart compiler adds a default constructor like this :
class Mammal{
Mammal(); //This is added by dart during the class instantiation by default.
String name = "cat";
int numberOfLegs = 2;
}
Yeah, that's how crucial constructors are to the dart compiler.
And on the topic of why are they necessary even when you declare all the properties by yourself in the class, as hacker1024 said it would make the class pretty useless, as the point of the existence of classes is to create variants but with different properties. Not adding a constructor to your class and defining all the properties in the class would mean that your class doesn't take property arguments which in turn also means that different variants of your class can't be created. Again this goes directly against the point of the existence of dart classes. For example, you have a class like this :
class Mammals{
Strig name = "Human";
int numberOfLegs = 2;
bool hasFur = false;
}
final cat = Mammal();
final human = Mammal();
print(cat.numberOfLegs); //Prints 2
//2
print(human.numberOfLegs); //Also prints 2
//2
print(cat.hasFur);
// false
Yeah, this class is problematic. Cats with 2 legs? You would agree with me that that's not how things are in reality. And also the class is pretty useless in the sense that it's not modular, no matter which kind of mammal we create be it a cat, a sheep or even a cow the name property is going to be the default one we set, that is "Human". When we create a class to simulate mammals we want to be able to define what kind of properties it has, not use some fixed values. So you want to create a class which has a constructor like this :
class Mammals{
Mammals(String name,int noOfLegs, bool hasFur){
this.name = name;
this.noOfLegs = noOfLegs;
this.hasFur = hasFur;
}
String name = "";
int noOfLegs = 0;
bool hasFur = False;
}
final cat = Mammal("Cat", 4, True); //Now you can pass in the properties ou want.
final human = Mammal("Human", 2, false);
print(cat.name); //This prints the customized name of the object cat instead of some fixed value
//Cat
print(human.name); //This prints the customized name of the object human
Now we have two instances of the class with separate property values.
Although this adds a little more code, the modularity benefit is worth it.
This code is from flutter gallery and i'm trying to understanding and adapting it. I would know what this syntax means:
class DemoItem<T> {
DemoItem({
this.valueName,
this.hintName,
this.valueSurname,
this.hintSurname,
this.builder,
this.valueToString
}) : textController = new TextEditingController(text: valueToString(valueName));
Especially i would know what means the colon after the constructor and if there is a way to define another TextEditingController, in addition to the one already defined.
The part after : is called "initializer list". It is a ,-separated list of expressions that can access constructor parameters and can assign to instance fields, even final instance fields. This is handy to initialize final fields with calculated values.
The initializer list is also used to call other constructors like : ..., super('foo').
Since Dart version 2.0 the initializer list also supports assert(...) which is handy to check parameter values.
The initializer list can't read from this because the super constructors need to be completed before access to this is valid, but it can assign to this.xxx.
Pointing out as mentioned in the comments by user693336:
This also means the initializer list is executed before the constructor body. Also the initializer lists of all superclasses are executed before any of the constructor bodies are executed.
Example (copied from https://github.com/dart-lang/language/issues/1394):
class C {
final int x;
final int y;
C(this.x) : y = x + 1;
}
To elaborate on other answers and to complete the syntax, it is also possible to have a real body for the constructor along with initializer code
NonNegativePoint(this.x, this.y) : assert(x >= 0), assert(y >= 0) {
print('I just made a NonNegativePoint: ($x, $y)');
}
^ Here the assertions happen before the execution of the body
Another use case is to assign values to final fields before body executes
final num x;
final num y;
Point.fromJson(Map<String, num> json) : x = json['x'], y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
I am trying to implement bigint class in c++, it's not completed yet, i have encountered some errors that i am unable understand.
I have erased all other functions (as they are unnecessary in this case)
and karatsuba is not yet completed (but that should't pose a problem in this case).
In the multiply function (overloaded * ) my compiler gives an error:
passing 'const BigInt' as 'this' argument discards qualifiers [-fpermissive]
at line
ans.a = karatsuba(n,m);
I understand that this would occur when i am trying to change a constant object or object passed to a constant function, in my case i am merely creating a new vector and passing it to karatsuba function.
Removing const from overloded * gets rid of this error.
So,does this mean that a constant function can't change anything at all? (including local variables?)
class BigInt {
typedef long long int ll;
typedef vector<int> vi;
#define p10 1000000000;
#define range 9
vi a;
bool sign;
public:
BigInt operator * (const BigInt &num) const
{
vi n(a.begin(),a.end()),m(num.a.begin(),num.a.end());
BigInt ans;
ans.sign = !(sign ^ num.sign);
while(n.size()<m.size()) n.push_back(0);
while(n.size()>m.size()) m.push_back(0);
ans.a = karatsuba(n,m);
return ans;
}
vi karatsuba(vi a,vi b)
{
int n = a.size();
if(n <= 16)
{
// some code
}
// some code
return a;
}
};
Ok so after googling a bit more, i realized that this pointer is implicitly passed to the oveloaded * and then on to karatsuba (as it is a member function of the class), and as karatsuba is not a constant function, there is no guarantee that it won't change the object contents, hence this error is triggered.
One solution is to declare karatsuba as static, as static member functions don't receive this pointer (they can even be called with out a class object simply using :: operator) , read more about them from here Static data members and member functions.
All that is needed to be changed is :-
static vi karatsuba(vi a,vi b)
{
int n = a.size();
if(n <= 16)
{
// some code
}
// some code
return a;
}
I don't really understand how required works. For example I've seen this code:
class Test{
final String x;
Test({
required this.x
});
factory Test.initial(){
return Test(x: "");
}
}
But what should required do here? Seems like it makes an optional parameter a non optional parameter.
Update
As of Dart 2.12, the required keyword replaces the #required meta annotation. For detailed info look into the official FAQ. The following answer has been updated to reflect both this and null safety.
Parameters required by default
The parameters of a class constructor or function are required by default.
class Test {
final String x;
Test(this.x);
}
You're not allowed to do this:
final value = Test();
// 1 positional argument(s) expected, but 0 found.
You must do this:
final value = Test('hello');
Optional named parameters
If you surround a parameter with curly braces, though, in addition to becoming a named parameter, it also becomes optional.
Since it's optional, the property must either be nullable like this:
class Test {
final String? x;
Test({this.x});
}
Or it has to have a default value like this:
class Test {
final String? x;
Test({this.x = ''});
}
So now this is ok:
final value = Test();
And so is this:
final value = Test(x: 'hello');
Required named parameters
Sometimes you don't want to allow a parameter to be null and there is no natural default variable. In that case you can add the required keyword in front of the parameter name:
class Test {
final String x;
Test({required this.x});
}
This is not ok anymore:
final value = Test();
// The named parameter 'x' is required, but there's no corresponding argument.
But this is still fine:
final value = Test(x: 'hello');
Dart 2.12 (null safety):
Beginning with Dart 2.12, the #required annotation is now replaced by the required keyword. You should mark your field required if it is mandatory for others to pass some value to it.
For example:
class Foo {
final int a; // Mandatory? Use 'required'
final int b; // Not mandatory? Don't use 'required'
Foo({
required this.a, // Marked 'required'
this.b = 1,
});
}
Usage:
Foo(); // Error: 'a' is required
Foo(a: 0); // Good
Foo(a: 0, b: 1); // Good
#required is an annotation that will create a warning for you to remember that the named parameter is necessary for the class to work as expected.
It will not create compile errors, at least for what I know.
#required bounds you to pass #required marked arguments while creating object of Class. For example, while showing a dialog, you'd mark context as required since, you cannot show dialog without having a valid context. But, you should not overuse it.
Short answer: Named parameters are optional by default in Dart. We prefer them to positional params for ease of use. In this case, the named parameters also might be expected to hold some value all the time (non-nullable) - from initialization itself. Hence, the double effort.
He could use default value initialization of the parameters instead of 'required', if the values were compile-time constants, and that doesn't seem to be the case here.
Positional parameters can be required or optional, which we pass in order when calling. The following is an example of required positional parameters' usage:
class Object{
String name;
int value;
Object(this.name, this.value=100); //auto type inference
}
final one = Object("Name here", 50); // All parameters are needed to call.
Named parameters are another type of optional parameters. Flutter APIs use named parameters and in our UI code, it is preferred to use named parameters instead of positional parameters. Reason being readability and clarity when reading code or calling the constructors later on at several parts of the code. You would have seen this as the case with all Widgets, Styles. For if it were to be positional it would be difficult to keep track of them upon calling with the sheer amount of methods that would be in use, and dynamic type inference could also be at work.
void display({required String name, int value1, int value2=100}) {...;} //named params
display(value1: 50, name: "Calculated name");
NOTE:
If exists, required positional parameters have to come first. Either named or optional positional params can follow(NOT BOTH).
String say(String from, String msg, [String? device]) { //req. pos params and opt pos params.
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
Remove
required
in constructor.
Instead write
final String? x;
So, it becomes as:
class Test{
final String? x;
Test({
this.x
});
factory Test.initial(){
return Test(x: "");
}
}