Problem
How can I implement the example of Iteration in A Tour of the Dart Libraries?
I understood that it is a code that must be supplemented, but how do I supplement it?
A Tour of the Dart Libraries
class Process {
// Represents a process...
}
class ProcessIterator implements Iterator<Process> {
#override
Process get current => ...
#override
bool moveNext() => ...
}
// A mythical class that lets you iterate through all
// processes. Extends a subclass of [Iterable].
class Processes extends IterableBase<Process> {
#override
final Iterator<Process> iterator = ProcessIterator();
}
void main() {
// Iterable objects can be used with for-in.
for (var process in Processes()) {
// Do something with the process.
}
}
Development Environment
Dart 2
DartPad
Tried → Error
I read and executed the document on my own, but the following error occurred.
class ProcessIterator implements Iterator<Process> {
#override
Process get current => new Process();
#override
bool moveNext() => false;
}
-> Error: 'IterableBase' expects 0 type arguments.
Best regards,
Two things.
1) Process is not available on the web, so your DartPad example won't work.
2) IterableBase is in dart:collection. Don't forget to import that.
This code seems to work for me:
import 'dart:collection';
class ProcessIterator implements Iterator<int> {
#override
int get current => 0;
#override
bool moveNext() => false;
}
// A mythical class that lets you iterate through all
// processes. Extends a subclass of [Iterable].
class Processes extends IterableBase<int> {
#override
final Iterator<int> iterator = ProcessIterator();
}
main() {
for (var thing in Processes()) {
print(thing);
}
}
Keep in mind, it's often MUCH easier to use sync* for custom iterators.
Iterable<int> _myProcesses() sync* {
yield 1;
yield 2;
yield 3;
}
main() {
for (var thing in _myProcesses()) {
print(thing);
}
}
Refer to #Kevin 's answer and rewrite the code below.
Code
import 'dart:collection';
class Process {
var foo = 'foo';
}
class ProcessIterator implements Iterator<Process> {
int i = 0;
#override
Process get current => new Process();
#override
bool moveNext() {
if(i++ < 5) {
return true;
} else {
return false;
}
}
}
// A mythical class that lets you iterate through all
// processes. Extends a subclass of [Iterable].
class Processes extends IterableBase<Process> {
#override
final Iterator<Process> iterator = ProcessIterator();
}
void main() {
// Iterable objects can be used with for-in.
for (var process in Processes()) {
print(process.foo);
}
}
Console
foo
foo
foo
foo
foo
Related
Is there way to overriding method in Dart like JAVA, for example:
public class A {
public void handleLoad() {
}
}
And when overriding:
A a = new A() {
#Override
public void handleLoad() {
// do some code
}
};
No, Dart does not have anonymous classes. You have to create a class that extends A and instantiate it.
No but it much less useful in Dart because you can just reassign function:
typedef void PrintMsg(msg);
class Printer {
PrintMsg foo = (m) => print(m);
}
main() {
Printer p = new Printer()
..foo('Hello') // Hello
..foo = ((String msg) => print(msg.toUpperCase()))
..foo('Hello'); //HELLO
}
However you will need some extra boilerplate to access instance.
Use type Function:
class A {
final Function h
A(this.h);
void handleLoad(String loadResult) { h(loadResult); }
}
Or
class A {
final Function handleLoad;
A(this.handleLoad);
}
A a = new A((String loadResult){
//do smth.
});
I was wondering if is possible to create an instance of a generic type in Dart. In other languages like Java you could work around this using reflection, but I'm not sure if this is possible in Dart.
I have this class:
class GenericController <T extends RequestHandler> {
void processRequest() {
T t = new T(); // ERROR
}
}
I tried mezonis approach with the Activator and it works. But it is an expensive approach as it uses mirrors, which requires you to use "mirrorsUsed" if you don't want to have a 2-4MB js file.
This morning I had the idea to use a generic typedef as generator and thus get rid of reflection:
You define a method type like this: (Add params if necessary)
typedef S ItemCreator<S>();
or even better:
typedef ItemCreator<S> = S Function();
Then in the class that needs to create the new instances:
class PagedListData<T>{
...
ItemCreator<T> creator;
PagedListData(ItemCreator<T> this.creator) {
}
void performMagic() {
T item = creator();
...
}
}
Then you can instantiate the PagedList like this:
PagedListData<UserListItem> users
= new PagedListData<UserListItem>(()=> new UserListItem());
You don't lose the advantage of using generic because at declaration time you need to provide the target class anyway, so defining the creator method doesn't hurt.
You can use similar code:
import "dart:mirrors";
void main() {
var controller = new GenericController<Foo>();
controller.processRequest();
}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T();
T t = Activator.createInstance(T);
t.tellAboutHimself();
}
}
class Foo extends RequestHandler {
void tellAboutHimself() {
print("Hello, I am 'Foo'");
}
}
abstract class RequestHandler {
void tellAboutHimself();
}
class Activator {
static createInstance(Type type, [Symbol constructor, List
arguments, Map<Symbol, dynamic> namedArguments]) {
if (type == null) {
throw new ArgumentError("type: $type");
}
if (constructor == null) {
constructor = const Symbol("");
}
if (arguments == null) {
arguments = const [];
}
var typeMirror = reflectType(type);
if (typeMirror is ClassMirror) {
return typeMirror.newInstance(constructor, arguments,
namedArguments).reflectee;
} else {
throw new ArgumentError("Cannot create the instance of the type '$type'.");
}
}
}
I don't know if this is still useful to anyone. But I have found an easy workaround. In the function you want to initialize the type T, pass an extra argument of type T Function(). This function should return an instance of T. Now whenever you want to create object of T, call the function.
class foo<T> {
void foo(T Function() creator) {
final t = creator();
// use t
}
}
P.S. inspired by Patrick's answer
2022 answer
Just came across this problem and found out that although instantiating using T() is still not possible, you can get the constructor of an object easier with SomeClass.new in dart>=2.15.
So what you could do is:
class MyClass<T> {
final T Function() creator;
MyClass(this.creator);
T getGenericInstance() {
return creator();
}
}
and when using it:
final myClass = MyClass<SomeOtherClass>(SomeOtherClass.new)
Nothing different but looks cleaner imo.
Here's my work around for this sad limitation
class RequestHandler {
static final _constructors = {
RequestHandler: () => RequestHandler(),
RequestHandler2: () => RequestHandler2(),
};
static RequestHandler create(Type type) {
return _constructors[type]();
}
}
class RequestHandler2 extends RequestHandler {}
class GenericController<T extends RequestHandler> {
void processRequest() {
//T t = new T(); // ERROR
T t = RequestHandler.create(T);
}
}
test() {
final controller = GenericController<RequestHandler2>();
controller.processRequest();
}
Sorry but as far as I know, a type parameter cannot be used to name a constructor in an instance creation expression in Dart.
Working with FLutter
typedef S ItemCreator<S>();
mixin SharedExtension<T> {
T getSPData(ItemCreator<T> creator) async {
return creator();
}
}
Abc a = sharedObj.getSPData(()=> Abc());
P.S. inspired by Patrick
simple like that.
import 'dart:mirrors';
void main(List<String> args) {
final a = A<B>();
final b1 = a.getInstance();
final b2 = a.getInstance();
print('${b1.value}|${b1.text}|${b1.hashCode}');
print('${b2.value}|${b2.text}|${b2.hashCode}');
}
class A<T extends B> {
static int count = 0;
T getInstance() {
return reflectClass(T).newInstance(
Symbol(''),
['Text ${++count}'],
{Symbol('value'): count},
).reflectee;
}
}
class B {
final int value;
final String text;
B(this.text, {required this.value});
}
Inspired by Patrick's answer, this is the factory I ended up with.
class ServiceFactory<T> {
static final Map<Type, dynamic> _cache = <String, dynamic>{};
static T getInstance<T>(T Function() creator) {
String typeName = T.toString();
return _cache.putIfAbsent(typeName, () => creator());
}
}
Then I would use it like this.
final authClient = ServiceFactory.getInstance<AuthenticationClient>(() => AuthenticationClient());
Warning: Erik made a very good point in the comment below that the same type name can exist in multiple packages and that will cause issues. As much as I dislike to force the user to pass in a string key (that way it's the consumer's responsibility to ensuring the uniqueness of the type name), that might be the only way.
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.
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;
}
I want to create a more specialized list in dart. I can't directly extend List. What are my options?
To make a class implement List there are several ways :
Extending ListBase and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends ListBase<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Mixin ListMixin and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends Base with ListMixin<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Delegating to an other List with DelegatingList from the quiver package:
import 'package:quiver/collection.dart';
class MyCustomList<E> extends DelegatingList<E> {
final List<E> _l = [];
List<E> get delegate => _l;
// your custom methods
}
Delegating to an other List with DelegatingList from the collection package:
import 'package:collection/wrappers.dart';
class MyCustomList<E> extends DelegatingList<E> {
final List<E> _l;
MyCustomList() : this._(<E>[]);
MyCustomList._(l) :
_l = l,
super(l);
// your custom methods
}
Depending on your code each of those options has their advantages. If you wrap/delegate an existing list you should use the last option. Otherwise, use one of the two first options depending on your type hierarchy (mixin allowing to extend another Object).
There is a ListBase class in dart:collection. If you extend this class, you only need to implement:
get length
set length
[]=
[]
Here is an example:
import 'dart:collection';
class FancyList<E> extends ListBase<E> {
List innerList = new List();
int get length => innerList.length;
void set length(int length) {
innerList.length = length;
}
void operator[]=(int index, E value) {
innerList[index] = value;
}
E operator [](int index) => innerList[index];
// Though not strictly necessary, for performance reasons
// you should implement add and addAll.
void add(E value) => innerList.add(value);
void addAll(Iterable<E> all) => innerList.addAll(all);
}
void main() {
var list = new FancyList();
list.addAll([1,2,3]);
print(list.length);
}
A new way of extending classes was introduced with Dart 2.6.
You can now create an extension of List like this:
extension MyCustomList<T> on List<T> {
// Any methods you want can be added here.
}
The methods you add can be used implicitly, i.e. you can just use them on any List when you have your extension imported.
Here is an example from the feature specification:
extension MyFancyList<T> on List<T> {
int get doubleLength => this.length * 2;
List<T> operator-() => this.reversed.toList();
List<List<T>> split(int at) =>
<List<T>>[this.sublist(0, at), this.sublist(at)];
List<T> mapToList<R>(R Function(T) convert) => this.map(convert).toList();
}
You can use these new members on any List, e.g. like this:
const list = <String>['some', 'elements'];
list.doubleLength; // Evaluates to 4.
The answers to this are pretty outdated, and I'm in the process of doing this for my own project, so I thought I'd help some people out by posting a really clean answer that doesn't involve any overriding or implementing of things.
The quiver package has an extendable List class called DelegatingList that makes extending a list trivial.
class FruitList extends DelegatingList<Fruit> {
final List<Fruit> _fruits = [];
List<Fruit> get delegate => _fruits;
// custom methods
}
Hopefully this helps someone who comes across this question like I did!
Following on from the answer above, you can create an immutable list like this:
class ImmutableList<E> extends ListBase<E> {
late final List<E> innerList;
ImmutableList(Iterable<E> items) {
innerList = List<E>.unmodifiable(items);
}
#override
int get length => innerList.length;
#override
set length(int length) {
innerList.length = length;
}
#override
void operator []=(int index, E value) {
innerList[index] = value;
}
#override
E operator [](int index) => innerList[index];
}
//list is your given List and iterable is any object in dart that can be iterated
list.addAll(Iterable)