How do I extend a List in Dart? - dart

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)

Related

Dart abstract static method

I want to create an abstract Sort class for my class project using dart which I will extend with Sorting algorithm classes like MergeSort, QuickSort, Heap, etc. I wrote the below code but I cannot create an abstract static sort method which I can override and use like
Heap.sort(arr)
OR
MergeSort.sort(arr)
Do anyone know why I cannot create abstract static method and also if you have any other way of doing this please feel free to guide me :D
abstract class Sort {
// void sort(List array);
static void sort(List array);
bool isSorted(List array) {
for (int i = 0; array.length > i - 1; i++) {
if (array[i] > array[i + 1]) {
return false;
}
}
return true;
}
void swap(arr, i, j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
As the answer linked above says, you can't have abstract static methods.
An abstract method does just one thing, it adds a method signature to the interface of the class, which other (non-abstract) classes implementing the interface then has to provide an implementation for. The abstract method doesn't add implementation.
Static methods are not part of the interface, so being abstract and static means it has no effect at all. It's a method with no implementation, which nobody can ever implement. So you're not allowed to do that.
To actually have separate classes representing different sorting algorithms, just do that directly using instance methods. That's the strategy object pattern.
abstract class Sorter<T> {
void sort(List<T> values);
int compare(T value1, T value2);
void swap(List<T> values, int index1, int index2) {
T tmp = values[index1];
values[index1] = values[index2];
values[index2] = tmp;
}
}
abstract class HeapSort<T> extends Sorter<T> {
void sort(List<T> values) {
// heap sort algorithm.
}
}
abstract class MergeSort<T> extends Sorter<T> {
void sort(List<T> values) {
// merge sort algorithm.
}
}
mixin ComparableSorter<T extends Comparable<T>> on Sorter<T> {
int compare(T value1, T value2) => value1.compareTo(value2);
}
class ComparableHeapSort<T extends Comparable<T>>
extends HeapSort<T> with ComparableSorter<T> {}
class CustomCompareHeapSort<T> extends HeapSort<T> {
int Function(T, T) _compare;
CustomCompareHeapSort(int Function(T, T) compare) : _compare = compare;
int compare(T value1, T value2) => _compare(value1, value2);
}
There are plenty of options about how to slice the API and abstract over different parts of it.
I recommend figuring out what use-cases you want to support, before starting the API design.

What's the equivalent to this[x] in Dart?

For instance, in Javascript I can do something like:
class Foo {
x = 'baz';
bar() {
const someVar = 'x';
console.log(this[someVar]);
// Output: 'baz';
}
}
Hopefully that's relatively clear - it boils down to accessing a member variable by another variable's contents. How is this achieved in Dart?
This is not trivial in Dart. Dart doesn't have a syntax to access class properties with [].
There are a couple of approaches though:
Mirrors:
https://api.dartlang.org/stable/2.6.1/dart-mirrors/dart-mirrors-library.html
Basically you have access to everything and offers the biggest freedom. You can check what properties a class has, access them via names and so on. Big disadvantage is that the generated JS (if targeting web) will be huge. Flutter doesn't support it at all.
Reflectable
To deal with the large generated JS, you can use package:reflectable. Never tried it with Flutter. It's a bit more to set up and start using bit it works.
Dart only solution 1
You can overload [] operator on a class:
class Foo {
final _backing = <String, String>{
'foo': 'bar'
};
operator [](String val) {
return _backing[val];
}
}
void main() {
final inst = Foo();
print(inst['foo']);
}
Dart only solution 2
Just use a map :) Well sort of... If you are dealing with complex types and you want to add some extra functionality to your map, you can do something like this:
import 'dart:collection';
class StringMap extends Object with MapMixin<String, String> {
final _backing = <String, String>{};
#override
String operator [](Object key) {
return _backing[key];
}
#override
void operator []=(String key, String value) {
_backing[key] = value;
}
#override
void clear() {
_backing.clear();
}
#override
Iterable<String> get keys => _backing.keys;
#override
String remove(Object key) {
return _backing.remove(key);
}
}

Limit a generic type argument only to be a int, double or custom class

I trying make the following code but T only can be int, double or a custom class. I couldn't find how to restrict the type in Dart or something that work like where from C#. How can I do that in Dart?
class Array3dG<T> extends ListBase<T> {
List<T> l = List<T>();
Array3dG(List<T> list) {
l = list;
}
set length(int newLength) { l.length = newLength; }
int get length => l.length;
T operator [](int index) => l[index];
void operator []=(int index, T value) { l[index] = value; }
}
There is no way to constrain the type variable at compile-time. You can only have one bound on a type variable, and the only bound satisfying both int and your custom class is Object.
As suggested by #Mattia, you can check at run-time and throw in the constructor if the type parameter is not one of the ones you supprt:
Array3dG(this.list) {
if (this is! Array3dG<int> &&
this is! Array3dG<double> &&
this is! Array3dG<MyClass>) {
throw ArgumentError('Unsupported element type $T');
}
}
This prevents creating an instance of something wrong, but doesn't catch it at compile-time.
Another option is to have factory methods instead of constructors:
class Array3dG<T> {
List<T> list;
Array3dG._(this.list);
static Array3dG<int> fromInt(List<int> list) => Array3dG<int>._(list);
static Array3dG<int> fromDouble(List<double> list) => Array3dG<double>._(list);
static Array3dG<MyClass> fromMyClass(List<MyClass> list) => Array3dG<MyClass>._(list);
...
}
which you then use as Array3dG.fromInt(listOfInt). It looks like a named constructor, but it is just a static factory method (so no using new in front).
You can check at runtime the type with the is keyword:
Array3dG(List<T> list) {
if (list is List<int>) {
//Handle int
}
else if (list is List<double>) {
//Handle double
}
else if (list is List<MyClass>) {
//Handle MyClass
}
else {
throw ArgumentError('Unsupported $T type');
}
}
Note that if you are handling int and double in the same way you can just check for num
You can check the progress of the Union types here: https://github.com/dart-lang/sdk/issues/4938

Error in Iteration example in A Tour of the Dart Libraries

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

Extending the List<T> class [duplicate]

This question already has answers here:
How do I extend a List in Dart?
(6 answers)
Closed 8 years ago.
Is it possible to extend a generic list with my my own specific list. Something like:
class Tweets<Tweet> extends List<T>
And how would a constructor look like, if I wanted to construct with my own constructor:
Datasource datasource = new Datasource('http://search.twitter.com/search.json');
Tweets tweets = new Tweets<Tweet>(datasource);
And how to call the parent constructor then, as this is not done in a extended class?
This is what i found out to extend list behavior:
import 'dart:collection';
extends ListBase
implement [] and length getter and setter.
See adapted Tweet example bellow. It uses custom Tweets method and standard list method.
Note that add/addAll has been removed.
Output:
[hello, world, hello]
[hello, hello]
[hello, hello]
Code:
import 'dart:collection';
class Tweet {
String message;
Tweet(this.message);
String toString() => message;
}
class Tweets<Tweet> extends ListBase<Tweet> {
List<Tweet> _list;
Tweets() : _list = new List();
void set length(int l) {
this._list.length=l;
}
int get length => _list.length;
Tweet operator [](int index) => _list[index];
void operator []=(int index, Tweet value) {
_list[index]=value;
}
Iterable<Tweet> myFilter(text) => _list.where( (Tweet e) => e.message.contains(text));
}
main() {
var t = new Tweet('hello');
var t2 = new Tweet('world');
var tl = new Tweets();
tl.addAll([t, t2]);
tl.add(t);
print(tl);
print(tl.myFilter('hello').toList());
print(tl.where( (Tweet e) => e.message.contains('hello')).toList());
}
Dart's List is an abstract class with factories.
I think you could implement it like this:
class Tweet {
String message;
Tweet(this.message);
}
class Tweets<Tweet> implements List<Tweet> {
List<Tweet> _list;
Tweets() : _list = new List<Tweet>();
add(Tweet t) => _list.add(t);
addAll(Collection<Tweet> tweets) => _list.addAll(tweets);
String toString() => _list.toString();
}
main() {
var t = new Tweet('hey');
var t2 = new Tweet('hey');
var tl = new Tweets();
tl.addAll([t, t2]);
print(tl);
}
There doesn't seem to be any direct way to do this and looks like there's also a bug ticket: http://code.google.com/p/dart/issues/detail?id=2600
Update: One way is to use noSuchMethod() and forward calls.

Resources