How to hint to C# that an implicit conversion exists? - c#

I have a sequence of classes and interfaces as follows:
interface IA
{ }
class A : IA
{
public static implicit operator A(int v) => new A(v);
public A(int v)
{ ... }
}
class B
{
public static void Foo(IA a)
{ ... }
}
And I want to be able to call B.Foo(int).
B.Foo(1) does not compile, but B.Foo((A)1) does. I am able to call B.Foo(1) if the method signature is instead Foo(A a), as C# is able to figure out the chain of implicit casting, so I know that I can modify the code in the following way:
class B
{
public static void Foo(A a) => Foo((IA)a)
public static void Foo(IA a)
{ ... }
}
However, this seems like a waste of code and time as I would have to do this for every method which accepts IA. It would become even more inefficient if a method such as Bar(IA p1, IA p2, ...) exists, as I would need n! copies of the signature with all of the different permutations of A and IA.
What is the best way to hint to C# that any method which accepts IA can also accept int?

For a call like B.Foo(1), the compiler would have to search through every type that implements IA to find a type T such that there is an implicit conversion from int to T and then perform the following conversion,
int -> T -> IA
The "finding T" step could be a lot of work, so the compiler is designed to not do it.
You seem to want to find a way to tell it that there is one specific implementation of IA, namely A, that does have have an implicit conversion from int. Well, you have actually already said it in the question:
B.Foo((A)1)
This tells the compiler to convert the int to an A first. Notice how this is as if you have found the type T, doing the hard work for the compiler.

Related

Difference between C# interface and Haskell Type Class

I know that there is a similar question here, but I would like to see an example, which clearly shows, what you can not do with interface and can with Type Class
For comparison I'll give you an example code:
class Eq a where
(==) :: a -> a -> Bool
instance Eq Integer where
x == y = x `integerEq` y
C# code:
interface Eq<T> { bool Equal(T elem); }
public class Integer : Eq<int>
{
public bool Equal(int elem)
{
return _elem == elem;
}
}
Correct my example, if not correctly understood
Typeclasses are resolved based on a type, while interface dispatch happens against an explicit receiver object. Type class arguments are implicitly provided to a function while objects in C# are provided explicitly. As an example, you could write the following Haskell function which uses the Read class:
readLine :: Read a => IO a
readLine = fmap read getLine
which you can then use as:
readLine :: IO Int
readLine :: IO Bool
and have the appropriate read instance provided by the compiler.
You could try to emulate the Read class in C# with an interface e.g.
public interface Read<T>
{
T Read(string s);
}
but then the implementation of ReadLine would need a parameter for the Read<T> 'instance' you want:
public static T ReadLine<T>(Read<T> r)
{
return r.Read(Console.ReadLine());
}
The Eq typeclass requires both arguments have the same type, whereas your Eq interface does not since the first argument is implicitly the type of the receiver. You could for example have:
public class String : Eq<int>
{
public bool Equal(int e) { return false; }
}
which you cannot represent using Eq. Interfaces hide the type of the receiver and hence the type of one of the arguments, which can cause problems. Imagine you have a typeclass and interface for an immutable heap datastructure:
class Heap h where
merge :: Ord a => h a -> h a -> h a
public interface Heap<T>
{
Heap<T> Merge(Heap<T> other);
}
Merging two binary heaps can be done in O(n) while merging two binomial heaps is possible in O(n log n) and for fibonacci heaps it's O(1). Implementors of the Heap interface do not know the real type of the other heap so is forced to either use a sub-optimal algorithm or use dynamic type checks to discover it. In contrast, types implementing the Heap typeclass do know the representation.
A C# interface defines a set of methods that must be implemented. A Haskell type class defines a set of methods that must be implemented (and possibly a set of default implementations for some of the methods). So there's a lot of similarities there.
(I guess an important difference is that in C#, an interface is a type, whereas Haskell regards types and type classes as strictly separate things.)
The key difference is that in C#, when you define a type (i.e., write a class), you define exactly what interfaces it implements, and this is frozen for all time. In Haskell, you can add new interfaces to an existing type at any time.
For example, if I write a new SerializeToXml interface in C#, I cannot then make double or String implement that interface. But in Haskell, I can define my new SerializeToXml type class, and then make all the standard, built-in types implement that interface (Bool, Double, Int...)
The other thing is how polymorphism works in Haskell. In an OO language, you dispatch on the type of the method the object is being invoked on. In Haskell, the type that the method is implemented for can appear anywhere in the type signature. Most particularly, read dispatches on the return type you want — something you usually can't do at all in OO languages, not even with function overloading.
Also, in C# it's kind of hard to say "these two arguments must have the same type". Then again, OO is predicated on the Liskov substitution principal; two classes that both descend from Customer should be interchangeable, so why would you want to constrain two Customer objects to both be the same type of customer?
Come to think of it, OO languages do method lookup at run-time, whereas Haskell does method lookup at compile-time. This isn't immediately obvious, but Haskell polymorphism actually works more like C++ templates than usual OO polymorphism. (But that's not especially to do with type classes, it's just how Haskell does polymorphism as such.)
Others have already provided excellent answers.
I only want to add a practical example about their differences. Suppose we want to model a "vector space" typeclass/interface, which contains the common operations of 2D, 3D, etc. vectors.
In Haskell:
class Vector a where
scale :: a -> Double -> a
add :: a -> a -> a
data Vec2D = V2 Double Double
instance Vector (Vec2D) where
scale s (V2 x y) = V2 (s*x) (s*y)
add (V2 x1 y1) (V2 x2 y2) = V2 (x1+x2) (y2+y2)
-- the same for Vec3D
In C#, we might try the following wrong approach (I hope I get the syntax right)
interface IVector {
IVector scale(double s);
IVector add(IVector v);
}
class Vec2D : IVector {
double x,y;
// constructor omitted
IVector scale(double s) {
return new Vec2D(s*x, s*y);
}
IVector add(IVector v) {
return new Vec2D(x+v.x, y+v.y);
}
}
We have two issues here.
First, scale returns only an IVector, a supertype of the actual Vec2D. This is bad, because scaling does not preserve the type information.
Second, add is ill-typed! We can't use v.x since v is an arbitrary IVector which might not have the x field.
Indeed, the interface itself is wrong: the add method promises that any vector must be summable with any other vector, so we must be able to sum 2D and 3D vectors, which is nonsense.
The usual solution is to switch to F-bounded quantification AKA CRTP or whatever it's being called these days:
interface IVector<T> {
T scale(double s);
T add(T v);
}
class Vec2D : IVector<Vec2D> {
double x,y;
// constructor omitted
Vec2D scale(double s) {
return new Vec2D(s*x, s*y);
}
Vec2D add(Vec2D v) {
return new Vec2D(x+v.x, y+v.y);
}
}
The first time a programmer meets this, they are usually puzzled by the seemingly "recursive" line Vec2D : IVector<Vec2D>. I surely was :) Then we get used to this and accept it as an idiomatic solution.
Type classes arguably have a nicer solution here.
After a long study of this issue, I came to an easy method of explaining. At least for me it's clear.
Imagine we have method with signature like this
public static T[] Sort(T[] array, IComparator<T> comparator)
{
...
}
And implementation of IComparator:
public class IntegerComparator : IComparator<int> { }
Then we can write code like this:
var sortedIntegers = Sort(integers, new IntegerComparator());
We can improve this code, first we create Dictionary<Type, IComparator> and fill it:
var comparators = new Dictionary<Type, IComparator>()
{
[typeof(int)] = new IntegerComparator(),
[typeof(string)] = new StringComparator()
}
Redesigned IComparator interface so that we could write like above
public interface IComparator {}
public interface IComparator<T> : IComparator {}
And after this let's redesign Sort method signature
public class SortController
{
public T[] Sort(T[] array, [Injectable]IComparator<T> comparator = null)
{
...
}
}
As you understand we are going to inject IComparator<T>, and write code like this:
new SortController().Sort<int>(integers, (IComparator<int>)_somparators[typeof(int)])
As you already guessed this code will not work for other types until we outline the implementation and add in Dictionary<Type, IComparator>
Notice, the exception we will see only on runtime
And now imagine if this work was done for us by the compiler during build and it threw exception if it could not find the comparator with corresponding types.
For this, we could help the compiler and add a new keyword instead of usage attribute. Out Sort method will be look like this:
public static T[] Sort(T[] array, implicit IComparator<T> comparator)
{
...
}
And code of realization concrete Comparator:
public class IntegerComparator : IComparator<int> implicit { }
Note, we use the keyword 'implicit', after this compiler will be able to do
routine work, which we wrote above, and the exception will be thrown during
compile-time
var sortedIntegers = Sort(integers);
// this gives us compile-time error
// because we don't have implementation of IComparator<string>
var sortedStrings = Sort(strings);
And give the name to this style of implementation Type Class
public class IntegerComparator : IComparator<int> implicit { }
I hope that I understood correctly and understandably explained.
PS: The code does not pretend to work.

Why is Explicit Operator Not Invoked In Generic Method

I've distilled this question down to the simplest code sample I can think of. Why is the explicit operator not invoked from the generic method?
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = (B)a; // works as expected
b = Cast<B>(a);
}
static TResult Cast<TResult>(object o)
{
return (TResult)o; // throws Invalid Cast Exception
}
}
class A
{
}
class B
{
public static explicit operator B(A a)
{
return new B();
}
}
Because a generic method has one set of IL, based around TResult. It doesn't do different IL per-caller. And the generic TResult does not have any operators.
Also: the operator here would need to be between object and TResult, and you can't define operators involving object.
For example: Cast<int> and Cast<string> and Cast<Guid> all have the exact same IL.
You can cheat with dynamic:
return (TResult)(dynamic)o;
What it comes down to is that the implicit and explicit operators aren't true conversion operators; they're entirely compile time syntactic sugar. Once the code is compiled nothing about the conversion operators remains.
When the compiler sees:
B b = (B) new A();
It says, "is there any native conversion (implicit or explicit) from an A to a B?" (This would be the case if A extended B, for example), or for one of the few special cased language conversions such as double to int (implicit) or int to double (explicit).)
If not, it then looks for user defined conversion operators (it only looks in the definition of A and B, it doesn't look in the definition of C for an implicit conversion from A and to B, for example). If it finds one, then it injects that operator as a static method call, so the code ends up looking like:
B b = B.SomeAutogneratedName(new A());
That way by the time you get to runtime it's just executing another method, something the runtime knows how to do. The only actual runtime conversion operators that are allowed are the handful baked into the language (i.e. from any base type to a parent type, and between certain primitive types).

C# - generic methods vs. non-generic methods

I'm a bit confused about why/when I'd ever want to use a generic method since a non-generic method can access the generic members of its containing class and be passed generic arguments anyway.
So, using a canned example that likely misses the point (yet highlights why I'm asking this question), why would I do this:
public class SomeGeneric<T>
{
public T Swap<T>(ref T a, ref T b)
{
T tmp = a;
a = b;
b = tmp;
}
}
over
public class SomeGeneric<T>
{
public T Swap(ref T a, ref T b)
{
T tmp = a;
a = b;
b = tmp;
}
}
this?
Or, really, why would I want to use a generic method at all?
You'd typically use a generic method in a type that isn't generic.
For example, look at the Enumerable class. It defines the generic extension methods for most of the LINQ fucntionaltiy, but itself isn't generic.
You also might want a generic method within a generic type, but only if the generic method used a different generic type specifier.
This lets you write something like the following:
class Foo<T> where T : IConvertible, IComparable<T>
{
int CompareTo<U>(U other) where U : IConvertible
{
// Convert to this
T otherConverted = Convert.ChangeType(other, typeof(T));
return this.CompareTo(otherConverted);
}
}
(Granted, this is a bit contrived, but does compile and work correctly for Foo<int> comparing to a double, etc)
What if the containing class is not generic? What if it has different generic type parameters?
The first example does not make much sense, because class parameter is not used. Consider another example though:
public class SomeGeneric<T>
{
public K ConvertTo<T>(T a)
{
return CodeThatConvertsTtoK(a);
}
}
and its usage:
new SomeGeneric<int>().ConvertToInt("ten");
A common scenario for method level type parameters are extension methods because they must be declared in a non-generic static class. But they are required for every generic member in a non-generic type.
public static class Extensions
{
public static void Foo<A, B>(this A a, B b) { [...] }
public static T Bar<T>(this String input) { [...] }
public static U FooBar<V, W>(this V v, W w) { [...] }
}
If both the class and the method are generic, the type parameters ("generic parameters") must have different names, of course. There can't be two different things named T like in your first example.
If your method is non-static (as it seems), if you choose to make the containing class generic, the type will have to be specified already when you instantiate your class. Like var obj = new SomeGeneric<DateTime>();. So it should be something that logically "belongs" to the object modelled by the class.
If your method is static, and you choose to make the class generic, you will still have to specify the type parameter together with the class somehow. If the method is called from outside the class, it would go like SomeGeneric<DateTime>.Swap(ref a, ref b);.
The advantage with making the method generic, is that in many cases you can use type inference which allows you to omit the angle bracketed type parameter. You can only do this with generic methods. Example: nonGeneric.Swap(ref a, ref b); where the Swap<T> method is generic. The compiler will look at the compile-time types of a and b and figure out which T fits in, without you specifying it.
Conclusion: If the T does not logically belong to the class (as in List<T>), put it with the method.
Here's one example where generic methods really shine. Consider an expression such as 1+2 expressed as a binary tree. You want to implement the Visitor pattern on the entire tree, with the goal being some sort of map/reduce operations. Some examples would be:
Reducing an expression to a string to print it
Reducing an expression to a double to calculate its value
Mapping an expression to another expression with some members altered/added/removed
All of these operations can be put behind a Visitor pattern method:
public abstract class Expression
{
public abstract T Reduce<T>(ITransformer<T> transformer);
}
This is similar to the classic Visitor implementation, but the terminology is changed: we have Reduce() instead of Accept() and an ITransformer<T> instead of an IVisitor. Notice that the method is generic.
This approach allows us to create any number of ITransformer<T> classes that transform the hierarchy to any type T, supporting map-reduce operations.

Generics in C# with multiple generic types leads to allowed and disallowed ambiguity

I recently wrote this and was surprised that it compiles:
public class MyGeneric<U, V> {
MyGeneric(U u) { ... }
MyGeneric(V v) { ... }
public void Add(U u, V v) { ... }
public void Add(V v, U u) { ... }
}
If I use this class as follows, I get an "Ambiguous constructor reference" and an "Ambiguous invocation" if I call Add.
var myVar = new MyGeneric<int, int>(new MyIntComparer());
Obviously, there's no ambiguity when I use int and double as generic types, except of course when I use both ints, which would also both assign to a double.
var myVar = new MyGeneric<int, double>(new MyIntComparer());
myVar.Add(3, 5);
So then I thought that the following was also allowed, but surprisingly I got an error. Why is the following not allowed to compile?
public interface IMyInterface<T, S> {
void Add(T t, S s);
}
public class MyGeneric<U, V> : IMyInterface<U, V>, IMyInterface<V, U> {
public MyGeneric(U u) { }
public MyGeneric(V v) { }
void IMyInterface<U, V>.Add(U u, V v) { ... }
void IMyInterface<V, U>.Add(V v, U u) { ... }
}
Regardless if I use implicit or explicit interface implementation, the compiler states that
'MyGeneric<U,V>' cannot implement both 'IMyInterface<U,V>' and 'IMyInterface<V,U>' because they may unify for some type parameter substitutions
And why is the first allowed to write?
1- Why is the following not allowed to compile ?
Part of the response is in that post : Why does the C# compiler complain that "types may unify" when they derive from different base classes?
The section 13.4.2 of the C# 4 specification states:
The interfaces implemented by a generic type declaration must remain
unique for all possible constructed types. Without this rule, it would
be impossible to determine the correct method to call for certain
constructed types.
2- And why is the first allowed to write?
The compiler perform the generic type check at compile time, the section 7.4.3.5 of the C# 4 specification states:
While signatures as declared must be unique, it is possible that
substitution of type arguments results in identical signatures. In
such cases, the tie-breaking rules of overload resolution above will
pick the most specific member. The following examples show overloads
that are valid and invalid according to this rule:
interface I1<T> {...}
interface I2<T> {...}
class G1<U>
{
int F1(U u); // Overload resulotion for G<int>.F1
int F1(int i); // will pick non-generic
void F2(I1<U> a); // Valid overload
void F2(I2<U> a);
}
class G2<U,V>
{
void F3(U u, V v); // Valid, but overload resolution for
void F3(V v, U u); // G2<int,int>.F3 will fail
void F4(U u, I1<V> v); // Valid, but overload resolution for
void F4(I1<V> v, U u); // G2<I1<int>,int>.F4 will fail
void F5(U u1, I1<V> v2); // Valid overload
void F5(V v1, U u2);
void F6(ref U u); // valid overload
void F6(out V v);
}
It's part of the language specification, as explained in the accepted answer here :
Why does the C# compiler complain that "types may unify" when they derive from different base classes?
Section 13.4.2 of the C# 4 specification states:
If any possible constructed type created from C would, after type arguments are substituted into L, cause two interfaces in L to be identical, then the declaration of C is invalid. Constraint declarations are not considered when determining all possible constructed types.
I guess the difference between your two example is that the second uses interfaces (checked for duplicates, per the language spec) but the first uses types (not checked for duplicates, despite potentially causing ambiguity as you have seen).

Method overloading in generic class

I am working with a code that contains following overloaded method in generic class:
public class A<T>
{
public void Process(T item) { /*impl*/ }
public void Process(string item) { /*impl*/ }
}
When parametrizing the class for string do I lose the possibility to call the version with generic parameter?
var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)
Specific types take precedence over generic types.
For example, this is what I tested with in LINQPad.
void Main()
{
new A<string>().Process("Hello");
}
public class A<T>
{
public void Process(T item) { Console.WriteLine("T"); }
public void Process(string item) { Console.WriteLine("string"); }
}
// Output: string
If you have a problem with hiding the generic method, then you need to rethink something. By overloading a generic method with specific types, you are effectively saying, "Use the generic overload if you need to, but if you can, use the specific version, because it should know what is best."
There is one way I just discovered, but it's a bit cross-eyed. Because generics and overloading get resolved in build time, you can define a generic method:
public static CallerClass
{
public static CallGenericOverload<T>(GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
//We can also make an extension method.
//We don't have to of course, it's just more comfortable this way.
public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
{
return cls.ProblemOverload(val);
}
}
public GenericClass<T>
{
public string ProblemOverload(T val)
{
return "ProblemOverload(T val)";
}
public string ProblemOverload(string val)
{
return "ProblemOverload(string val)";
}
}
Now, if we do the following:
var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)
You can use a similar trick if you define a generic class instead of a generic method. The important thing is that the parameter you transfer to ProblemOverload needs to be of type T rather than type string in the invocation. After all, the method CallGenericOverload knows it's getting a T at build time, so it's going to bind to the overload that accepts the parameter. It doesn't matter that it's actually going to get a string at runtime.
Yes. This is documented in the C# spec, section 7.5.3, overload resolution.
From 7.5.3.6:
"While signatures as declared must be unique, it is possible that substitution of type arguments results in identical signatures. In
such cases, the tie-breaking rules of overload resolution above will
pick the most specific member."
The example given in there states that in the case below, overload resolution for G<int>.F1 will pick non-generic
class G1<U>
{
int F1(U u);
int F1(int i);
}
The tie-breaking rule that applies here is outlined in 7.5.3.2, "Better function member":
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …,
QN} are equivalent (i.e. each Pi has an identity conversion to the
corresponding Qi), the following tie-breaking rules are applied, in
order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
Having done this before, I'm inclined to say "No," but there's always more knowledgable folks who would argue otherwise.
If memory serves, the runtime compiler chooses the most strongly typed overload to execute.
CLARIFICATION
My answer is badly worded, and I deserve the downvote.
The OP asked, "When parametrizing the class for string do I lose the possibility to call the version with generic parameter?" I wasn't answering that "No, you can't do that," but that "No, you don't lose the ability to call the version with the generic parameter."
I should have been more clear.

Categories

Resources