This function should transform each element of the list with the given function transform:
void _doSomething(List<Something> numbers, [transform(Something element)]) {...}
As I don't want to skip this method when the transform should not do anything, I wanted to give a default value to the transform method like this:
void _doSomething(List<Something> numbers,
[transform(Something element) = (v) => v]) {...}
Unfortunately, the editor tells me
Expected constant expected
Is there some workaround or simply not possible (or shouldn't be done like this at all)?
if you want to initialize a Function parameter that is also a field of your class I suggest:
class MyClass{
Function myFunc;
MyClass({this.myFunc = _myDefaultFunc}){...}
static _myDefaultFunc(){...}
}
Or more suitable:
typedef SpecialFunction = ReturnType Function(
FirstParameterType firstParameter,
SecondParameterType secondParameter);
class MyClass{
SpecialFunction myFunc;
MyClass({this.myFunc = _myDefaultFunc}){...}
static ReturnType _myDefaultFunc(FirstParameterType firstParameter,
SecondParameterType secondParameter){...}
}
You can define the default function as private method :
_defaultTransform(Something v) => v;
void _doSomething(List<Something> numbers,
[transform(Something element) = _defaultTransform]) {...}
Or check argument like this :
void _doSomething(List<Something> numbers, [transform(Something element)]) {
if (!?transform) transform = (v) => v;
...
}
Or like Ladicek suggests :
void _doSomething(List<Something> numbers, [transform(Something element)]) {
transform ??= (v) => v;
...
}
Write your default parameters inside a square bracket []
DummyFunctin(String var1, int Var2,[ String var3 = "hello", double var4 = 3.0, List<int> var5 = [2,4,5,6],] ){
// some calculation
// return something
}
Related
I have many confusion about Brackets in Dart(Flutter).
Which bracket "(), {}, []" is used for what?
() can group expressions:
var x = (1 + 2) * 3;
or can designate parameter lists for functions:
var getAnswer = () => 42;
int square(int x) => x * x;
or can designate function calls:
var answer = getAnswer();
var squared = square(4);
or is part of the syntax to some keywords. This includes (but is not limited to) if, assert, for, while, switch, catch:
if (condition) {
...
}
assert(condition);
for (var item in collection) {
...
}
while (condition) {
...
}
switch (value) {
...
}
try {
...
} on Exception catch (e) {
...
}
[] by itself creates List literals:
var list = [1, 2, 3];
var emptyList = []; // Creates a List<dynamic>.
or when used on an object, calls operator [], which usually accesses an element of a collection:
var element = list[index];
var value = map[key];
or in a parameter list, specifies optional positional parameters:
int function(int x, [int y, int z]) {
return x + y ?? 0 + z ?? 0;
}
function(1, 2);
or in dartdoc comments, creates linked references to other symbols:
/// Creates a [Bar] from a [Foo].
Bar fooToBar(Foo foo) {
// ...
}
{} can create a block of code, grouping lines together and limiting variable scope. This includes (but is not limited to) function bodies, class declarations, if-else blocks, try-catch blocks, for blocks, while blocks, switch blocks, etc.:
class Class {
int member;
}
void doNothing() {}
void function(bool condition) {
{
int x = 'Hello world!';
print(x);
}
if (condition) {
int x = 42; // No name collision due to separate scopes.
print(x);
}
}
or by itself can create Set or Map literals:
var set = {1, 2, 3};
var emptySet = <int>{};
var map = {'one': 1, 'two': 2, 'three': 3};
var emptyMap = {}; // Creates a Map<dynamic, dynamic>
or in a parameter list, specifies optional named parameters:
int function(int x, {int y, int z}) {
return x + y ?? 0 + z ?? 0;
}
function(1, y: 2);
or creates enumerations:
enum SomeEnumeration {
foo,
bar,
baz,
}
or in Strings is used to disambiguate interpolated expressions:
var foo = 'foo';
var foobar = '${foo}bar';
var s = '${function(1, 2)}';
<> when used as a pair in function or class declarations creates generics:
class GenericClass<T> {
T member;
}
T function<T>(T x) {
// ...
}
or specifies explicit types when using generics:
var map = <String, int>{};
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).
I'm checking out some dart code and looking at this:
AppState.fromJson(Map<String, dynamic> json)
: cartItems = (json['cartItems'] as List)
.map((i) => new CartItem.fromJson(i as Map<String, dynamic>))
.toList();
What's the reasoning behind the colon?
Why is this different from a regular assignment?
You can find more info in the dart tour: https://dart.dev/guides/language/language-tour#classes
If the superclass doesn’t have an unnamed, no-argument constructor, then you must manually call one of the constructors in the superclass. Specify the superclass constructor after a colon (:), just before the constructor body (if any).
Besides invoking a superclass constructor, you can also initialize instance variables before the constructor body runs. Separate initializers with commas.
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
During development, you can validate inputs by using assert in the initializer list.
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
You can also use them to initialize the final variables:
class Point {
final num x;
final num y;
final num distanceFromOrigin;
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
I am trying List.fold() in Dart 2.1.0:
void main() {
final a = [1,2,3];
print(a.fold(0, (x,y) => x + y));
}
It comes back with an error:
Error: The method '+' isn't defined for the class 'dart.core::Object'.
Try correcting the name to the name of an existing method, or defining a method named '+'.
Seems that it can't infer the type of x to be int, so doesn't know how to apply the + there.
According to the method spec, x should have the same type as the initial value 0, which is obviously an int. Why can't Dart infer that?
I can make it work by explicitly tipping the type:
void main() {
final a = [1,2,3];
print(a.fold<int>(0, (x,y) => x + y));
}
But I am a little disappointed that Dart cannot infer that for me. Its type inference seems stronger in most other cases.
Dart type inference works as expected:
void main() {
final a = [1,2,3];
var sum = a.fold(0, (x,y) => x + y);
print(sum);
}
The reason it fails in your example is because type inference outcome depends on the context where the expression is evaluated:
print(a.fold(0, (x,y) => x + y));
throws an error because print parameter is expected to be an Object: inference uses Object to fill generic T type argument` of fold:
T fold <T>(T initialValue, T combine(T previousValue, T element)) :
To validate this assumption:
void main() {
final a = [1,2,3];
Object obj = a.fold(0, (x,y) => x + y);
}
Throws exactly the same error.
Take away:
Type inference works well, but care must be paid to the generic expression's surrounding context.
Is it this a Dart limitation?
I dont think this behavoir it is a limitation of dart, just an implementation choice.
Probably there are also sound theoretical reasons that I'm not able to speak about but I can works out some reasoning about that.
Considering the generic method:
T fold <T>(T initialValue, T combine(T previousValue, T element))
and its usage:
Object obj = a.fold(0, (x,y) => x + y);
There are two paths for inferring the type of T:
fold returned value is assigned to an Object obj, 0 is an Object since it is an int, then T "resolve to" Object
fold first argument is an int, the returned value is expected to be an Object and int is an Object,
then T "resolve to" int
Dart chooses the path 1: it takes for inferred type the "broadest" (the supertype) that satisfy the generic method.
Should be better if Dart implements path 2 (the inferred type is the "nearest" type)?
In this specific case probably yes, but then there will be cases that does not works with path 2.
For example this snippet would not be happy with path 2:
abstract class Sensor {
String getType();
}
class CADPrototype extends Sensor {
String getType() {
return "Virtual";
}
}
class Accelerometer extends Sensor {
String getType() {
return "Real";
}
}
T foo<T extends Sensor>(T v1, T v2, T bar(T t1, T t2)) {
if (v2 is CADPrototype) {
return v1;
}
return v2;
}
Sensor foo_what_dart_does(Sensor v1, Sensor v2, Sensor bar(Sensor t1, Sensor t2)) {
if (v2 is CADPrototype) {
return v1;
}
return v2;
}
Accelerometer foo_infer_from_argument(Accelerometer v1, Accelerometer v2, Accelerometer bar(Accelerometer t1, Accelerometer t2)) {
if (v2 is CADPrototype) {
return v1;
}
return v2;
}
void main() {
Accelerometer v1 = Accelerometer();
CADPrototype v2 = CADPrototype();
Sensor result;
result = foo(v1, v2, (p1, p2) => p1);
// it works
result = foo_what_dart_does(v1, v2, (p1, p2) => p1);
// Compilation Error: CADPrototype cannot be assigned to type Accelerometer
result = foo_infer_from_argument(v1, v2, (p1, p2) => p1);
}
I have a generic static method that looks like this:
static build<K>() {
return (GenericClass<K> param) => MyClass<K>(param);
}
So far I have tried:
typedef F = MyClass<K> Function(GenericClass<K> param);
but it says that:
The return type '(GenericClass<K>) → MyClass<K>' isn't a '(GenericClass<dynamic>) → MyClass<dynamic>', as defined by the method 'build'.
and
typedef F = SimpleViewModel<K> Function<k>(Store<K> param);
Which says that:
The return type '(GenericClass<K>) → MyClass<K>' isn't a '<K>(GenericClass<K>) → MyClass<K>', as defined by the method 'build'.
MyClass looks like this:
class MyClass<T> {
final GenericClass<T> param;
MyClass(this.param);
static build<K>() {
return (GenericClass<K> param) => MyClass<K>(param);
}
}
So, what is a valid typedef for it?
There are two concepts of "generic" when it comes to a typedef. The typedef can be generic on a type, or the typedef can refer to a generic function (or both):
A typedef which is generic on T:
typedef F<T> = T Function(T);
Then in usage:
F first = (dynamic arg) => arg; // F means F<dynamic>
F<String> second = (String arg) => arg; // F<String> means both T must be String
A typedef which refers to a generic function on M:
typedef F = M Function<M>(M);
Then in usage:
F first = <M>(M arg) => arg; // The anonymous function is defined as generic
// F<String> -> Illegal, F has no generic argument
// F second = (String arg) => arg -> Illegal, the anonymous function is not generic
Or both:
typedef F<T> = M Function<M>(T,M);
And in usage:
F first = <M>(dynamic arg1, M arg2) => arg2; // F means F<dynamic> so the T must be dynamic
F<String second = <M>(String arg1, M arg2) => arg2; // The T must be String, the function must still be generic on the second arg and return type