Why does Dart's compiler believe code might be null when the code guarantees it cannot be? - dart

I'm working through an exercise from this course. This code:
void main() {
const order = ['pepperoni', 'margherita', 'pineapple'];
print("Total: ${calculateTotal(order)}");
}
double calculateTotal(List<String> order) {
var total = 0.0;
const pizzaPrices = {
'margherita': 5.5,
'pepperoni': 7.5,
'vegetarian': 6.5,
};
for (var item in order) {
if (pizzaPrices[item]!=null) {
total += pizzaPrices[item];
}
}
return total;
}
Produces the error message The argument type 'double?' can't be assigned to the parameter type 'num'. pointing to the line total += pizzaPrices[item];
total += pizzaPrices[item]! compiles as expected, without errors.
I don't understand why the compiler would need the !, since it already knows pizzaPrices[item] cannot be null.

The reason is that the [] operator on Map is defined to return a nullable type since if the element you search for are not in the map, the [] operator will return null.
It might look obvious to you, but the compiler cannot know for sure that just because you checked the returned value from pizzaPrices[item] once, it will return the same value again the second time you ask (e.g. in some custom made Map implementation).
A solution is instead to save the value in a local variable which you can then check for null. Dart will in this case promote the variable as expected:
void main() {
const order = ['pepperoni', 'margherita', 'pineapple'];
print("Total: ${calculateTotal(order)}");
}
double calculateTotal(List<String> order) {
var total = 0.0;
const pizzaPrices = {
'margherita': 5.5,
'pepperoni': 7.5,
'vegetarian': 6.5,
};
for (var item in order) {
final pizzaPrice = pizzaPrices[item];
if (pizzaPrice != null) {
total += pizzaPrice;
}
}
return total;
}

Related

calculate column total in Vaadin 7 Grid

In Vaadin 7, is there an easy way to calculate the numeric total for selected columns? I know how to do it for Vaadin 8, defined here. But since Vaadin 7 uses a container, I am trying to think of the best way to do it. Currently, this is the best way I can think of, based on the documentation here. Code is a rough draft, so I expect there are some syntax problems. Treat it more as pseudo code, if possible.
Map<Object,Double> totals = new HashMap();
for (Iterator<?> i = container.getItemIds().iterator(); i.hasNext();) {
Object itemId = i.next();
Item item = container.getItem(itemId);
for(Object totalCol : totalColumns)
{
Object columnVal = item.getItemProperty(totalCol);
Double total = totals.get(totalCol);
if(!(total instanceof Double))
total = 0.0;
if(columnVal instanceof Double)
{
total += (Double)columnVal;
}
else if(columnVal instanceof Long)
{
total += (Long)columnVal;
}
else if(columnVal instanceof Integer)
{
total += (Integer)columnVal;
}
else if(columnVal instanceof String)
{
try {
Long value = Long.parseLong((String) columnVal);
total += value;
} catch (NumberFormatException e) {
try {
Double value = Double.parseDouble((String) columnVal);
total += value;
} catch (NumberFormatException e1) {
}
}
}
totals.put(totalCol, total);
}
/* At this point, go through totals Map, and set value to correct footer column with correct
* text formatting. This part is easy, and clearly documented, so leaving it off this
* code example.
*/
}
By the way, the above idea works, my question is more if this is the best idea or not?

Dart Null Safety / Assertion Operator

I'm new to Dart. I'm calculating the price of a pizza order. In my current solution, I'm using the assertion operator. What do you think about it?
I've read many times that you shouldn't use it. Do you think my code is ok, or would you do something better/different?
void main() {
const List<String> order = ['margherita', 'pepperoni', 'pineapple'];
calcTotalPrice(order: order);
}
calcTotalPrice({required List<String> order}) {
final Map<String, double> pizzaPrices = {
'margherita': 5.5,
'pepperoni': 7.5,
'vegetarian': 6.5
};
double total = 0.0;
for (var item in order) {
pizzaPrices[item] ??= 0.0;
total += pizzaPrices[item]!; // assertion operator (!)
}
print(total);
}
Your code is fine but you can avoid collecting unknown keys in the map pizzaPrices with:
for (var item in order) {
total += pizzaPrices[item] ?? 0.0;
}

How to do lazy evaluation in Dart?

Is there a native (language supported) lazy evaluation syntax? Something like lazy val in Scala.
I've gone through the docs, and could not find anything. There is only a chapter about "lazily loading a library", but it's not what I am asking.
Based on this research I incline to believe (please correct me if I'm wrong) that currently there is no such thing. But maybe you know of any plans or feature requests which will provide the functionality? Or maybe it was considered and rejected by the Dart team?
If indeed there is no native support for this, then what is the best practice (best syntax) for implementing lazy evaluation? An example would be appreciated.
Edit:
The benefits of the feature that I am looking for are mostly the same as in implementation in other languages: Scala's lazy val or C#'s Lazy<T> or Hack's __Memorize attribute:
concise syntax
delayed computation until the value is needed
cache the result (the by-need laziness)
don't break pure functional paradigm (explanation below)
A simple example:
class Fibonacci {
final int n;
int _res = null;
int get result {
if (null == _res) {
_res = _compute(this.n);
}
return _res;
}
Fibonacci(this.n);
int _compute(n) {
// ...
}
}
main(List<String> args) async {
print(new Fibonacci(5).result);
print(new Fibonacci(9).result);
}
The getter is very verbose and has a repetitive code. Moreover I can't make the constructor const because the caching variable _res has to be computed on demand. I imagine that if I had a Scala-like lazy feature then I would also have language support for having a constant constructor. That's thanks to the fact, that the lazy evaluated _res is referentially transparent, and would not be in the way.
class Fibonacci {
final int n;
int lazy result => _compute(this.n);
const Fibonacci(this.n); // notice the `const`
int _compute(n) {
// ...
}
}
main(List<String> args) async {
// now these makes more sense:
print(const Fibonacci(5).result);
print(const Fibonacci(9).result);
}
Update 2021
Lazy initialization is now part of dart from the release 2.12.
Simply add late modifier to the variable declaration
late MyClass obj = MyClass();
And this object will be initialized only when it is first used.
From the docs:
Dart 2.12 added the late modifier, which has two use cases:
Declaring a non-nullable variable that’s initialized after its
declaration.
Lazily initializing a variable.
Checkout the example here:
https://dartpad.dev/?id=50f143391193a2d0b8dc74a5b85e79e3&null_safety=true
class A {
String text = "Hello";
A() {
print("Lazily initialized");
}
sayHello() {
print(text);
}
}
class Runner {
late A a = A();
run() async {
await Future.delayed(Duration(seconds: 3));
print("First message");
a.sayHello();
}
}
Here class A will be initialized only after "First message" has been displayed.
update2
From #lrn s comment - using an Expando for caching makes it work with const:
class Lazy<T> {
static final _cache = new Expando();
final Function _func;
const Lazy(this._func);
T call() {
var result = _cache[this];
if (identical(this, result)) return null;
if (result != null) return result;
result = _func();
_cache[this] = (result == null) ? this : result;
return result;
}
}
defaultFunc() {
print("Default Function Called");
return 42;
}
main([args, function = const Lazy(defaultFunc)]) {
print(function());
print(function());
}
Try it in DartPad
update
A reusable Lazy<T> could look like below in Dart but that also doesn't work with const and can't be used in field initializers if the calculation needs to refer instance members (this.xxx).
void main() {
var sc = new SomeClass();
print('new');
print(sc.v);
}
class SomeClass {
var _v = new Lazy<int>(() {
print('x');
return 10;
});
int get v => _v();
}
class Lazy<T> {
final Function _func;
bool _isEvaluated = false;
Lazy(this._func);
T _value;
T call() {
if(!_isEvaluated) {
if(_func != null) {
_value = _func();
}
_isEvaluated = true;
}
return _value;
}
}
Try it in DartPad
original
Dart version of http://matt.might.net/articles/implementing-laziness/ using a closure to lazy evaluate:
void main() {
var x = () {
print ("foo");
return 10;
}();
print("bar");
print(x);
// will print foo, then bar then 10.
print('===');
// But, the following Scala program:
x = () {
print("foo");
return 10;
};
print ("bar");
print (x());
// will print bar, then foo, then 10, since it delays the computation of x until it’s actually needed.
}
Try it in DartPad
Update
int _val;
int get val => _val ??= 9;
Thanks #Nightscape
Old
I think this little snippet might help you...
int _val;
int get val => _val ?? _val = 9;

How to set values of global variables used in function parameters

I can conveniently change opsCount variable directly from inside the function,
because there is only one of that type of variable.
int opsCount = 0;
int jobXCount = 0;
int jobYCount = 0;
int jobZCount = 0;
void doStats(var jobCount) {
opsCount++;
jobCount++;
}
main() {
doStats(jobXCount);
}
But there are many jobCount variables, so how can I change effectively that variable, which is used in parameter, when function is called?
I think I know what you are asking. Unfortunately, the answer is "you can't do this unless you are willing to wrap your integers". Numbers are immutable objects, you can't change their value. Even though Dart's numbers are objects, and they are passed by reference, their intrinsic value can't be changed.
See also Is there a way to pass a primitive parameter by reference in Dart?
You can wrap the variables, then you can pass them as reference:
class IntRef {
IntRef(this.val);
int val;
#override
String toString() => val.toString();
}
IntRef opsCount = new IntRef(0);
IntRef jobXCount = new IntRef(0);
IntRef jobYCount = new IntRef(0);
IntRef jobZCount = new IntRef(0);
void doStats(var jobCount) {
opsCount.val++;
jobCount.val++;
}
main() {
doStats(jobXCount);
print('opsCount: $opsCount; jobXCount: $jobXCount; jobYCount: $jobYCount; jobZCount: $jobZCount');
}
EDIT
According to Roberts comment ..
With a custom operator this would look like:
class IntRef {
IntRef(this.val);
int val;
#override
String toString() => val.toString();
operator +(int other) {
val += other;
return this;
}
}
void doStats(var jobCount) {
opsCount++;
jobCount++;
}

Assign function/method to variable in Dart

Does Dart support the concept of variable functions/methods? So to call a method by its name stored in a variable.
For example in PHP this can be done not only for methods:
// With functions...
function foo()
{
echo 'Running foo...';
}
$function = 'foo';
$function();
// With classes...
public static function factory($view)
{
$class = 'View_' . ucfirst($view);
return new $class();
}
I did not found it in the language tour or API. Are others ways to do something like this?
To store the name of a function in variable and call it later you will have to wait until reflection arrives in Dart (or get creative with noSuchMethod). You can however store functions directly in variables like in JavaScript
main() {
var f = (String s) => print(s);
f("hello world");
}
and even inline them, which come in handy if you are doing recusion:
main() {
g(int i) {
if(i > 0) {
print("$i is larger than zero");
g(i-1);
} else {
print("zero or negative");
}
}
g(10);
}
The functions stored can then be passed around to other functions
main() {
var function;
function = (String s) => print(s);
doWork(function);
}
doWork(f(String s)) {
f("hello world");
}
I may not be the best explainer but you may consider this example to have a wider scope of the assigning functions to a variable and also using a closure function as a parameter of a function.
void main() {
// a closure function assigned to a variable.
var fun = (int) => (int * 2);
// a variable which is assigned with the function which is written below
var newFuncResult = newFunc(9, fun);
print(x); // Output: 27
}
//Below is a function with two parameter (1st one as int) (2nd as a closure function)
int newFunc(int a, fun) {
int x = a;
int y = fun(x);
return x + y;
}

Resources