StreamTransformer in Dart being skipped? - stream

I'm not sure if I'm not understanding this correctly, but here's my code. I'm trying to get the StreamTransformer to act on the stream, but the values still come out the other end untouched.
Note: I added the .map() function, which does nothing, just to make sure it wasn't a missing map function that was my issue. I'm leaving it here just in case.
import 'dart:async';
void main() {
int count = 0;
var counterController = new StreamController();
counterController.stream.listen((value) => print(value));
void increment() {
counterController.add(count++);
}
final transformToString =
new StreamTransformer.fromHandlers(handleData: (number, sink) {
if (number.runtimeType == int) {
sink.add("The counter is at $number!");
} else {
sink.addError("$number is not an int!");
}
});
counterController.stream.map((input) => input).transform(transformToString);
for(int i=0; i < 10; i++){
increment();
}
}
Link to the code in DartPad

As was mentioned by my instructor, the transform function creates out a new stream. So I have to attach a listener to the transformed stream, I can't expect transformed values to come out of the old stream. So the modified code below works.
import 'dart:async';
void main() {
...
counterController.stream.map((input) => input)
.transform(transformToString).listen(print);
for(int i=0; i < 10; i++){
increment();
}
}

Related

dart: access function from list

Edit: i know, always call the first element on list, it isnt the point. i want to call numbers[0] func. and it regenerate new int.actually codes are not same which mine, i have a custom class which based on functions with random int and i need to use list of my custom class , so if i use func in list it will be awesome, how can i make new numbers list each time. when app start list regenerated, but i want when i call the list, it will regenerated
i want to print new int for each print but it prints same int , i tried so many thing and i cant figure out
void main{
int ramdomint(){
final _random = new Random();
int _num = _random.nextInt(100);
return _num;
}
List<int> numbers=[ramdomint(),ramdomint(),ramdomint()];
void printNums(){
for(var i=0;i<3;i++){
List<int> newNumbers =new List.from(numbers); //what can i use for this?
print(newNumbers[0]); //edit:i dont want [i], iwant to use ewNumbers[0] for new int for each time
}
}
printNums();
// expected new int for each but same one
}
solution from a friend:
import 'dart:math';
int get ramdomint => Random().nextInt(100);
List<int> get numbers => [ramdomint, ramdomint, ramdomint];
void main() {
for (var i = 0; i < 3; i++) {
print(numbers[0]);
}
}
Do not nest functions. Move ramdomint and printNums outside main function.
Add an empty list of arguments to the main function.
printNums: pass list of numbers as an argument.
printNums: you don't need to copy the list to the newNumbers if you want only to display the content of the list.
printNums: the problem is, you access only first element of the list (with 0 index).
import 'dart:math';
void main() {
List<int> numbers = [ramdomint(), ramdomint(), ramdomint()];
printNums(numbers);
}
int ramdomint() => Random().nextInt(100);
void printNums(List<int> numbers) {
// Easier way:
for (int item in numbers) {
print(item);
}
// Your way:
for (int i = 0; i < numbers.length; i++) {
print(numbers[i]);
}
}
EDIT:
According to #jamesdlin's comment, you can extend list class to randomize unique values in the list:
import 'dart:math';
void main() {
var numbers = <int>[]..randomize();
printNums(numbers);
}
void printNums(List<int> numbers) {
// Easier way:
for (int item in numbers) {
print(item);
}
// Your way:
for (int i = 0; i < numbers.length; i++) {
print(numbers[i]);
}
}
extension on List<int> {
void randomize({
int length = 3,
int maxValue = 100,
}) {
final generator = Random();
for (var i = 0; i < length; i++) {
add(generator.nextInt(maxValue));
}
}
}
The Problem here is that you are creating a list from the numbers list and accessing only the first element.
So it always prints the first element.
import 'dart:math';
void main() {
int ramdomint(){
final _random = new Random();
int _num = _random.nextInt(100);
return _num;
}
List<int> numbers=[ramdomint(),ramdomint(),ramdomint()];
void printNums(){
for(var i=0;i<3;i++){
print(numbers[i]);
}
}
printNums();
}
Don't want newNumbers, because it is already in List.
and the usage of List.from() - Documentation
Hope that works!

Dart: Accessing function from list

I want to have a new random number every time to print it, but it prints the same on. I tried so many thing, but I can't figure out what's wrong. Help me, please!
import 'dart:math';
int next_int() { return new Random().nextInt(100); }
void main()
{
List<int> list = [next_int(), next_int(), next_int()];
// expected new int each time but got the same one
for (var i = 0; i < 3; i++)
{
List<int> cur_list = new List.from(list);
print(cur_list[0]);
}
}
This code will work as you expect:
import 'dart:math';
int next_int() { return new Random().nextInt(100); }
void main()
{
List<int> list = [next_int(), next_int(), next_int()];
// expected new int each time but got the same one
for (var i = 0; i < 3; i++)
{
List<int> cur_list = new List.from(list);
print(cur_list[i]); // <= Use the index value stored in "i" instead of 0
}
}

How do these function return values work in Dart?

the official Bloc documentation gives this code snippet:
Stream<int> countStream(int max) async* {
for (int i = 0; i < max; i++) {
yield i;
}
}
This looks very simple to me, until I realize that the function does not return anything (no returnstatement), but yields all the time (which is to me - coming from python - not the same as a return statement).
There's also this example, which is even more clear:
Future<int> sumStream(Stream<int> stream) async {
int sum = 0;
await for (int value in stream) {
sum += value;
}
return sum;
}
Here there's an int returned explicitly, but if I read this correctly the function definition should return a Future<int>type:
Future<int> sumStream(Stream<int> stream) async { //...
Now, how does this work? I'm a bit confused here.
Thanks in advance!
Axel.
For your first example, countStream is a Stream of integer designed with an async*. (take care of the star)
In this stream definition, Yield emit a new integer on the stream flow (of integer as said by stream < int > .
If you consume the stream, you will get 0,1,2,3,4,...,max-1
In the second snippet, read it as : sumStream is a Future that must return an int.
More generally, A Future < T > instance produces a value of type T.
sumStream will consume a stream (given in parameter) and as long as this stream has values, sum them and return the last sum when finished. Sum is an integer : it's ok with Future definition.
Using both, you can have :
> void main() async {
print(await sumStream(countStream(5)));
}
result : 10 (0+1+2+3+4)
As sumStream is a Future, main can wait for asynchronous execution: it declares its intention to use async function (async declaration), then it can use await to stop its own execution until sumStream returns.
Another way if you leave main without async is to add a .then clause to the Future:
void main() {
sumStream(countStream(5)).then((x)=>print(x));
print("after sumStream");
}
Result :
after sumStream
10
As you can see main pass over sumStream it has started but which is not finished and print("after sumStream") first.
Then the main finished, but Dart knows there is still async job running and it will wait until all is done, so we can see the result, but once Future sumStream is finished.
HTH
This looks very simple to me, until I realize that the function does not return anything (no return statement)
First of all, this function returns Stream<int> result value as specified in function declartion. This function often called as the generator function.
Stream<int> countStream(int max) async*
The function body code (generator) will generate the int values and yield these generated values to the initially returned Stream<int> stream.
The statement yield means in this case the following logic of work:
Add a value to Stream<int> controller and return to the next statement in the body of the function that follows that statement yield.
Something like this:
import 'dart:async';
Future<void> main() async {
await for (final i in countStream(5)) {
print(i);
}
}
Stream<int> countStream(int max) {
int i;
final _ctl$ = StreamController<int>();
void Function(int) _switchState$;
_switchState$ = (int _state$) {
while (true) {
switch (_state$) {
case 0:
// for (int i = 0;
i = 0;
_state$ = 1;
break;
case 1:
// i < max;
if (i < max) {
_state$ = 2;
} else {
return;
}
break;
case 2:
// yield i;
_ctl$.add(i);
Timer.run(() => _switchState$(3));
return;
case 3:
// i++
i++;
_state$ = 1;
break;
}
}
};
Timer.run(() => _switchState$(0));
return _ctl$.stream;
}
Result:
0
1
2
3
4

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 to implement Iterable<E> in dart?

I still havn't understood how to deal with Iterable/Iterator in Dart.
I think I have to give up and simply return Lists but that's not what I want since it will
lead bad performance in my case.
What I want is to understand how to implement my own Iterable/Iterator.
Why do both of these attempts fail?
library foo;
import 'dart:collection';
// Both attemps below raises the following error:
// ==============================================
//
// Closure call with mismatched arguments: function 'moveNext'
//
// NoSuchMethodError: incorrect number of arguments passed to method named 'moveNext'
// Receiver: Closure: (dynamic) => Iterator<int> from Function 'iterator':.
// Tried calling: moveNext()
main() {
Iterable<int> iterable1 = new OddsIterableDartStyle([1,2,4,6,7,8,9]);
for (int i in iterable1)
print("ODD: $i");
Iterable<int> iterable2 = new OddsIterableJavaStyle([1,2,4,6,7,8,9]);
for (int i in iterable2)
print("ODD: $i");
}
// ------------------------------------------
class OddsIterableDartStyle extends Object with IterableMixin<int> {
List<int> _ints;
OddsIterableDartStyle(this._ints);
Iterator<int> iterator() {
return new OddsIterator(this);
}
}
// ------------------------------------------
class OddsIterableJavaStyle implements Iterable<int> {
List<int> _ints;
OddsIterableJavaStyle(this._ints);
Iterator<int> iterator() {
return new OddsIterator(this);
}
}
// ------------------------------------------
class OddsIterator implements Iterator<int> { // Iterate over odd numbers
List<int> _ints;
int _index;
OddsIterator(this._ints) {
_index = -1;
}
bool moveNext() {
while (++_index < _ints.length) {
if (_ints[_index].isOdd)
return true;
}
return false;
}
int get current => (_index < 0) ? null : _ints[_index];
}
I see two immediate problems:
iterator is a getter. The code shouldn't read Iterator<int> iterator() { ... }, it should be Iterator<int> get iterator { ... } instead.
Your iterators are expecting the underlying integer lists, but you are passing in the wrapper. You probably want to construct your iterator like new OddsIterator(_ints), not like new OddsIterator(this).
Btw, Iterator is supposed to return null if you call current and you have already moved beyond the end.
class Count extends Iterable with Iterator {
Count([this.limit = 10]);
int limit;
int i = 0;
#override
int get current => i;
#override
bool moveNext() {
i++;
return i <= limit;
}
#override
Iterator get iterator => this;
}

Resources