Block until field is initialized - dart

trying to block the execution within a setter until the filed value changes and i know that it will change within a few microseconds, to demonstrate the problem i wrote:
import 'dart:async';
void main() {
new Timer.periodic(new Duration(seconds:1),(t)=>print(Store.x));
new Timer.periodic(new Duration(seconds:3),(t)=>Store.x='initialized');
}
class Store{
static String _x = null;
static set x(v) => _x=v;
static get x{
//how do i block here until x is initialized
return _x;
}
}
A while(x==null); caused stackoverflow, any idea how to do this properly within the setter?
basically i want the setter to return the value when its initialized it should never return null.

This can't be done.
Dart is single-threaded. If you stop execution the code updating the field can't be executed.
If you want something like that you need to switch to async execution.
import 'dart:async';
void main() {
new Timer.periodic(new Duration(seconds:1),(t)=>print(Store.x));
new Timer.periodic(new Duration(seconds:3),(t)=>Store.x='initalized');
}
class Store{
static String _x = null;
static set x(v) => _x=v;
static Future<String> get x async {
while(x == null) {
await new Future.delayed(const Duration(milliseconds: 20),
}
return _x;
}
}
func someFunc() async {
var x = await new Store.x;
}
I wouldn't consider this Future.delayed() good design for this use case. It should be implemented in a way that Store.x fires an event or completes a future when the value changed.

Related

Dart - How to add async to class? [duplicate]

Let's assume that an initialization of MyComponent in Dart requires sending an HttpRequest to the server. Is it possible to construct an object synchronously and defer a 'real' initialization till the response come back?
In the example below, the _init() function is not called until "done" is printed. Is it possible to fix this?
import 'dart:async';
import 'dart:io';
class MyComponent{
MyComponent() {
_init();
}
Future _init() async {
print("init");
}
}
void main() {
var c = new MyComponent();
sleep(const Duration(seconds: 1));
print("done");
}
Output:
done
init
Probably the best way to handle this is with a factory function, which calls a private constructor.
In Dart, private methods start with an underscore, and "additional" constructors require a name in the form ClassName.constructorName, since Dart doesn't support function overloading. This means that private constructors require a name, which starts with an underscore (MyComponent._create in the below example).
import 'dart:async';
import 'dart:io';
class MyComponent{
/// Private constructor
MyComponent._create() {
print("_create() (private constructor)");
// Do most of your initialization here, that's what a constructor is for
//...
}
/// Public factory
static Future<MyComponent> create() async {
print("create() (public factory)");
// Call the private constructor
var component = MyComponent._create();
// Do initialization that requires async
//await component._complexAsyncInit();
// Return the fully initialized object
return component;
}
}
void main() async {
var c = await MyComponent.create();
print("done");
}
This way, it's impossible to accidentally create an improperly initialized object out of the class. The only available constructor is private, so the only way to create an object is with the factory, which performs proper initialization.
A constructor can only return an instance of the class it is a constructor of (MyComponent). Your requirement would require a constructor to return Future<MyComponent> which is not supported.
You either need to make an explicit initialization method that needs to be called by the user of your class like:
class MyComponent{
MyComponent();
Future init() async {
print("init");
}
}
void main() async {
var c = new MyComponent();
await c.init();
print("done");
}
or you start initialization in the consturctor and allow the user of the component to wait for initialization to be done.
class MyComponent{
Future _doneFuture;
MyComponent() {
_doneFuture = _init();
}
Future _init() async {
print("init");
}
Future get initializationDone => _doneFuture
}
void main() async {
var c = new MyComponent();
await c.initializationDone;
print("done");
}
When _doneFuture was already completed await c.initializationDone returns immediately otherwise it waits for the future to complete first.
I agree, an asynchronous factory function would help Dart devs with this problem. #kankaristo has IMHO given the best answer, a static async method that returns a fully constructed and initialized object. You have to deal with the async somehow, and breaking the init in two will lead to bugs.

how to make singleton class with some initialization code?

I have tried the answers in here How do you build a Singleton in Dart?
but I can't achieve what I want. so basically I want to make a Shared Preference Service as a singleton class. currently my code is like this. this is just a regular class, not a singleton.
class SharedPreferenceService {
late SharedPreferences _prefs;
SharedPreferenceService() {
SharedPreferences.getInstance().then((value) => _prefs = value);
}
Future<void> setIntroPagesHaveBeenViewed() async {
await _prefs.setBool(SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED, true);
}
Future<bool> checkIfIntroPagesHaveBeenViewed() async {
return _prefs.getBool(SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED) ?? false;
}
}
I need a singleton class, but when the instance is initialize for the first time, I also need to initialize _pref , so then I can access that _pref on the methods
Your problem is that initialization is asynchronous.
That means that the first time the singleton instance is accessed, that access needs to be asynchronous too (and so does any further access which happens before the initialization completes). However, the usage pattern of a singleton like this is such that you don't know which access is the first. So you have to make every access asynchronous.
Example:
class SharedPreferenceService {
static final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Future<void> setIntroPagesHaveBeenViewed() async {
await (await _prefs).setBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED, true);
}
Future<bool> checkIfIntroPagesHaveBeenViewed() async {
return (await _prefs).getBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED) ?? false;
}
}
If all the methods are asynchronous anyway, that extra delay is not going to be a problem.
If you really, really only want to do that extra await if absolutely necessary,
you can cache the value, like you try to here:
class SharedPreferenceService {
static final Future<SharedPreferences> _prefsFuture = SharedPreferences.getInstance();
static SharedPreferences? _prefs;
Future<void> setIntroPagesHaveBeenViewed() async {
var prefs = _prefs ??= await _prefsFuture;
await _prefs.setBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED, true);
}
Future<bool> checkIfIntroPagesHaveBeenViewed() async {
var prefs = _prefs ??= await _prefsFuture;
return _prefs.getBool(
SharedPreferenceKey.INTRODUCTION_PAGES_HAVE_BEEN_VIEWED) ?? false;
}
}

What are the pros and cons of async, when to and when not to use it and what other alternatives to callback are there?

callbacks or asynchronous methods or other options
A solution to the callback plague is "await" and "async" or more specifacally 'dart:async' library.
Now, what is the cost of asynchrony?
When should we not use them?
What are the other alternatives?
The below is a badly coded non-polymer custom element that acts like a messageBox in desktop environment. It gives me less braces and parenthesis-es but requires the caller to be also async or use "show().then((v){print(v);});" pattern. Should I avoid the pattern like this?
Is callback better? Or there is an even smarter way?
Polling version
import 'dart:html';
import 'dart:async';
void init(){
document.registerElement('list-modal',ListModal);
}
class ListModal extends HtmlElement{
ListModal.created():super.created();
String _modal_returns="";
void set modal_returns(String v){
///use the modal_returns setter to
///implement a custom behaviour for
///the return value of the show method
///within the callback you can pass on calling append .
_modal_returns=v;
}
factory ListModal(){
var e = new Element.tag('list-modal');
e.style..backgroundColor="olive"
..position="absolute"
..margin="auto"
..top="50%"
..verticalAlign="middle";
var close_b = new DivElement();
close_b.text = "X";
close_b.style..right="0"
..top="0"
..margin="0"
..verticalAlign="none"
..backgroundColor="blue"
..position="absolute";
close_b.onClick.listen((_){
e.hide();
});
e.append(close_b,(_)=>e.hide());
e.hide();
return e;
}
#override
ListModal append(
HtmlElement e,
[Function clickHandler=null]
){
super.append(e);
if(clickHandler!=null) {
e.onClick.listen(clickHandler);
}else{
e.onClick.listen((_){
this.hide();
_modal_returns = e.text;
});
}
return this;
}
Future<String> show() async{
_modal_returns = '';
this.hidden=false;
await wait_for_input();
print(_modal_returns);
return _modal_returns;
}
wait_for_input() async{
while(_modal_returns=="" && !this.hidden){
await delay();
}
}
void hide(){
this.hidden=true;
}
Future delay() async{
return new Future.delayed(
new Duration(milliseconds: 100));
}
}
Non-polling version
In response to Günter Zöchbauer's wisdom(avoid polling), posting a version that uses a completer. Thanks you as always Günter Zöchbauer:
import 'dart:html';
import 'dart:async';
void init(){
document.registerElement('list-modal',ListModal);
}
class ListModal extends HtmlElement{
ListModal.created():super.created();
String _modal_returns="";
Completer _completer;
void set modal_returns(String v){
///use the modal_returns setter to
///implement a custom behaviour for
///the return value of the show method.
///Use this setter within the callback for
///append. Always call hide() after
///setting modal_returns.
_modal_returns=v;
}
factory ListModal(){
var e = new Element.tag('list-modal');
e.style..backgroundColor="olive"
..position="absolute"
..margin="auto"
..top="50%"
..verticalAlign="middle";
var close_b = new DivElement();
close_b.text = "X";
close_b.style..right="0"
..top="0"
..margin="0"
..verticalAlign="none"
..backgroundColor="blue"
..position="absolute";
close_b.onClick.listen((_){
e.hide();
});
e.append(close_b,(_){e.hide();});
e.hide();
return e;
}
#override
ListModal append(
HtmlElement e,
[Function clickHandler=null]
){
super.append(e);
if(clickHandler!=null) {
e.onClick.listen(clickHandler);
}else{
e.onClick.listen((_){
_modal_returns = e.text;
this.hide();
});
}
return this;
}
Future<String> show() async{
_modal_returns = '';
_completer = new Completer();
this.hidden=false;
return _completer.future;
}
void hide(){
hidden=true;
_completer?.complete(_modal_returns);
_completer=null;
}
}
Usually there is no question whether async should be used or not. Usually one would try to avoid it. As soon as you call an async API your code goes async without a possibility to choose if you want that or not.
There are situations where async execution is intentionally made async. For example to split up large computation in smaller chunks to not starve the event queue from being processed.
On the server side there are several API functions that allow to choose between sync and async versions. There was an extensive discussion about when to use which. I'll look it up and add the link.
The disadvantages of using async / await instead of .then() should be minimal.
minimal Dart SDK version with async / await support is 1.9.1
the VM needs to do some additional rewriting before the code is executed the first time, but this is usually neglectable.
Your code seems to do polling.
wait_for_input() async {
while(_modal_returns=="" && !this.hidden){
await delay();
}
}
This should be avoided if possible.
It would be better to let the modal manage its hidden state itself (by adding a hide() method for example), then it doesn't have to poll whether it was hidden from the outside.

Extending Future

I find quite a lot about using but not about defining futures in Dart. Lets say I have letsWait() which takes quite some time. How do I use the Future class?
import 'dart:async';
void main() {
print('Let\'s get started');
ArtificialWait waitPoint = new ArtificialWait();
Future<String> future = waitPoint.letsWait();
// and how about printing the return here?
print('something fast');
}
class ArtificialWait extends Future<String> {
String letsWait() {
for (var i = 0; i < 5000000000; i++) {
// lol
}
return 'finally';
}
}
This try gives me a:
unresolved implicit call to super constructor 'Future()' class ArtificialWait extends Future<String> {
I don't know why you want to inherit from Future.
Normally you would use this like:
import 'dart:async';
void main() {
print('Let\'s get started');
artificialWait().then((e) => print(e));
// and how about printing the return here?
print('something fast');
}
Future<String> artificialWait () {
var completer = new Completer<String>();
Timer.run(() {
for (var i = 0; i < 5000000000; i++) {
// lol
}
completer.complete('finally');
});
return completer.future;
}
Instead of trying to extend a future, you just need to 'use' the future.
import 'dart:async';
void main() {
print('Let\'s get started');
ArtificialWait waitPoint = new ArtificialWait();
Future<String> future = waitPoint.letsWait();
// and how about printing the return here?
print('something fast');
}
class ArtificialWait {
Future<String> letsWait => new Future<String>(_letsWait);
String _letsWait() {
for (var i = 0; i < 5000000000; i++) {
// lol
}
return 'finally';
}
}
Generally a future can be constructed without using a completer except in certain circumstances. The default constructor for Future will automatically wrap your passed function (which takes no arguments) in a Timer.run() to perform it asynchronously.

How return Future from Future? Or this is prohibited in async library?

How I can return Future value from Future object?
This code does not work.
import 'dart:async';
void main() {
var temp = foo();
temp.then((Future<int> future) {
future.then((int result) {
print(result);
});
});
}
Future<Future<int>> foo() {
return new Future<Future<int>>(() {
return new Future<int>(() => 5);
});
}
How to prevent unnecessary unwrapping?
In this case in async library 'Future' declared as generic class.
abstract class Future<T> {
}
If I create expression as the following
new Future<Future<int>>();
Then with type T specified as Future<int> which result expected from generic class Future?
I thing that result must be as specified in type argument T.
I.e. Future<int>.
But result is not as expected.
There is no information found about this abnormal behavior on Dart API site.
If this is a "feature" (but I think that abnormal behavior wrongly to call "feature') then why it not documented in Dart API?
How can be explained this discrepancy?
Why this code not generated errors and warnings?
Another IDENTICAL example but w/o using Future.
void main() {
var temp = foo();
temp.baz((Foo<int> foo) {
foo.baz((int result) {
print(result);
});
});
}
Foo<Foo<int>> foo() {
return new Foo<Foo<int>>(() {
return new Foo<int>(() => 5);
});
}
If in this case result will be as when using Future (i.e. unexpected) then how we can call this code?
Normal or abnormal?
Or maybe the Future in Dart some special (magic)?
Look at the api documentation
http://api.dartlang.org/docs/releases/latest/dart_async/Future.html
It says there:
If the returned value is itself a Future, completion of the created future will wait until
the returned future completes, and will then complete with the same result.
I guess that means you can't return a Future from a Future.
But you could return a list of futures.
void main() {
var temp = foo();
temp.then((List<Future<int>> list) {
list[0].then((int result) {
print(result);
});
});
}
Future<List<Future<int>>> foo() {
return new Future<List<Future<int>>>(() {
return [new Future<int>(() => 5)];
});
}
There is no need for any of that extra wrapping. According to the Future documentation:
If the returned value is itself a [Future], completion of the created
future will wait until the returned future completes, and will then
complete with the same result.
This means you can rewrite your code as:
import 'dart:async';
void main() {
var temp = foo();
temp.then((int result) {
print(result);
});
}
Future<int> foo() {
return new Future<int>(() {
return new Future<int>(() => 5);
});
}
This is a lot cleaner to work with and provides the expected result.

Resources