Skip to content

Instantly share code, notes, and snippets.

@lrhn
Last active April 11, 2019 10:39
Show Gist options
  • Save lrhn/214bb4e86d5c3621b8df5fb42046e31a to your computer and use it in GitHub Desktop.
Save lrhn/214bb4e86d5c3621b8df5fb42046e31a to your computer and use it in GitHub Desktop.
Example of Extension Method Resolution
// C# has invariant generics, so only `b.Copy()` matches the `Bar.Copy` method.
// It's unsurprising that the other two use Foo.
// For the conflict, C# prefers the non-generic function over the generic one.
// That's also true for normal static class.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<A> a = new List<A>() { new A() };
List<B> b = new List<B>() { new B() };
List<C> c = new List<C>() { new C() };
a.Copy(false); // Gen
b.Copy(false); // Spc
c.Copy(false); // Gen
Test(a); // TestGen
Test(b); // TestSpc
Test(c); // TestGen
}
static List<T> Test<T>(List<T> self) {
Console.WriteLine("TestGen");
return self;
}
static List<B> Test(List<B> self) {
Console.WriteLine("TestSpc");
return self;
}
}
static class Foo {
public static List<T> Copy<T>(this List<T> self, bool reversed) {
Console.WriteLine("Gen");
List<T> result = new List<T>();
foreach (var v in self) {
if (reversed) {
result.Insert(0, v);
} else {
result.Add(v);
}
}
return result;
}
}
static class Bar {
public static List<B> Copy(this List<B> self, bool reversed) {
Console.WriteLine("Spc");
List<B> result = new List<B>();
foreach (var v in self) {
if (reversed) {
result.Insert(0, v);
} else {
result.Add(v);
}
}
return result;
}
}
class A {}
class B : A {}
class C : B {}
// Prefers specific type over generic where both apply.
// Same resolution as fo static method overloading.
fun main() {
var a : List<A> = listOf<A>(A());
var b : List<B> = listOf<B>(B());
var c : List<C> = listOf<C>(C());
a.copy().isGen(); // Gen
b.copy().isSpc(); // Spc
c.copy().isSpc(); // Spc
test(a).isGen(); // TestGen
test(b).isSpc(); // TestSpc
test(c).isSpc(); // TestSpc
}
fun <T> test(x: List<T> ) : Gen {
println("TestGen");
return Gen();
}
fun test(x: List<B>) : Spc {
println("TestSpc");
return Spc();
}
// Cannot have same return type as List<T>.copy, after erasure, they have same signature.
fun List<B>.copy() : Spc {
println("Spc");
return Spc();
}
fun <T> List<T>.copy() : Gen {
println("Gen");
return Gen();
}
class Spc {
fun isSpc() {}
}
class Gen {
fun isGen() {}
}
open class A() {}
open class B() : A() {}
open class C() : B() {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment