dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.08k stars 1.56k forks source link

List swap method #22306

Open azenla opened 9 years ago

azenla commented 9 years ago

I would like to propose a 'swap' method on List, which would have the following functionality:

void swap(int x, int y) {   var tmp = this[x];   this[x] = this[y];   this[y] = tmp; }

Of course there would probably be some range checks, but this would greatly enhance the List class for me, and I'm sure others.

sethladd commented 9 years ago

Added Area-Library, Triaged labels.

andrey-zakharov commented 8 years ago

Especially this will be useful with ObservableList, to get only one change record, with added and removed fields simultaneously.

vogella commented 4 years ago

+1, would be nice to have this method in the core SDK.

andredsnogueira commented 4 years ago

+1

nishiths23 commented 4 years ago

+1

lrhn commented 4 years ago

We have no current plans to change the List API. It's a very central API, and adding a method to it will break all classes currently implementing List. The benefit has to be very great for us to do that (no matter how convenient such a method would be).

jodinathan commented 4 years ago

We have no current plans to change the List API. It's a very central API, and adding a method to it will break all classes currently implementing List. The benefit has to be very great for us to do that (no matter how convenient such a method would be).

can it be done with extensions so it don't break implementations? I know there may be a package that does this, but I have the feeling that this kind of stuff should be in the core

lrhn commented 4 years ago

You can definitely write an extension, but then ObservableList won't be able to intercept the operation (as suggested above) unless the target is statically typed as ObservableList.

(Again, interface default methods would allow us to add members to an interface without (necessarily) breaking classes implementing the interface. We can break classes which already uses the same name, but that's still less than breaking all classes implementing an interface. Until we get interface default methods, I don't see a big urge to add swap in the platform libraries, because anyone can add it just as efficiently).

extension ListSwap<T> on List<T> {
  void swap(int index1, int index2) {
    var length = this.length;
    RangeError.checkValidIndex(index1, this, "index1", length);
    RangeError.checkValidIndex(index2, this, "index2", length);
    if (index1 != index2) {
      var tmp1 = this[index1];
      this[index1] = this[index2];
      this[index2] = tmp1;
    }
  }
}
fabiancrx commented 1 year ago

Are "interface default methods" being considered or tracked in any issue?

eernstg commented 1 year ago

https://github.com/dart-lang/language/issues/884 outlines a proposal for interface default methods. There's a different proposal with similar properties in https://github.com/dart-lang/language/issues/2510: class extension members.

Interface default members are real instance members, which means that if a class C has an implementation of a member m because there's a (direct or indirect) superinterface S of C that declares an interface default member named m, then a subclass class D extends C can declare its own implementation of m, and that implementation will override C.m just like regular instance members.

Class extension members are more like extension members. This means that they are resolved statically, and there's no way you could write a declaration which will dynamically override the statically known declaration for any given call site.

The other side of that coin is that interface default member conflicts are more difficult to handle: If C has superinterfaces S1 and S2, and both of them provide an interface default member named m (and C doesn't have an implementation of m), then there must be some mechanism to decide which one of those two implementations is copied down into C (if any). Moreover, if those two variants of m have incompatible signatures (say, S1.m is a getter and S2.m is a method) then it's not obvious that there is a solution at all (e.g., what should (myC as dynamic).m do, should it invoke the getter or tear off the method?). With a class extension member you can just declare whatever kind of member you want in C, because every call site will invoke the statically known declaration: When the static type is S1 it will call S1.m, when it's S2 then it will call S2.m, and when it's C it will call C.m. They can have completely unrelated signatures, because there is never a dynamic dispatch step where we don't know which one we're calling.

lrhn commented 1 year ago

Conflicts between interface default methods are like conflicts between any other interface methods, if a subclass can't define a member signature that satisfies both, it cannot implement both interfaces. On top of that, a conflict may also prevent automatic introduction of the default implementation.

Interface default methods exist to solve the software engineering problem of adding members to interfaces that are already implemented by third-party classes, without those classes suddenly not satisfying the interface. It's just about providing a default implementation of new members, it can't solve API conflicts. (Traits, on the other hand, might be able to.)