Consider this two interfaces.
interface Iterator { }
interface Iterable {
Iterator GetIterator();
}
So every class that implements Iterator is effectively an Iterable. To establish this relation, one might think of default methods:
interface Iterable {
default Iterator GetIterator() {
return this; // ERROR
}
}
But this doesn't help because you can't say if the implementor is an Iterator. We might define the default method as generic constrained to an Iterator.
interface Iterable {
default<T> Iterator GetIterator() where T : Iterator {
return this;
}
}
But this design is somehow flawed (you might want more default generic implementations of the same method with different constraints) and limiting (you don't always have access to Iterable declaration).
So you decide to declare an extension method for every Iterator.
static class IteratorExtensions {
public Iterator GetIterator(this Iterator @this) {
return @this;
}
}
And now you didn't establish any relation to Iterable interface at all. You know that it does have a method named GetIterator (duck typing) but the compiler doesn't.
So, here's my solution: define an implementation for every type that is an Iterator.
implement Iterable for Iterator {
Iterator GetIterator() {
return this;
}
}
Q: OK, What if we have other constraints as well? A: then you might define it as a generic implementation,
implement<T> Iterable for T where T : Iterator {
Iterator GetIterator() {
return this;
}
}
This is basically Rust's syntax for implementations but as an alternative you might suggest,
extension Iterator : Iterable {
Iterator GetIterator() {
return this;
}
}
extension<T> T : Iterable where T : Iterator {
Iterator GetIterator() {
return this;
}
}
which is closer to Swift's extensions.
And how this would work? Via virtual extension methods (#258). The compiler generates a static class for extension methods on the target type (or on the constrained generic type).
// the former case
static class _CompilerGeneratedName_ {
public static Iterator GetIterator(this Iterator @this) {
return @this;
}
}
// the latter case
static class _CompilerGeneratedName_ {
public static Iterator GetIterator<T>(this T @this) where T : Iterator {
return @this;
}
}
Note that it is possible to add members without any interface in question, e.g.
extension C {
void ExtensionMethodForC() { }
}
extension<T> T /* where T */ {
void ExtensionMethodForGenericT() { }
}
It would be nice to be able to name the generated static class, then it's possible to refactor existing classes like Enumerable (using an analyzer, perhaps) in this manner without breaking existing code, otherwise, extension methods would be accessible via the target type itself, e.g. C.ExtensionMethodForC.
This can neatly cover the #7844 use case. Suppose we have two classes with no relation to each other.
class A { public void M() { } }
class B { public void M() { } }
interface IHasM { void M(); }
extension A : IHasM {
// can be omitted due to the trivial implementation
// void M() { this.M(); }
}
extension B : IHasM { }
As discussed in the aforementioned issue, this kind of duck typing can be inferred by the compiler but it cannot be done without a high risk of breaking existing code.
There’s an important restriction for implementations, either the interface or the type you’re implementing it for must be defined in the same assembly.
PS: (1) There are numerous open proposals regarding template/structural types, extension classes, etc, but none of them are directly related to #258 so I decided to open another one. (2) This is not about traits and zero-cost abstraction, but same syntax can be used for implementing traits for arbitrary types.
Consider this two interfaces.
So every class that implements
Iteratoris effectively anIterable. To establish this relation, one might think of default methods:But this doesn't help because you can't say if the implementor is an
Iterator. We might define the default method as generic constrained to anIterator.But this design is somehow flawed (you might want more default generic implementations of the same method with different constraints) and limiting (you don't always have access to
Iterabledeclaration).So you decide to declare an extension method for every
Iterator.And now you didn't establish any relation to
Iterableinterface at all. You know that it does have a method namedGetIterator(duck typing) but the compiler doesn't.So, here's my solution: define an implementation for every type that is an
Iterator.Q: OK, What if we have other constraints as well? A: then you might define it as a generic implementation,
This is basically Rust's syntax for implementations but as an alternative you might suggest,
which is closer to Swift's extensions.
And how this would work? Via virtual extension methods (#258). The compiler generates a static class for extension methods on the target type (or on the constrained generic type).
Note that it is possible to add members without any interface in question, e.g.
It would be nice to be able to name the generated static class, then it's possible to refactor existing classes like
Enumerable(using an analyzer, perhaps) in this manner without breaking existing code, otherwise, extension methods would be accessible via the target type itself, e.g.C.ExtensionMethodForC.This can neatly cover the #7844 use case. Suppose we have two classes with no relation to each other.
As discussed in the aforementioned issue, this kind of duck typing can be inferred by the compiler but it cannot be done without a high risk of breaking existing code.
There’s an important restriction for implementations, either the interface or the type you’re implementing it for must be defined in the same assembly.
PS: (1) There are numerous open proposals regarding template/structural types, extension classes, etc, but none of them are directly related to #258 so I decided to open another one. (2) This is not about traits and zero-cost abstraction, but same syntax can be used for implementing traits for arbitrary types.