Kris Craig
Kris Craig

Reputation: 586

Why doesn't Comparer support 64-bit (long) delegate return type for lambda operations in C#?

I'm trying to create a priority queue in C# that consists of 64-bit (long) integers in DESCENDING order. Unfortunately, it looks like .NET doesn't support this?

Here's the code that fails:

PriorityQueue<long, long> pq = new PriorityQueue<long, long>(Comparer<long>.Create((x, y) => y - x));

And here are the errors it generates:

error CS0266: Cannot implicitly convert type 'long' to 'int'. An explicit conversion exists (are you missing a cast?)

error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type

It should be noted that everything works perfectly if I change all the "long" references to "int".

Is there a cast I can put somewhere to make this work or is this just a basic feature that C# doesn't support for whatever reason?

Upvotes: 0

Views: 91

Answers (2)

Ivan Petrov
Ivan Petrov

Reputation: 4915

It does support it.

You need to do this though:

IComparer<long> comparer = Comparer<long>.Create((x, y) => y == x ? 0 : y > x ? 1 : -1)

Your (understandable) confusion stems from the parameter for Comparer<T>.Create being a dedicated "old-style" delegate that "hides" its signature a bit when you hover over the method that accepts it:

public delegate int Comparison<in T>(T x, T y)

you are not seeing int anywhere just Comparison<long>, and assume that it's Func<T,T,T> whereas it actually is Func<T,T,int>.

Unfortunately it's late now to also add an overload for Comparer<T>.Create with a Func<T,T,int> parameter because it will create ambiguity for the compiler when you pass the lambda inline - the two delegates being functionally equivalent it won't be able to pick one method over the other.

The int return type is as others have commented for the actual contract of IComparer<T> - int CompareTo(T x, T y)

Upvotes: 4

Charlieface
Charlieface

Reputation: 72194

Not sure what you were trying to do with y - x, that would give you incorrect results in some cases.

It was erroring because you were returning a long, and Compare expects an int which is:

  • 0 for equal values
  • Positive where x > y
  • Negative where y > x

The simplest way to return the reverse comparison is to just flip the operands. Compare x against y rather than the other way round.

var comparer = Comparer<long>.Create((x, y) => y.CompareTo(x));
PriorityQueue<long, long> pq = new PriorityQueue<long, long>(comparer);

Upvotes: 4

Related Questions