-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lean Iterable<E> - allow iterating without support for 30 methods #43392
Comments
I'm not sure what justifies the should in that sentence. Users do use Iterable as a type in their APIs. If you have a method that accepts an Iterable, it's useful to be able to do lots of things with the object that you get, and the rich method set on Iterable enables that. An implementer of Iterable is not burdened with manually implementing all of those. They can simply mixin IterableMixin and they get that behavior for free after defining
Yes, this is generally a problem with interfaces in Dart and with classes in general. The lack of overloading and non-virtual methods makes basically every base class hard to change.
Sure, they could use them in
This would be nice, but I don't think we could reasonably do this in a non-breaking way. We don't have a time machine, and Iterable is what it is. (Many people on the Dart team did push for extension methods way back before Dart 1.0 specifically because it would have let us design the core libraries around them, but it didn't happen.) I'm not sure what's actionable about this request. Users frequently call the many methods on Iterable, so we can't just take them away. |
What would break if you implement all those methods as extension methods? |
This depends a lot on the specific details of extension methods, which I think aren't pinned down yet. But, in general, it would probably move where the methods appear in the resolution order. Today, you'd write something like: abstract class Iterable<E> {
bool get isEmpty;
Iterator<E> get iterator;
}
abstract class IterableBase<E> implements Iterable<E> {
bool get isEmpty => iterator.moveNext();
Iterator<E> get iterator;
}
/// Special "collection" that always contains a single value.
class BoxIterable<E> extends IterableBase {
final E _value;
bool get isEmpty => false; // Always contains one item.
Iterator<E> get iterator => [_value].iterator;
}
main() {
Iterable<int> iterable = BoxIterable(123);
iterable.isEmpty; // <--
} On the last marked line, that's resolved like:
If you change abstract class Iterable<E> {
Iterator<E> get iterator;
}
extension IterableExtensions<E> on Iterable<E> {
bool get isEmpty => iterator.moveNext();
}
/// Special "collection" that always contains a single value.
class BoxIterable<E> implements Iterable {
final E _value;
bool get isEmpty => false; // Always contains one item.
Iterator<E> get iterator => [_value].iterator;
}
main() {
Iterable<int> iterable = BoxIterable(123);
iterable.isEmpty; // <--
} Now the resolution, I think, looks something like:
So now you're calling a different method at runtime. In the example here, aside from wasting a little time and memory, the difference doesn't matter. But in real code, it very well could. |
I agree with Bob that it's probably not feasible to change If we add static extension methods, with the semantics Bob was using (and which are the most likely ones to pick), then changing existing methods to extension methods will, as described, make them non-virtual. That is a significant change. Existing subclasses will keep compiling, but their specialized methods will no longer be called unless the static type at the invocation point is the subclass. |
We now have extension methods. |
Iterable<E>
defines 30 methods. That's too much because all anIterable
should do is to provide anIterator
. All other functions are only using theIterator
and are therefore not required to define anIterable
.Additionally,
Iterable
can't be extended with new convenience methods. Every additional method breaks 3rd party libraries implementingIterable<E>
.Goal
Without those 30 methods it would be much easier for 3rd party libraries like
kt.dart
or built_collection toimplement
Iterable<T>
allowing users to use custom collections infor
loops. It is currently not or hardly possible because of many naming clashes.Currently kt.dart users have to use the property
iter
to actually iterate over collections with for loops.Solution A: Extension methods
Converting all methods to extension methods dart-lang/language#40 would be a major step forward. It would cleanup the
Iterable
class and removes the need forIterableMixin
. This approach would also be future proof allowing method additions without requiring 3rd party libraries to adopt the new methods.The naming clashes most likely wouldn't go away. It depends on how extensions will be imported which got discussed in dart-lang/language#41.
Solution B:
For backwards compatability Dart could provide a new
class
BareIterable
which works infor
loops, likeIterable
today. All it does is providing theIterator
.The existing
Iterable
class could even extendBareIterable<E>
, keeping everything as it is.3rd party collection libraries are then able to implement
BareIterable<E>
without implementing 30 more methods.The text was updated successfully, but these errors were encountered: