When optional named parameter is not provided, why it is not null as expected?
void main() {
num double({v: num}) {
if (v == null)
return 0;
else
return v * 2;
}
print(double(v: 2));
print(double());
print('done');
}
which output as
4
Uncaught TypeError: v.$mul is not a function
num double({v: num}) {
defines a named parameter v of type dynamic with the default value num (a type)
It should instead be
num double({num v}) {
to make your code work as expected
Related
I've defined an extension:
extension MyIterable<T extends num> on Iterable<T> {
T sum() => reduce((v, e) => v + e); // Error
}
Why is v + e not considered T, why is there an error?
The return type 'num' isn't a 'T', as required by the closure's context.
I'm using it in the main:
void main() {
int a = MyIterable<int>([1, 2]).sum();
double b = MyIterable<double>([1.0, 2]).sum();
num c = MyIterable<num>([1.0, 2]).sum();
}
Although v and e are statically known to be T, which is some subtype of num, the exact subtype isn't known, so v + e is only statically known to conform to num.operator+. Consequently, the result is num (the base type), not necessarily a T (the more specific subtype).
In this case, I think you'll probably need to add an as T explicit cast.
I'm working on some generic list utility functions and there seems to be an issue with the type inference for a generic function when the primary variables are lists. This is demonstrated with the following code:
List<T> combine<T>(List<T> a, List<T> b, T Function(T a, T b) combiner) {
final list = <T>[];
for (int i = 0; i < a.length && i < b.length; i++) {
list.add(combiner(a[i], b[i]));
}
return list;
}
void main() {
final a = [5, 8];
final b = [7, -3];
final c = combine(a, b, (a, b) => a + b); // Error
print(c);
// Expected: [12, 5]
}
When I use this code as-is, the type inference within the lambda sets a and b to be Object?, which results in the following error message:
The operator '+' can't be unconditionally invoked because the receiver can be 'null'.
Try adding a null check to the target ('!').
Doing what the error message says changes the message to the following:
The operator '+' isn't defined for the type 'Object'.
Try defining the operator '+'.
The issue obviously is that type inference is assigning the parameters to Object? instead of the expected int. This can be worked around by either typing the parameters or explicitly passing the generic type to the function:
final c = combine(a, b, (int a, int b) => a + b);
// OR
final c = combine<int>(a, b, (a, b) => a + b);
However, that's an added level of verbosity that I don't want to have to force the users of these utility functions to have to do (not to mention it will be a support issue when I have to explain to them to do this). Is there a way to change the function signature to make it so type inference works as expected?
This is basically Dart List.fold vs List.reduce type inference, but in your case you could sidestep the problem by making your function an extension method so that T is deduced from the receiver instead of from the arguments:
extension<T> on List<T> {
List<T> combineWith(List<T> b, T Function(T a, T b) combiner) {
final list = <T>[];
for (int i = 0; i < length && i < b.length; i++) {
list.add(combiner(this[i], b[i]));
}
return list;
}
}
void main() {
final a = [5, 8];
final b = [7, -3];
final c = a.combineWith(b, (a, b) => a + b); // Error
print(c);
// Expected: [12, 5]
}
Let's say I have:
class Test<T> {
void method() {
if (T is int) {
// T is int
}
if (T == int) {
// T is int
}
}
}
I know I can override == operator but what's the main difference between == and is in Dart if I don't override any operator.
Edit:
Say I have
extension MyIterable<T extends num> on Iterable<T> {
T sum() {
T total = T is int ? 0 : 0.0; // setting `T == int` works
for (T item in this) {
total += item;
}
return total;
}
}
And when I use my extension method with something like:
var addition = MyIterable([1, 2, 3]).sum();
I get this error:
type 'double' is not a subtype of type 'int'
identical(x, y) checks if x is the same object as y.
x == y checks whether x should be considered equal to y. The default implementation for operator == is the same as identical(), but operator == can be overridden to do deep equality checks (or in theory could be pathological and be implemented to do anything).
x is T checks whether x has type T. x is an object instance.
class MyClass {
MyClass(this.x);
int x;
#override
bool operator==(dynamic other) {
return runtimeType == other.runtimeType && x == other.x;
}
#override
int get hashCode => x.hashCode;
}
void main() {
var c1 = MyClass(42);
var c2 = MyClass(42);
var sameC = c1;
print(identical(c1, c2)); // Prints: false
print(identical(c1, sameC)); // Prints: true
print(c1 == c2); // Prints: true
print(c1 == sameC); // Prints: true
print(c1 is MyClass); // Prints: true
print(c1 is c1); // Illegal. The right-hand-side must be a type.
print(MyClass is MyClass); // Prints: false
}
Note the last case: MyClass is MyClass is false because the left-hand-side is a type, not an instance of MyClass. (MyClass is Type would be true, however.)
In your code, T is int is incorrect because both sides are types. You do want T == int in that case. Note that T == int would check for an exact type and would not be true if one is a derived type of the other (e.g. int == num would be false).
Basically, == is equality operator and "is" is the instanceof operator of Dart (If you come from Java background, if not, it basically tells you if something is of type something).
Use == for equality, when you want to check if two objects are equal. You can implement the == operator (method) in your class to define on what basis do you want to judge if two objects are equal.
Take this example:
class Car {
String model;
String brand;
Car(this.model, this.brand);
bool operator == (otherObj) {
return (otherObj is Car && other.brand == brand); //or however you want to check
//On the above line, we use "is" to check if otherObj is of type Car
}
}
Now you can check if two cars are "equal" based on the condition that you have defined.
void main() {
final Car micra = Car("Micra", "Nissan");
print(micra == Car("Micra", "Nissan")); // true
print(micra is Car("Micra", "Nissan")); // true
}
Hence, == is something you use to decide if two objects are equal, you can override and set it as per your expectations on how two objects should be considered equal.
On the other hand, "is" basically tells you if an instance is of type object (micra is of type Car here).
When working with a sort function, the implemented node i had created seems to cause some issues.
I have tracked it down to the comparison of Nodes in the Merge function of MergeSort. That being said, the line of code in question is:
if (_tmpArray[i] <= _tmpArray[j])
_tmpArray is defined in the the constructor, but given content value in the merge
Node implementation of operator ==, operator <, operator <= are as follows.
bool operator ==( Node<T> other) => identical(this, other);
bool operator <( Node<T> other){
//other is of same type, T.
if (_value.compareTo(other) == -1){
return true;
}
return false;
}
bool operator <= ( Node<T> other){
return (this == other) || (this < other);
}
It seems that maybe my implementation is wrong. I am doing a test inside of main with a List of size 400, of T = int.
Attached is my Dartpad file: https://dartpad.dartlang.org/612422345f1ac8a27f8e
It seems that the comparison of: _value.compareTo is not correct because T doesnt have compareTo in this case of int being T. When converting the int to "String" which is comparable though compareTo it still shows the same error.
//other is of same type, T.
if (_value.compareTo(other._value) == -1){
// ^^^^^^^ was missing
return true;
}
return false;
Having a simple class as follows is considered a static warning, why?
operator 'negate' should return numeric type
class Vector {
final int x,y;
const Vector(this.x, this.y);
Vector operator +(Vector v) { // Overrides + (a + b).
return new Vector(x + v.x, y + v.y);
}
Vector operator -(Vector v) { // Overrides - (a - b).
return new Vector(x - v.x, y - v.y);
}
Vector operator negate() { // Overrides unary negation (-a).
return new Vector(-x,-y);
}
String toString() => '($x,$y)';
}
main() {
final v = new Vector(2,3);
final w = new Vector(2,2);
assert((-v).x == -2 && (-v).y == -3); // -v == (-2,-3)
}
As of 8/21/2012 the Dart Specification Section 7.1.2 Operators, considers defining negate with a possible nullary type as bad style and should report to the user a static warning.
Defining a nullary method named negate or a binary method named equals
will have the same effect as dening an operator but is considered bad
style, and will cause a static warning.
[...]
It is a static warning if the return type of the user-declared
operator []= is explicitly declared and not void. It is a static
warning if the return type of the user-declared operator equals is
explicitly declared and is not bool. It is a static warning if the
return type of the user-declared operator negate is explicitly
declared and not a numerical type.
We have an open bug for this: http://code.google.com/p/dart/issues/detail?id=3416