I am having trouble understanding why one piece of code prints the future is null
void main() async {
task1();
String str = await task2();
task3(str);
}
void task1() {
print('ring');
}
Future<String> task2() async {
Duration dur = Duration(seconds: 3);
String res;
await Future.delayed(dur, () {
res = 'a bright one!';
return res; // return statement inside the callback.
});
}
void task3(String str) {
print('the future is $str');
}
while this works properly and has the expected behavior of printing 'the future is a bright one'
void main() async {
task1();
String str = await task2();
task3(str);
}
void task1() {
print('ring');
}
Future<String> task2() async {
Duration dur = Duration(seconds: 3);
String res;
await Future.delayed(dur, () {
res = 'a bright one!';
});
return res;
}
void task3(String str) {
print('the future is $str');
}
I am new to asynchronous programming but my understanding is that the callback that is the second argument in Future.delayed is executed after a delay what I don't understand why the placement of the return statement here breaks the code. I tried to run the code in debug mode to trace the code but I didn't understand what is exactly happening. All help is greatly appreciated
Related
Why is the follow code valid? I thought there should be compile-time errors. I thought the return in the body return an int(value 1). If not, it must be returning a Future, which does not comply to the return type either. What has happened with the await?
void longRun() async {
return await Future.delayed(
Duration(seconds: 3),
()=>1,
);
}
If I assign the await part to a variable, like the following, the compiler starts to complain, which is obvious and easy to understand. But why doesn't the code above complain?
void longRun() async {
var foo = await Future.delayed(
Duration(seconds: 3),
()=>1,
);
return foo;
}
Keep studying I've found more confusing thing: all the following versions work. They seem identical, wired.
version1:
void longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version2:
Future<void> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version3:
Future<int> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version4:
Future longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
version5:
Future longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
version6:
void longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
This is mostly about the behavior of =>, not about await. Normally () => 1 can be thought of as shorthand for () { return 1; }, but that's actually an oversimplification.
=> is allowed for void functions as a convenience so that people can write things like:
bool functionWithSideEffect() {
print('Some side effect');
return true;
}
void foo() => functionWithSideEffect();
int _someValue = 0;
set someValue(int value) => _someValue = value;
even though these aren't legal:
var foo() {
// error: A value of type 'bool' can't be returned from the function 'foo'
// because it has a return type of 'void'.
return functionWithSideEffect();
}
set someValue(int value) {
// error: A value of type 'int' can't be returned from the function
// 'someValue' because it has a return type of 'void'.
return _someValue = value;
}
The crux of your confusion is that () => 1 either could be int Function() or void Function(), and type inference picks different things given different constraints.
When you do:
void longRun() async {
return await Future.delayed(
Duration(seconds: 3),
()=>1,
);
}
then type inference works outside-in, propagating the void return type of longRun through the unconstrained, returned expression. The Future.delayed call is inferred to be Future<void>.delayed and the () => 1 callback is inferred to be void Function(). (Arguably a void async function returning Future<void> could be treated as error.)
In contrast, when you do:
void longRun() async {
var foo = await Future.delayed(
Duration(seconds: 3),
()=>1,
);
return foo;
}
now type inference runs in the other direction (inside-out): foo has no explicit type, so it does not constrain the right-hand-side. Therefore () => 1 is instead assumed to be int Function(), which causes Future.delayed to be inferred to be Future<int>.delayed and foo to be inferred as an int. Since foo is an int, attempting to return it from a function declared to return void is an error.
version2:
Future<void> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
You've changed longRun's return type from void to Future<void>. async functions usually should return a Future but may also return void to be fire-and-forget. The only difference from version 1 is that callers can now wait (fire a callback) when longRun completes. () => 1 is still inferred to be void Function().
version3:
Future<int> longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
Same as version2 except longRun returns Future<int> instead of Future<void>. Now () => 1 is inferred to be int Function().
version4:
Future longRun() async {
return await Future.delayed(Duration(seconds:2), ()=>1);
}
longRun's return type is now Future, which means Future<dynamic>. () => 1 is inferred to be dynamic Function().
version5:
Future longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
Same as version4 except there is no explicit return statement. Now the Future.delayed expression is no longer constrained by longRun's return type, and inference will flow inside-out; () => 1 is assumed to be int Function().
version6:
void longRun() async {
await Future.delayed(Duration(seconds:2), ()=>1);
}
Same as version5 except that longRun returns void and is a fire-and-forget function. Callers cannot be notified when longRun completes.
(Note that in the above, when I write () => 1 is inferred to be int Function() or void Function(), it really should be FutureOr<int> Function() or FutureOr<void> Function(), but that's not the important part.)
Edit:
Pre-emptively addressing some potential follow-up questions:
Why is:
void longRun() async {
int f() {
return 1;
}
return await Future<void>.delayed(
Duration(seconds: 3),
f,
);
}
okay, but:
void longRun() async {
return await Future<void>.delayed(
Duration(seconds: 3),
// info: Don't assign to void.
() {
return 1;
},
);
}
generates an analysis complaint? Both versions are legal because substituting a Future<U> for a Future<T> is legal when U is a subtype of T. When T is void, U can be anything; the value can just be ignored. (In Dart, partly for historical reasons when it didn't always have a void type, void actually means that the value cannot be used and not that there is no value. void x = 42; is legal, but attempting to read the value of x would be an error. This is why the "Don't assign to void" analysis complaint isn't categorized as an error.)
In the second version that uses an anonymous function, the tighter locality of the return statement allows the analyzer to perform more extensive checks.
When adding async* to listen method it isn't executing the function body
import 'dart:async';
main(List<String> args) {
print('====');
tranStream();
}
Stream<int> intStreamer() async* {
int c = 0;
while (c <= 30) {
await Future.delayed(Duration(seconds: 1));
yield c++;
}
}
tranStream() {
intStreamer().listen((event) async* { // If i remove async* from here it will execute print statement
print(event);
});
}
If i remove async* from intStreamer().listen it will execute print statement. What is happening here?
When you are using async*, the method will only start being executed when the returned Stream gets a subscriber. Your code does not really make any sense since listen takes a method which returns void. So nobody are going to listen on the returned Stream which the given method will automatically return (based on the async* keyword).
I would also properly rewrite your code so you instead of listen uses await for which I think makes it more clear what happens`:
import 'dart:async';
Future<void> main(List<String> args) async {
print('====');
await tranStream();
}
Stream<int> intStreamer() async* {
int c = 0;
while (c <= 30) {
await Future<void>.delayed(const Duration(seconds: 1));
yield c++;
}
}
Future<void> tranStream() async {
await for (final event in intStreamer()) {
print(event);
}
}
Update with example of tranStream returns a Stream:
import 'dart:async';
Future<void> main(List<String> args) async {
print('====');
await for (final event in tranStream()) {
print('main got: $event');
}
}
Stream<int> intStreamer() async* {
int c = 0;
while (c <= 30) {
await Future<void>.delayed(const Duration(seconds: 1));
yield c++;
}
}
Stream<int> tranStream() async* {
await for (final event in intStreamer()) {
print('tranStream got: $event');
yield event;
}
}
import 'dart:io';
void main() {
performTask();
}
void performTask() {
task1();
task2();
task3();
}
void task1() {
print('task1');
}
void task2() {
Duration timeDuration = Duration(seconds: 3);
sleep(timeDuration);
print('task2');
}
void task3() {
print('task3');
}
After executing first function that is task1() it throws an error:
Uncaught Error: Unsupported operation: ProcessUtils._sleep
I just hit the same roadblock! Not sure how to get sleep to work, but i found that using async/await is a bit more predictable:
// Unused import
// import 'dart:io'; // Delete me
void main() {
performTask();
}
// No need for async/await here, just the method in which it's used to await Future.delayed
void performTask() {
task1();
task2();
task3();
}
void task1() {
print('task1');
}
// I'm still a bit new to flutter, but as I understand it, best practice is to use Future<T> myFunction() {...} when defining async/await method.
// In this case <T> is <void> because you're not returning anything!
Future<void> task2() async {
Duration timeDuration = Duration(seconds: 3);
// sleep(timeDuration) // Delete Me
await Future.duration(timeDuration); // replacement for the sleep method, comes from the 'package:flutter/material.dart'
print('task2');
}
void task3() {
print('task3');
}
Credit: How can I "sleep" a Dart program
Since Future.duration doesn't
await Future.delayed(const Duration(seconds: 1));
credit: How can I "sleep" a Dart program
I need to call dart function do something and return data back to aqueduct controller. So, Can I call any dart function inside aqueduct response controller? If yes, how?
class NtmsApiController extends Controller {
#override
Future<RequestOrResponse> handle(Request request) async {
try {
if (request.path.remainingPath != null) {
_requestValue = request.path.remainingPath;
…
… can I go from here to dart function and get data back???? If yes, how?
UPDATE CODE:
I have global variable and it prints in null. Once the socket gets the data the void _printResponse(String _response) prints the data and from there I assign the data to global variable. But in Future handle data become null so I cannot return the as a response object. Any idea?
#override
Future<RequestOrResponse> handle(Request request) async {
_stopWatch = Stopwatch() //Global
..start();
_response = ""; // Global
if (request.path.remainingPath != null) {
final _requestValue = request.path.remainingPath;
await _getData(_requestValue);
}
print(_secureResponse); // It prints null, _secureResponse is Global variable
return Response.ok("$_secureResponse")
..contentType = ContentType.json;
}
//TODO: GET DATA FROM CSBINS
Future<Null> _getData(String _request) async {
await Socket.connect("192.168.22.120", 3000).then((Socket sock) {
_socket = sock;
_socket.write('$_request\r\n');
_socket.listen (dataHandler,
onError: errorHandler,
onDone: doneHandler,
cancelOnError: true);
}).catchError((AsyncError e) {
_response = "Server_Error";
});
}
void dataHandler(data) {
final List<int> byteArray = data;
_response = String.fromCharCodes(byteArray).trim();
}
void errorHandler(error, StackTrace trace) {
_response = "Server_Error";
}
void doneHandler() {
_socket.destroy();
}
void _printResponse(String _response) {
// prints succefully ***************************
print("$_response ... (${_stopWatch.elapsedMilliseconds} ms)");
_secureResponse = _response;
_stopWatch..stop();
if (_stopWatch.isRunning == false) {
_socket.flush();
_socket.close();
print("Socket Closed.");
}
}
I want to return a String from an async function but I get a Future
What am I doing wrong;
Example
main() {
String s;
s = dummy("http://www.google.com");
}
String dummy(String s) {
String response;
response = readURL(s);
return response;
}
Future<String> readURL(String requestString) async {
String response = await http.read(requestString);
print(response);
return response;
}
Error:
type '_Future' is not a subtype of type 'String' of 'response'.
A function that's annotated with async will always return a Future.
so when you call readUrl(s) you can await its result.
To use await, the caller (here your main function) has to be marked as async. So the end result could look like this:
main() async {
String s = await dummy("http://www.google.com");
}
Future<String> dummy(String s) async {
String response = await readURL(s);
return (response);
}
Future<String> readURL(String requestString) async {
String response = await http.read(requestString);
print(response);
return(response);
}
The thing to notice here: If you use await in a function, it is now considered as function that returns a Future. So every function you convert to be async will now return a Future.
Here is the Simple Two way to get value from Function with return type Future<Type>
1- First way (best way, as you call this code from any file)
FutureFunctionName.then((val) {
val contains data
});
For example- (I am posting one from real example)
Future<String> getUserAgents() async {
String userAgent;
await FlutterUserAgent.init();
userAgent = FlutterUserAgent.webViewUserAgent;
return userAgent;
}
String userAgent;
getUserAgents().then((val) {
userAgent = val;
});
print(userAgent); // you will get output
2- Second way (use a global variable to get data)
String userAgent;
Future<void> getUserAgents() async {
await FlutterUserAgent.init();
userAgent = FlutterUserAgent.webViewUserAgent;
}
print(userAgent);