class Foo {
int count; // Error
void bar() => count = 0;
}
Why I'm seeing an error when I'am already initializing it in the bar method? I could understand this error if count was marked final.
(Your code was fine before Dart 2.12, null safety)
With null safety, Dart doesn't know if you actually assigned a value to count. Dart can see initialization in three ways:
1. At the time of declaration:
int count = 0;
2. In the initializing formals parameters:
Foo(this.count);
3. In the initializer list:
Foo() : count = 0;
So, according to Dart, count was never initialized in your code and hence the error. The solution is to either initialize it in 3 ways shown above or just use the late keyword which will tell Dart that you are going to initialize the variable later.
4. Use the late keyword:
class Foo {
late int count; // No error
void bar() => count = 0;
}
5. Make variable nullable:
class Foo {
int? count; // No error
void bar() => count = 0;
}
Use the late keyword to initialize a variable when it is first read, rather than when it's created.
class Questionz {
late String questionText;
late bool questionAnswer;
Questionz({required String t, required bool a}) {
questionText = t;
questionAnswer = a;
}
}
in pubspec.yaml if you are using :
environment: sdk: ">=2.12.0 <3.0.0"
change to environment: sdk: ">=2.7.0 <3.0.0"
2.12.0 null safety feature is on &
2.7.0 null safety feature is off
tip : instead of copy change manually
for more info https://dart.dev/null-safety
for null safety use ? after variable like var a? and while using the variable use ! after variable , like : if(a!){}
IN my case i found giving ? and ! to the variable helpful:
double? _bmi; // adding ? to the double
String calculateBMI(){
_bmi=weight/pow(height/100, 2);
return _bmi!.toStringAsFixed(1);// adding ! to the private variable
}
String getResult(){
if(_bmi!>=25){ //adding ! to the private variable
return 'Overweight';
} else if (_bmi!>=18.5)
{
return 'normal';
}else{return 'underweight';}
Related
Learning Dart and using dart_code_metrics to ensure that I write code that meets expectations. One of the rules that is active is avoid-non-null-assertion.
Note, the code below was created to recreate the problem encountered in a larger code base where the value of unitString is taken from a JSON file. As such the program cannot control what is specified in the JSON file.
From pubspec.yaml
environment:
sdk: '>=2.15.0 <3.0.0'
// ignore_for_file: avoid_print
import 'package:qty/qty.dart';
void main() {
const String unitString = 'in';
// unit.Width returns null if unitString is not a unit of Length.
if (Length().unitWith(symbol: unitString) == null) {
print('units $unitString not supported.');
} else {
// The following line triggers avoid-non-null-assertion with the use of !.
final Unit<Length> units = Length().unitWith(symbol: unitString)!;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
If I don't use ! then I get the following type error:
A value of type 'Unit<Length>?' can't be assigned to a variable of type 'Unit<Length>'.
Try changing the type of the variable, or casting the right-hand type to 'Unit<Length>'.
Casting the right-hand side to
Unit<Length>
fixes the above error but cause a new error when instantiating Quantity() since the constructor expects
Unit<Length>
and not
Unit<Length>?
I assume there is an solution but I'm new to Dart and cannot formulate the correct search query to find the answer.
How can I modify the sample code to make Dart and dart_code_metrics happy?
Your idea of checking for null before using a value is good, it's just not implemented correctly. Dart does automatically promote nullable types to non-null ones when you check for null with an if, but in this case you need to use a temporary variable.
void main() {
const String unitString = 'in';
//Use a temp variable, you could specify the type instead of using just using final
final temp = Length().unitWith(symbol: unitString);
if (temp == null) {
print('units $unitString not supported.');
} else {
final Unit<Length> units = temp;
final qty = Quantity(amount: 0.0, unit: units);
print('Qty = $qty');
}
}
The basic reason for that when you call your unitWith function and see that it's not null the first time, there's no guarantee that the when you call it again that it will still return a non-null value. I think there's another SO question that details this better, but I can't seem to find.
I was following a PR for Flutter and came across this code:
if (chunkCallback != null) {
chunkCallback!(0, 100);
}
What does the exclamation mark mean after chunkCallback? Nothing I search on Google works.
"!" is a new dart operator for conversion from a nullable to a non-nullable type.
Read here and here about sound null safety.
Use it only if you are absolutely sure that the value will never be null and do not confuse it with the conditional property access operator.
chunkCallback is a nullable reference to a function.
If you are sure that chunkCallback can't be null at runtime you can "Cast away nullability" by adding ! to it to make compiler happy
typedef WebOnlyImageCodecChunkCallback = void Function(
int cumulativeBytesLoaded, int expectedTotalBytes);
...
class Class1 {
final WebOnlyImageCodecChunkCallback? chunkCallback;
Class1(this.chunkCallback);
void test() {
if (chunkCallback == null) {
throw Exception("chunkCallback is null");
}
chunkCallback!.call(0, 100);
}
}
Esentially, ! in this case is a syntactic sugar for
(chunkCallback as WebOnlyImageCodecChunkCallback).call(0, 100);
I think it is a shorthand syntax for “Casting away nullability”, as per the docs: https://dart.dev/null-safety/understanding-null-safety#null-assertion-operator
The variable chunkCallback must be able to accept null and you cannot call a function on a nullable type without either using ! or ?. This is part of Darts sound null safety
Some great videos on this:
Flutter vid
YouTube vid
Even though the conditional statement checks for null, Dart still requires the exclamation mark before the function call. The difference between using ! over ? is that it will throw an exception instead of using the variable if the value is null.
Some examples:
class Car {
String? make; // String or null type
Car([this.make]); // parameter is optional
}
main() {
Car test = Car('Ford'); // initialised with a value
Car test2 = Car(); // no value given so null is default
// returns 4
if (test.make != null) {
print(test.make!.length); // ! still needed even though !=null condition stated
} else {
print('The value is null');
}
// returns The value is null
if (test2.make != null) {
print(test2.make!.length);
} else {
print('The value is null');
}
}
Above example shows that conditional check for null is not enough.
And choosing between ? and !
class Customer {
String? name;
String? surname;
Customer(this.name, [this.surname]); // constructor with optional parameter []
}
main() {
Customer ford = Customer('John'); //only name is given a value
// calling a method on a nullable type doesn't work
// so ? and ! used here after variable name and before method
print(ford.name!.length); // operation executed as usual => 4
print(ford.surname?.length); // ? on null value returns null => null
print(ford.surname!.length); // Exception is thrown => TypeError
}
I would like to pass a primitive (int, bool, ...) by reference. I found a discussion about it (paragraph "Passing value types by reference") here: value types in Dart, but I still wonder if there is a way to do it in Dart (except using an object wrapper) ? Any development ?
The Dart language does not support this and I doubt it ever will, but the future will tell.
Primitives will be passed by value, and as already mentioned here, the only way to 'pass primitives by reference' is by wrapping them like:
class PrimitiveWrapper {
var value;
PrimitiveWrapper(this.value);
}
void alter(PrimitiveWrapper data) {
data.value++;
}
main() {
var data = new PrimitiveWrapper(5);
print(data.value); // 5
alter(data);
print(data.value); // 6
}
If you don't want to do that, then you need to find another way around your problem.
One case where I see people needing to pass by reference is that they have some sort of value they want to pass to functions in a class:
class Foo {
void doFoo() {
var i = 0;
...
doBar(i); // We want to alter i in doBar().
...
i++;
}
void doBar(i) {
i++;
}
}
In this case you could just make i a class member instead.
No, wrappers are the only way.
They are passed by reference. It just doesn't matter because the "primitive" types don't have methods to change their internal value.
Correct me if I'm wrong, but maybe you are misunderstanding what "passing by reference" means? I'm assuming you want to do something like param1 = 10 and want this value to still be 10 when you return from your method. But references aren't pointers. When you assign the parameter a new value (with = operator), this change won't be reflected in the calling method. This is still true with non-primitive types (classes).
Example:
class Test {
int val;
Test(this.val);
}
void main() {
Test t = new Test(1);
fn1(t);
print(t.val); // 2
fn2(t);
print(t.val); // still 2, because "t" has been assigned a new instance in fn2()
}
void fn1(Test t) {
print(t.val); // 1
t.val = 2;
}
void fn2(Test t) {
t = new Test(10);
print(t.val); // 10
}
EDIT
I tried to make my answer more clear, based on the comments, but somehow I can't seem to phrase it right without causing more confusion. Basically, when someone coming from Java says "parameters are passed by reference", they mean what a C/C++ developer would mean by saying "parameters are passed as pointers".
As dart is compiled into JavaScript, I tried something that works for JS, and guess what!? It worked for dart!
Basically, what you can do is put your value inside an object, and then any changes made on that field value inside that function will change the value outside that function as well.
Code (You can run this on dartpad.dev)
main() {
var a = {"b": false};
print("Before passing: " + a["b"].toString());
trial(a);
print("After passing: " + a["b"].toString());
}
trial(param) {
param["b"] = true;
}
Output
Before passing: false
After passing: true
One of the way to pass the variables by reference by using the values in List. As arrays or lists are Pass by reference by default.
void main() {
List<String> name=['ali' ,'fana'];
updatename(name);
print(name);
}
updatename(List<String> name){
name[0]='gufran';
}
Try this one, This one of the simplest way to pass by reference.
You can use ValueNotifier
And, you can pass it as ValueListenable to classes or methods that needs to know up-to-date value, but should not edit it:
class Owner {
final theValue = ValueNotifier(true);
final user = User(theValue);
...
}
class User {
final ValueListeneble<bool> theValue;
User(this.theValue);
...
}
It provides more functionality than actually needed, but solves the problem.
If ValueNotifier + ValueListenable do not work for you (you want to make sure the client does not listen to every change of the value, or your package is pure Dart package and thus cannot reference Flutter libraries), use a function:
class Owner {
int _value = 0;
int getValue() => _value;
void increase() => _value++;
}
void main() {
final owner = Owner();
int Function() obtainer = owner.getValue;
print(obtainer());
owner.increase();
print(obtainer());
}
Output will be:
0
1
This approach has memory usage related downside: the obtainer will hold the reference to the owner, and this, even if owner is already not referenced, but obtainer is still reachable, owner will be also reachable
and thus will not be garbage collected.
If you do not want the downside, pass the smaller container than the entire owner:
import 'package:flutter/foundation.dart';
class ListenableAsObtainer<T> implements ValueObtainer<T> {
ListenableAsObtainer(this._listenable);
final ValueListenable<T> _listenable;
#override
T get value => _listenable.value;
}
class FunctionAsObtainer<T> implements ValueObtainer<T> {
FunctionAsObtainer(this._function);
final T Function() _function;
#override
T get value => _function();
}
class ValueAsObtainer<T> implements ValueObtainer<T> {
ValueAsObtainer(this.value);
#override
T value;
}
/// Use this interface when the client needs
/// access to the current value, but does not need the value to be listenable,
/// i.e. [ValueListenable] would be too strong requirement.
abstract class ValueObtainer<T> {
T get value;
}
The usage of FunctionAsObtainer will still result in holding the owner from garbage collection, but two other options will not.
Just to make it clear:
void main() {
var list1 = [0,1,2];
var modifiedList1 = addMutable(list1, 3);
var list2 = [0,1,2];
var modifiedList2 = addImmutable(list2, 3);
print(list1);
print(modifiedList1);
print(list2);
print(modifiedList2);
}
List<int> addMutable(List<int> list, int element){
return list..add(element);
}
List<int> addImmutable(List<int> list, int element){
return [...list, element];
}
Output:
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1, 2, 3]
All variables are passed by value. If a variable contains a primitive (int, bool, etc.), that's it. You got its value. You can do with it whatever you want, it won't affect the source value. If a variable contains an object, what it really contains is a reference to that object.
The reference itself is also passed by value, but the object it references is not passed at all. It just stayed where it was. This means that you can actually make changes to this very object.
Therefore, if you pass a List and if you .add() something to it, you have internally changed it, like it is passed by reference. But if you use the spread operator [...list], you are creating a fresh new copy of it. In most cases that is what you really want to do.
Sounds complicated. Isn't really. Dart is cool.
I want to create a private variable but I cannot.
Here is my code:
void main() {
var b = new B();
b.testB();
}
class A {
int _private = 0;
testA() {
print('int value: $_private');
_private = 5;
}
}
class B extends A {
String _private;
testB() {
_private = 'Hello';
print('String value: $_private');
testA();
print('String value: $_private');
}
}
When I run this code, I get the following result:
String value: Hello
int value: Hello
Breaking on exception: type 'int' is not a subtype of type 'String' of 'value'.
Also I not get any error or warnings when editing this source code.
How can I create a private variable in Dart?
From Dart documentation:
Unlike Java, Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its library.
Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore _ are visible only inside the library.
A few words about libraries:
Every Dart app is a library, even if it doesn’t use a library directive. The import and library directives can help you create a modular and shareable code base.
You may have heard of the part directive, which allows you to split a library into multiple Dart files.
Dart documentation "libraries-and-visibility"
Privacy in Dart exists at the library, rather than the class level.
If you were to put class A into a separate library file (eg, other.dart), such as:
library other;
class A {
int _private = 0;
testA() {
print('int value: $_private'); // 0
_private = 5;
print('int value: $_private'); // 5
}
}
and then import it into your main app, such as:
import 'other.dart';
void main() {
var b = new B();
b.testB();
}
class B extends A {
String _private;
testB() {
_private = 'Hello';
print('String value: $_private'); // Hello
testA();
print('String value: $_private'); // Hello
}
}
You get the expected output:
String value: Hello
int value: 0
int value: 5
String value: Hello
In dart '_' is used before the variable name to declare it as private. Unlike other programming languages, here private doesn't mean it is available only to the class it is in, private means it is accessible in the library it is in and not accessible to other libraries. A library can consists of multiple dart files as well using part and part of. For more information on Dart libraries, check this.
The top answer as of now is definitely correct.
I'll try to go into more detail in this answer.
I'll answer the question, but lead with this: That's just not how Dart is intended to be written, partly because library-private members make it easier to define operators like ==. (Private variables of a second object couldn't be seen for the comparison.)
Now that we've got that out of the way, I'll start out by showing you how it's meant to be done (library-private instead of class-private), and then show you how to make a variable class-private if you still really want that. Here we go.
If one class has no business seeing variables on another class, you might ask yourself whether they really belong in the same library:
//This should be in a separate library from main() for the reason stated in the main method below.
class MyClass {
//Library private variable
int _val = 0;
int get val => _val;
set val(int v) => _val = (v < 0) ? _val : v;
MyClass.fromVal(int val) : _val = val;
}
void main() {
MyClass mc = MyClass.fromVal(1);
mc.val = -1;
print(mc.val); //1
//main() MUST BE IN A SEPARATE LIBRARY TO
//PREVENT MODIFYING THE BACKING FIELDS LIKE:
mc._val = 6;
print(mc.val); //6
}
That should be good. However if you really want private class data:
Though you technically aren't allowed to create private variables, you could emulate it using the following closure technique. (HOWEVER, you should CAREFULLY consider whether you really need it and whether there is a better, more Dart-like way to do what you're trying to accomplish!)
//A "workaround" that you should THINK TWICE before using because:
//1. The syntax is verbose.
//2. Both closure variables and any methods needing to access
// the closure variables must be defined inside a base constructor.
//3. Those methods require typedefs to ensure correct signatures.
typedef int IntGetter();
typedef void IntSetter(int value);
class MyClass {
IntGetter getVal;
IntSetter setVal;
MyClass.base() {
//Closure variable
int _val = 0;
//Methods defined within constructor closure
getVal = ()=>_val;
setVal = (int v) => _val = (v < 0) ? _val : v;
}
factory MyClass.fromVal(int val) {
MyClass result = MyClass.base();
result.setVal(val);
return result;
}
}
void main() {
MyClass mc = MyClass.fromVal(1);
mc.setVal(-1); //Fails
print(mc.getVal());
//On the upside, you can't access _val
//mc._val = 6; //Doesn't compile.
}
So yeah. Just be careful and try to follow the language's best-practices and you should be fine.
EDIT
Apparently there's a new typedef syntax that's preferred for Dart 2. If you're using Dart 2 you should use that. Or, even better, use inline function types.
If you use the second, it will be less verbose, but the other problems remain.
Given the following class, Dart Editor (build 5549) gives me some conflicting feedback (per the comments in the constructor body):
class Example {
final int foo;
Example() :
foo = 0
{
foo = 1; // 'cannot assign value to final variable "foo"'
this.foo = 2; // ok
}
}
Even more confusingly, it will happily generate equivalent (working) javascript for both lines. The situation seems to be the same with methods as it is with the constructor; this especially leads me to believe that it was intended to be disallowed in both cases.
The Dart Style Guide suggests using public final fields instead of private fields with public getters. I like this in theory, but non-trivial member construction can't really go into the initializer list.
Am I missing a valid reason for the former to be reported as an error while the latter is not? Or should I be filing a bug right now?
This is surely a bug in the JavaScript generator if you run the following in the Dart VM:
main() {
new Example();
}
class Example {
final int foo;
Example() : foo = 0 {
foo = 1; // this fails in the dart vm
this.foo = 2; // this also fails in the dart vm
}
}
then it refuses to execute both the line foo = 1 and this.foo = 2. This is consistent with the spec which requires (if I read it correctly) that final fields to be final in the constructor body.