Dart: forEach method parameter accepts void but even returning int works - flutter

In iterable.dart file, code for forEach is:
void forEach(void f(E element)) {
for (E element in this) f(element);
}
You can see, forEach parameter accepts a method and its return type should be void but following code just works fine without any error:
var list = [1, 2, 3];
list.forEach((item) {
print(item);
return true; // should show an error
});

The callback you pass to forEach() would be inferred as a bool Function(int), and List<int>.forEach() expects a void Function(int). This is accepted since T Function() is considered a subtype of void Function(); T Function() is substitutable anywhere void Function() is used.

I think in dart when you use the void return type with a function , the return type could be void or anything else
for example :
main()=>print(function() as int); // the output is 12
void function()=>12;
in this example the void function returns a value
example 2:
class Super {
void function(){}
}
class Child extends Super{
#override
int function(){
return 10;
}
you can override a function that have a type of void and change the type of the function to anything else.

Related

Dart assign a function/method to variable after declaration

I want to assign a function, with parameters, to an already declared variable, So I be able to execute it later.
Something like that:
void main() {
Function p;
p = print('1'); // should not execute;
p;
}
How do I do that? Is it possible?
You can do it like
void main() {
late Function p;
p = () {
print('1');
};
p(); // it will print 1
}
For the example you have provided you can do this:
void main() {
Function p = (){print('1');};
}
now you can call p() to execute it later.
void Function(Object? object) p;
p = print;
p.call('1');

How to null-check a simple Function in Dart?

void main() {
Car myCar = Car(drive: slowDrive);
myCar.drive();
}
class Car {
Car({this.drive});
Function? drive;
}
void slowDrive() {
print('Driving slowly');
}
void fastDrive() {
print('Driving fast');
}
The error says An expression whose value can be null must be null-checked before it can be dereferenced.
How can I null-check this?
It can be done using .call()
void main() {
Car myCar = Car(drive: slowDrive);
myCar.drive?.call();
}
class Car {
Car({this.drive});
Function? drive;
}
void slowDrive() {
print('Driving slowly');
}
void fastDrive() {
print('Driving fast');
}
call accepts also function with parameters
void main() {
Car myCar = Car(drive: slowDrive);
myCar.drive?.call(5);
}
class Car {
Car({this.drive});
Function(int)? drive;
}
void slowDrive(int a) {
print('Driving slowly');
}
void fastDrive(int a) {
print('Driving fast');
}
You can make the parameter drive required:
void main() {
Car myCar = Car(drive : slowDrive);
myCar.drive();
}
class Car {
Car({required this.drive});
Function drive;
}
void slowDrive() {
print('Driving slowly');
}
void fastDrive() {
print('Driving fast');
}
To guarantee that you never see a null parameter with a non-nullable type, the type checker requires all optional parameters to either have a nullable type or a default value. What if you want to have a named parameter with a nullable type and no default value? That would imply that you want to require the caller to always pass it. In other words, you want a parameter that is named but not optional.
https://dart.dev/null-safety/understanding-null-safety#required-named-parameters

void vs Null return types Flutter

I was looking at Flutter Boring Show and they used Future<Null> instead of Future<void> return type for a method. Then I came across this question but what confuses me is that as the answer explained,
The type void allows values of any type, but communicates that the value shouldn't be used.
I tried to check that in dart so I used the following code:
void main() {
for (int i = 0; i < 5; i++) {
print('hello ${i + 1}');
}
return 1;
}
And it gave me the following error:
Error: Can't return a value from a void function. return 1;
My question is that can you return anything if the function return type is void? Also what is the difference between Null & void as return types and which one is better to use if they have similar results?
Thanks.

RxJava2: Using Flowable with zipWith

I'm trying to make the following code work me but something is wrong, here is a snippet:
private void myMethod() {
Flowable.fromIterable(cache)
.zipWith(this::doesExist, (record, exist) -> {
// do stuff
return true;
}).subscrib();
}
private Flowable<Boolean> doesExist(CacheRecord record) {
// Do something
return Flowable.just(true);
}
This doesn't compile, any idea?
UPDATE:
Any thoughts about the following snippet:
Flowable.fromIterable(m_cache) //
.flatMapCompletable(cachedStation -> {
return Single.zip(Single.just(cachedStation), doesIssueExist(cachedStation), (record, exist) -> {
System.out.println(cachedStation + ", " + exist);
return true;
}).toCompletable();
}).subscribe();
Your doesExist method requires a CacheRecord as a parameter. But the method reference you have given this::doesExist sends an instance of Subscriber<? super Object> that's why the incompatible type error is showing.
The expanded form of your method is given below.
private void myMethod() {
Flowable.fromIterable(cache)
.zipWith(new Publisher<Object>() {
#Override
public void subscribe(Subscriber<? super Object> s) {
doesExist(s);
}
}, (record, exist) -> {
// do stuff
return true;
}).subscribe();
}
Here, the first parameter to zipWith
new Publisher<Object>() {
#Override
public void subscribe(Subscriber<? super Object> s) {
doesExist(s);
}
}
is what you have shortened as this::doesExist
As you can see the zipWith requires the first parameter a Publisher, and you have created an anonymous Publisher, and in the subscribe method you are calling doesExist(s) by sending the Subscriber<? super Object> s, which is not the required type. Your method reference statement this::doesExist does exactly the above operation and that's why the incompatible type error is shown by the compiler.
If you are trying to zip the Flowable with the flowable returned by doesExist method, you can directly call it, without method reference, by passing a valid CacheRecord object as follows
Flowable.fromIterable(cache)
.zipWith(doesExist(anotherCache), (record, exist) -> {
// do stuff
return true;
}).subscribe();
Note: See method reference for more information
Update: If you are trying to pass the items emitted by fromIterable to doesExist method and get combined result boolean and cacheRecord, then
create a holder class as follows
class CacheRecordResult {
CacheRecord cacheRecord;
boolean isExist;
public CacheRecordResult(CacheRecord cacheRecord, boolean isExist) {
this.cacheRecord = cacheRecord;
this.isExist = isExist;
}
}
Then subscribe to CacheRecordResult as follows
private void myMethod() {
Flowable.fromIterable(cache)
.flatMap(cacheRecord -> doesExist(cacheRecord)
.map(exist -> new CacheRecordResult(cacheRecord, exist)))
.subscribe(cacheRecordResult -> {
CacheRecord cacheRecord = cacheRecordResult.cacheRecord;
boolean isExist = cacheRecordResult.isExist;
});
}

What are function typedefs / function-type aliases in Dart?

I have read the description, and I understand that it is a function-type alias.
A typedef, or function-type alias, gives a function type a name that you can use when declaring fields and return types. A typedef retains type information when a function type is assigned to a variable.
http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#kix.yyd520hand9j
But how do I use it? Why declaring fields with a function-type? When do I use it? What problem does it solve?
I think I need one or two real code examples.
A common usage pattern of typedef in Dart is defining a callback interface. For example:
typedef void LoggerOutputFunction(String msg);
class Logger {
LoggerOutputFunction out;
Logger() {
out = print;
}
void log(String msg) {
out(msg);
}
}
void timestampLoggerOutputFunction(String msg) {
String timeStamp = new Date.now().toString();
print('${timeStamp}: $msg');
}
void main() {
Logger l = new Logger();
l.log('Hello World');
l.out = timestampLoggerOutputFunction;
l.log('Hello World');
}
Running the above sample yields the following output:
Hello World
2012-09-22 10:19:15.139: Hello World
The typedef line says that LoggerOutputFunction takes a String parameter and returns void.
timestampLoggerOutputFunction matches that definition and thus can be assigned to the out field.
Let me know if you need another example.
Dart 1.24 introduces a new typedef syntax to also support generic functions. The previous syntax is still supported.
typedef F = List<T> Function<T>(T);
For more details see https://github.com/dart-lang/sdk/blob/master/docs/language/informal/generic-function-type-alias.md
Function types can also be specified inline
void foo<T, S>(T Function(int, S) aFunction) {...}
See also https://www.dartlang.org/guides/language/language-tour#typedefs
typedef LoggerOutputFunction = void Function(String msg);
this looks much more clear than previous version
Just slightly modified answer, according to the latest typedef syntax, The example could be updated to:
typedef LoggerOutputFunction = void Function(String msg);
class Logger {
LoggerOutputFunction out;
Logger() {
out = print;
}
void log(String msg) {
out(msg);
}
}
void timestampLoggerOutputFunction(String msg) {
String timeStamp = new Date.now().toString();
print('${timeStamp}: $msg');
}
void main() {
Logger l = new Logger();
l.log('Hello World');
l.out = timestampLoggerOutputFunction;
l.log('Hello World');
}
Typedef in Dart is used to create a user-defined function (alias) for other application functions,
Syntax: typedef function_name (parameters);
With the help of a typedef, we can also assign a variable to a function.
Syntax:typedef variable_name = function_name;
After assigning the variable, if we have to invoke it then we go as:
Syntax: variable_name(parameters);
Example:
// Defining alias name
typedef MainFunction(int a, int b);
functionOne(int a, int b) {
print("This is FunctionOne");
print("$a and $b are lucky numbers !!");
}
functionTwo(int a, int b) {
print("This is FunctionTwo");
print("$a + $b is equal to ${a + b}.");
}
// Main Function
void main() {
// use alias
MainFunction number = functionOne;
number(1, 2);
number = functionTwo;
// Calling number
number(3, 4);
}
Output:
This is FunctionOne
1 and 2 are lucky numbers !!
This is FunctionTwo
3 + 4 is equal to 7
Since dart version 2.13 you can use typedef not only with functions but with every object you want.
Eg this code is now perfectly valid:
typedef IntList = List<int>;
IntList il = [1, 2, 3];
For more details see updated info:
https://dart.dev/guides/language/language-tour#typedefs
https://www.tutorialspoint.com/dart_programming/dart_programming_typedef.htm
typedef ManyOperation(int firstNo , int secondNo); //function signature
Add(int firstNo,int second){
print("Add result is ${firstNo+second}");
}
Subtract(int firstNo,int second){
print("Subtract result is ${firstNo-second}");
}
Divide(int firstNo,int second){
print("Divide result is ${firstNo/second}");
}
Calculator(int a,int b ,ManyOperation oper){
print("Inside calculator");
oper(a,b);
}
main(){
Calculator(5,5,Add);
Calculator(5,5,Subtract);
Calculator(5,5,Divide);
}