How to emulate scanf in dart?
I want to translate the following C code into dart.
#include <stdio.h>
void main() {
double a,b;
printf("a b? ");
scanf("%lf%lf",&a,&b);
printf("a=%lf b=%lf\n",a,b);
}
As I know, I cannot use call by reference, variable number arguments function call or destructuring assignment in dart.
So, it seems that it is impossible to make a function emulating scanf for now.
Here is my version in dart.
import "dart:io";
void main() {
stdout.write("a b? ");
var line = stdin.readLineSync();
var tokens = line?.split(RegExp(r'\s+'));
double a = double.tryParse(tokens?[0] ?? '0') ?? 0;
double b = double.tryParse(tokens?[1] ?? '0') ?? 0;
print("a=$a b=$b");
}
In there any possible improvement in the code?
Here is another version using Iterator.
import 'dart:io';
void main() {
stdout.write("a b? ");
var scan = Scan();
var a = scan.getDouble();
var b = scan.getInt();
print("a=$a b=$b");
}
class Scan {
Iterator? it;
Scan([String? line]) {
it = (line ?? stdin.readLineSync())?.split(RegExp(r'\s+')).iterator;
}
double getDouble() {
return double.tryParse(it?.moveNext() == true ? it?.current : '') ?? 0;
}
int getInt() {
return int.tryParse(it?.moveNext() == true ? it?.current : '') ?? 0;
}
}
The Dart debugger is apparently calling collection methods to display values in the Variables view. The result is that the execution is completely different in Debug mode than in Run mode.
In the following example, Run prints 2, while Debug prints 8 or 14 or 20 depending on the breakpoints...
How can I prevent this?
import 'dart:collection';
main() {
var test = CustomMap();
test.addAll({1: 1, 2: 2, 3: 3});
test[1];
test[2];
print(test.callCount);
}
class CustomMap extends MapBase<int, int> {
var _map = Map<int, int>();
int callCount = 0;
int? operator [](Object? key) {
callCount++;
return _map[key];
}
void operator []=(int key, int value) => _map[key] = value;
void clear() {}
Iterable<int> get keys => _map.keys;
int? remove(Object? key) => _map.remove(key);
}
My goal is to process gui events in parallel, but only when I have processing power plus the last event must always be processed. I have a panel which can be resized. Every resize produces new event. I want to process new width, height of panel on a computation thread pool (Scheduler newParallel = Schedulers.newParallel("Computation", 4);) in ordered fashion. If none of the threads is available I need to drop the oldest gui events and when thread becomes available it should take the latest from the backpressure queue.
I wrote the test app and I have several issues. After gui events stop to being produced there is still considerable time when processing is done which ultimately will manifest as an unwanted animation effect. My guess is that the backpressure queue size=256 kept the old events and is still processing it but it does not match with the result logs. After producing 561 events only 33 events were processed (why not 256?) with ids [0-32, 560]. Is there a way to change the backpressure buffer size (I could not find a way to do it) or maybe there is totally different way I should approach this task?
I attach test code for recreation.
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink.OverflowStrategy;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
public class BackpressureApp extends Application {
public static void main(String[] args) {
launch(args);
}
private int id = 0;
#Override
public void start(Stage stage) throws Exception {
Scheduler computation = Schedulers.newParallel("Computation", 4);
Flux<Width> flux = Flux.create(sink -> {
stage.widthProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
Width width = new Width(id++, newValue.doubleValue());
System.out.println("[" + Thread.currentThread().getName() + "] PUBLISH width=" + width);
sink.next(width);
});
}, OverflowStrategy.LATEST);
flux.concatMap(width -> Mono.just(width).subscribeOn(computation).map(this::process))
.publishOn(Schedulers.single())
.subscribe(width -> {
System.out.println("[" + Thread.currentThread().getName() + "] RECEIVED width=" + width);
});
stage.setScene(new Scene(new StackPane()));
stage.show();
}
public Width process(Width width) {
Random random = new Random();
int next = random.nextInt(1000);
try {
TimeUnit.MILLISECONDS.sleep(next);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("[" + Thread.currentThread().getName() + "] PROCESS width=" + width + " sleep=" + next);
return width;
}
}
class Width {
private final int id;
private final double width;
public Width(int id, double width) {
super();
this.id = id;
this.width = width;
}
public int getId() {
return id;
}
public double getWidth() {
return width;
}
#Override
public String toString() {
return "Width[id=" + id + ", width=" + width + "]";
}
}
I am new to Dart. To become familiar with Dart, I created this script. It works fine with the editor and pub serve. But pub serve dart2js logs these two warnings, which I do not understand:
No member named 'length' in class 'ElementList'
No operator '[]' in class ElementList
coloring.dart:
import 'dart:math';
import 'dart:html';
import 'dart:async';
const String CLICK_ME = 'Click me to pause!';
void randomColoring(StreamSubscription subscription) {
final Random random = new Random();
final Element intro = querySelector("#intro");
final ElementList<Element> boxes = querySelectorAll('.box');
final Element info = querySelector("#info");
subscription.onData((eventValue) {
var box = random.nextInt(boxes.length); /// WARNING
var hexCssColor = random.nextInt(0xFFFFFF + 1).toRadixString(16)
.padLeft(6, "0").toUpperCase();
boxes[box].style.background = "#$hexCssColor"; /// WARNING
info.text = eventValue.toString();
print("box: $box - hexCssColor: $hexCssColor - count: $eventValue");
});
var text = intro.text;
intro
..text = CLICK_ME
..onClick.listen((mouseEvent) {
if (subscription.isPaused) {
intro.text = CLICK_ME;
subscription.resume();
} else {
intro.text = text;
subscription.pause();
}
});
}
There is a bug for the [] operator of ElementList https://code.google.com/p/dart/issues/detail?id=19628 (fixed at June 26).
What Dart version are you using?
I wasn't able to find something about length but I guess it's a bug in Dart2JS.
You can report it at http://dartbug.com/new
But maybe the fix for the [] bug applies here as well.
How do I read console input from stdin in Dart?
Is there a scanf in Dart?
The readLineSync() method of stdin allows to capture a String from the console:
import 'dart:convert';
import 'dart:io';
void main() {
print('1 + 1 = ...');
var line = stdin.readLineSync(encoding: utf8);
print(line?.trim() == '2' ? 'Yup!' : 'Nope :(');
}
Old version:
import 'dart:io';
main() {
print('1 + 1 = ...');
var line = stdin.readLineSync(encoding: Encoding.getByName('utf-8'));
print(line.trim() == '2' ? 'Yup!' : 'Nope :(');
}
The following should be the most up to date dart code to read input from stdin.
import 'dart:async';
import 'dart:io';
import 'dart:convert';
void main() {
readLine().listen(processLine);
}
Stream<String> readLine() => stdin
.transform(utf8.decoder)
.transform(const LineSplitter());
void processLine(String line) {
print(line);
}
import 'dart:io';
void main(){
stdout.write("Enter your name : ");
var name = stdin.readLineSync();
stdout.write(name);
}
Output
Enter your name : Jay
Jay
By default readLineSync() takes input as string. But If you want integer input then you have to use parse() or tryparse().
With M3 dart classes like StringInputStream are replaced with Stream, try this:
import 'dart:io';
import 'dart:async';
void main() {
print("Please, enter a line \n");
Stream cmdLine = stdin
.transform(new StringDecoder())
.transform(new LineTransformer());
StreamSubscription cmdSubscription = cmdLine.listen(
(line) => print('Entered line: $line '),
onDone: () => print(' finished'),
onError: (e) => /* Error on input. */);
}
As of Dart 2.12, null-safety is enabled, and stdin.readLineSync() now returns a String? instead of a String.
This apparently has been confusing a lot of people. I highly recommend reading https://dart.dev/null-safety/understanding-null-safety to understand what null-safety means.
For stdin.readLineSync() specifically, you can resolve this by checking for null first, which for local variables will automatically promote a String? to a String. Here are some examples:
// Read a line and try to parse it as an integer.
String? line = stdin.readLineSync();
if (line != null) {
int? num = int.tryParse(line); // No more error about `String?`.
if (num != null) {
// Do something with `num`...
}
}
// Read lines from `stdin` until EOF is reached, storing them in a `List<String>`.
var lines = <String>[];
while (true) {
var line = stdin.readLineSync();
if (line == null) {
break;
}
lines.add(line); // No more error about `String?`.
}
// Read a line. If EOF is reached, treat it as an empty string.
String line = stdin.readLineSync() ?? '';
Note that you should not blindly do stdin.readLineSync()!. readLineSync returns a String? for a reason: it returns null when there is no more input. Using the null assertion operator (!) is asking for a runtime exception.
Note that while calling stdin.readLineSync() your isolate/thread will be blocked, no other Future will be completed.
If you want to read a stdin String line asynchronously, avoiding isolate/thread block, this is the way:
import 'dart:async';
import 'dart:convert';
import 'dart:io';
/// [stdin] as a broadcast [Stream] of lines.
Stream<String> _stdinLineStreamBroadcaster = stdin
.transform(utf8.decoder)
.transform(const LineSplitter()).asBroadcastStream() ;
/// Reads a single line from [stdin] asynchronously.
Future<String> _readStdinLine() async {
var lineCompleter = Completer<String>();
var listener = _stdinLineStreamBroadcaster.listen((line) {
if (!lineCompleter.isCompleted) {
lineCompleter.complete(line);
}
});
return lineCompleter.future.then((line) {
listener.cancel();
return line ;
});
}
All these async API readLine*() based solutions miss the syntactic sugar which gives you the ability to do everything without synchronous blocking, but written like synchronous code. This is even more intuitive coming from other languages where you write code to execute synchronously:
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
var lines = stdin.transform(utf8.decoder).transform(const LineSplitter());
await for (final l in lines) {
print(l);
}
print("done");
}
The key takeaway here is to make use of async and await:
async on your method is required, as you're using await to interface with asynchronous API calls
await for is the syntax for doing "synchronous-like" code on a Stream (the corresponding syntax for a Future is just await).
Think of await like "unwrapping" a Stream/Future for you by making the following code execute once something is available to be handled. Now you're no longer blocking your main thread (Isolate) to do the work.
For more information, see the Dart codelab on async/await.
(Sidenote: The correct way to declare any return value for an async function is to wrap it in a Future, hence Future<void> here.)
You can use the following line to read a string from the user:
String str = stdin.readLineSync();
OR the following line to read a number
int n = int.parse(stdin.readLineSync());
Consider the following example:
import 'dart:io'; // we need this to use stdin
void main()
{
// reading the user name
print("Enter your name, please: ");
String name = stdin.readLineSync();
// reading the user age
print("Enter your age, please: ");
int age = int.parse(stdin.readLineSync());
// Printing the data
print("Hello, $name!, Your age is: $age");
/* OR print in this way
* stdout.write("Hello, $name!, Your age is: $age");
* */
}
You could of course just use the dcli package and it's ask function
Import 'package: dcli/dcli.dart':
Var answer = ask('enter your name');
print (name);
Use the named validator argument to restrict input to integers.
To read from the console or terminal in Dart, you need to:
import 'dart:io' library
store the entered value using stdin.readLineSync()!
parse the input into an int using int.parse(input) if necessary
Code:
import 'dart:io';
void main() {
String? string;
var number;
stdout.writeln("Enter a String: ");
string = stdin.readLineSync()!;
stdout.writeln("Enter a number: ");
number = int.parse(stdin.readLineSync()!);
}