weight is a field (Number in Firestore), set as 100.
int weight = json['weight'];
double weight = json['weight'];
int weight works fine, returns 100 as expected, but double weight crashes (Object.noSuchMethod exception) rather than returning 100.0, which is what I expected.
However, the following works:
num weight = json['weight'];
num.toDouble();
When parsing 100 from Firestore (which actually does not support a "number type", but converts it), it will by standard be parsed to an int.
Dart does not automatically "smartly" cast those types. In fact, you cannot cast an int to a double, which is the problem you are facing. If it were possible, your code would just work fine.
Parsing
Instead, you can parse it yourself:
double weight = json['weight'].toDouble();
Casting
What also works, is parsing the JSON to a num and then assigning it to a double, which will cast num to double.
double weight = json['weight'] as num;
This seems a bit odd at first and in fact the Dart Analysis tool (which is e.g. built in into the Dart plugin for VS Code and IntelliJ) will mark it as an "unnecessary cast", which it is not.
double a = 100; // this will not compile
double b = 100 as num; // this will compile, but is still marked as an "unnecessary cast"
double b = 100 as num compiles because num is the super class of double and Dart casts super to sub types even without explicit casts.
An explicit cast would be the follwing:
double a = 100 as double; // does not compile because int is not the super class of double
double b = (100 as num) as double; // compiles, you can also omit the double cast
Here is a nice read about "Types and casting in Dart".
Explanation
What happened to you is the following:
double weight;
weight = 100; // cannot compile because 100 is considered an int
// is the same as
weight = 100 as double; // which cannot work as I explained above
// Dart adds those casts automatically
You can do it in one line:
double weight = (json['weight'] as num).toDouble();
You can Parse the data Like given below:
Here document is a Map<String,dynamic>
double opening = double.tryParse(document['opening'].toString());
In Dart, int and double are separate types, both subtypes of num.
There is no automatic conversion between number types. If you write:
num n = 100;
double d = n;
you will get a run-time error. Dart's static type system allows unsafe down-casts, so the unsafe assignment of n to d (unsafe because not all num values are double values) is treated implicitly as:
num n = 100;
double d = n as double;
The as double checks that the value is actually a double (or null), and throws if it isn't. If that check succeeds, then it can safely assign the value to d since it is known to match the variable's type.
That's what's happening here. The actual value of json['weight'] (likely with static type Object or dynamic) is the int object with value 100. Assigning that to int works. Assigning it to num works. Assigning it to double throws.
The Dart JSON parser parses numbers as integers if they have no decimal or exponent parts (0.0 is a double, 0e0 is a double, 0 is an integer). That's very convenient in most cases, but occasionally annoying in cases like yours where you want a double, but the code creating the JSON didn't write it as a double.
In cases like that, you just have to write .toDouble() on the values when you extract them. That's a no-op on actual doubles.
As a side note, Dart compiled to JavaScript represents all numbers as the JavaScript Number type, which means that all numbers are doubles. In JS compiled code, all integers can be assigned to double without conversion. That will not work when the code is run on a non-JS implementation, like Flutter, Dart VM/server or ahead-of-time compilation for iOS, so don't depend on it, or your code will not be portable.
Simply convert int to double like this
int a = 10;
double b = a + 0.0;
Related
Iam new to dart I want a Make table of food program which take an input from user for each food and how much they want but i have an problem with multiply listOfFood[name] with count which both of them double is there any way to solve this ?
double name , count ;
Map<String , dynamic> listOfFood = {
'bacon' :'4.2',
'salad' :'3.5',
'cheaken' :'5.6',
'Goatmeat' :'6.9',
'fish' : '6.5',
};
Map<int , dynamic> food = {
1 : listOfFood ['bacon']
,2 : listOfFood ['salad']
,3 : listOfFood ['cheaken']
,4 : listOfFood ['Goatmeat']
,5 : listOfFood ['fish']
};
stdout.write('please Choose your product \n ${listOfFood}');
name = double.parse(stdin.readLineSync()!);
count = double.parse(stdin.readLineSync()!);
double result = (food[name]) * count;
print(result);
}
You cannot coerce a String that looks like a number to a double in Dart.
Dart has strong typing even when you declare a variable dynamic.
In your case, you're taking the value from listOfFood (not a List, use a better name like priceByFoodName), which is always a String (despite the Map having dynamic values) and multiplying that with a double which can't work.
You should ask yourself why are the prices Strings?
If you want to use them as numbers, just make them numbers.
Also, you don't need dynamic at all. Use types! If you had done that the compiler would've told you right away what the problem was before you even ran the code. That's why types exist.
To solve the problem quickly... this line:
double result = (food[name]) * count;
Should be changed to:
double result = double.parse(food[name]!) * count;
But you should probably change your code quite a bit to handle errors, use appropriate types, stop ignoring nulls etc.
This question already has answers here:
What is Null Safety in Dart?
(2 answers)
Closed 1 year ago.
After defining a map (with letters as keys and scrabble tile scores as values)
Map<String, int> letterScore //I'm omitting the rest of the declaration
when I experiment with this function (in DartPad)
int score(String aWord) {
int result = 0;
for (int i = 0; i < aWord.length; ++i) {
result += letterScore[aWord[i]];
}
return result;
}
I consistently get error messages, regardless of whether I experiment by declaring variables as num or int:
Error: A value of type 'int?' can't be assigned to a variable of type
'num' because 'int?' is nullable and 'num' isn't [I got this after declaring all the numerical variables as int]
Error: A value of type 'num' can't be returned from a function with
return type 'int'.
Error: A value of type 'num?' can't be assigned to a variable of type
'num' because 'num?' is nullable and 'num' isn't.
I understand the difference between an integer and a floating point (or double) number, it's the int vs int? and num vs num? I don't understand, as well as which form to use when declaring variables. How should I declare and use int or num variables to avoid these errors?
Take this for example:
int x; // x has value as null
int x = 0; // x is initialized as zero
Both the above code are fine and compilable code. But if you enable Dart's null-safety feature, which you should, it will make the above code work differently.
int x; // compilation error: "The non-nullable variable must be assigned before can be used"
int x = 0; // No Error.
This is an effort made from the compiler to warn you wherever your variable can be null, but during the compile time. Awesome.
But what happens, if you must declare a variable as null because you don't know the value at the compile time.
int? x; // Compiles fine because it's a nullable variable
The ? is a way for you tell the compiler that you want this variable to allow null. However, when you say a variable can be null, then every time you use the variable, the compiler will remind you to check whether the variable is null or not before you can use it.
Hence the other use of the ?:
int? x;
print(x?.toString() ?? "0");
Further readings:
Official Docs: https://dart.dev/null-safety/understanding-null-safety
Null-aware operators: https://dart.dev/codelabs/dart-cheatsheet
I want to use doubles in my code but Dart converts them to ints (or dynamic).
I have tried to cast them using 'as' or .toDouble() but they do not stay as doubles:
(in dartpad)
main() {
print ((1.0 as double).runtimeType);
print (1.0.toDouble().runtimeType);
}
(output)
int
int
I would have expected the output of these statements to be 'double'. If I change the value to 1.1 I get a double out.
Is it save to use cast to int instead of Math.floor to convert float / double values to integers?
var scale = 1.5;
int foo1 = (int)scale;
int foo2 = Math.floor(scale);
In this case both Case to Int and Math.floor will return integer value. If x=3.5 then both function will return 3 in output. Cast to int is a function to convert variable of any datatype to integer type, on the other hand Math.floor function will only floor the decimal number to integer not converting datatype. But result will be different in case of negative values because Cast to Int approaches to zero and Math.floor approaches to negative infinity. So in that perspective if you are working on real numbers (both positive and negative) then it is unsafe to use Cast to Int instead of Math.floor to get precise output.
As Vala code is translated into C, this is the same question as Cast to int vs floor
TL;DR: yes it is safe but the result of Math.floor and float/double casting are different when negative numbers are given.
Note that Math.floor is part of the GLib library and thus is not available in the POSIX profile.
I have always considered the types float32 and single to be interchangeable, in that they are type aliases. The same for float and double. However, they appear to be declared in different assemblies Microsoft.FSharp.Core.Operators vs Microsoft.FSharp.Core.ExtraTopLevelOperators.
Also, the popup description is slightly different, where F# says on float32 and float that it can take a string and use Parse() on it.
However, trying that with single and double succeeds just fine too:
let x = single "12.3"
let y = double "13.4"
Is there any difference I should be aware of? I have always used them interchangeably, never really gave it another thought, until I saw the differences in the popups and in signatures:
// on hovering, or in FSI, this will have the slightly confusing signature:
// val x: a: double -> float
let x (a: double) = float a
All of them are just aliases of the corresponding CLR types as you can see in prim-types-prelude.fs.
type float32 = System.Single
type float = System.Double
type single = System.Single
type double = System.Double
As for the confusing signature consider this:
type typA = A;;
type typB = typA;;
let f (x : typA) = (x : typB)
//val f : x:typA -> typB
Seems like F# prefers to use the aliases at the places you (or some other definition) used them.
Finally the namespaces you are referring to (FSharp.Core.Operators) are referring not to the float type but the float function (float : 'T -> float). See prim-types.fs.