Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Covariance in different FW causes Code Break?

I saw Jon Skeet's lecture at the NDC 2010

He mentioned something interesting :

public Class Base
{
 public void Foo(IEnumerable<string> strings){}
}

public Class Child:Base
{
 publc void Foo(IEnumerable<object> objects) {}
}

Main :

List<string> lst = new List<string>();
lst.Add("aaa");
Child c = new Child();
c.Foo(lst);

With C# 3 it will call : Base.Foo

With C# 4 it will call : Child.Foo

I know it's because covariance

Question :

Isn't it a bit code breaking change ? Is there any workaround so this code will continue work as it was on ver 3?

like image 763
Royi Namir Avatar asked Dec 17 '22 03:12

Royi Namir


2 Answers

Yes, it's a breaking change. Any time you make a prevously-invalid conversion legal, it's a breaking change.

Unfortunately, it's very hard to add features to the language without making any breaking changes. There are a few more around events in C# 4 if you really want to look for them. It's unlikely that these will affect most developers, of course.

There were similar breaking changes between C# 1 and C# 2, where the implementation used would have changed between different versions for this code:

using System;

public delegate void StringAction(string x);

public class Base
{
    public void Foo(string x)
    {
        Console.WriteLine("Base");
    }
}

public class Child : Base
{
    public void Foo(object x)
    {
        Console.WriteLine("Child");
    }
}

public class Test
{
    static void Main()
    {
        Child c = new Child();
        StringAction action = new StringAction(c.Foo);
        action("x");
    }
}

In this case the compiler actually gives a warning:

Test.cs(26,31): warning CS1707: Delegate 'StringAction' bound to
        'Child.Foo(object)' instead of 'Base.Foo(string)' because of new
        language rules
like image 90
Jon Skeet Avatar answered Dec 18 '22 18:12

Jon Skeet


Jon is of course right; it is a breaking change. An even easier way to see that breaking change is:

object x = new List<string>();
if (x is IEnumerable<object>) 
    Console.WriteLine(4);
else
    Console.WriteLine(3);

In C# 3 that prints 3; in C# 4 it prints 4.

When you change the type system, you change the results of overload resolution; that's just how it goes. The benefit of the feature outweighs the pain of the possible breaks.

Is there a workaround? Yes. Don't call Child.Foo in the first place:

Base c = new Child();
c.Foo(list);
like image 41
Eric Lippert Avatar answered Dec 18 '22 16:12

Eric Lippert