Beef icon indicating copy to clipboard operation
Beef copied to clipboard

[BUG] Some problems with extension methods

Open Igoorx opened this issue 5 years ago • 5 comments

I have encountered some problems while using extension methods, summarizing:

  1. FIXED ~~for doesn't work even though TList has IEnumerable constraint.~~
  2. Extension methods declared as mixin doesn't work at all. (PS: If this isn't a bug, you can leave it as it is if you want, no worries)
  3. Crash while typing a delegate.
  4. FIXED ~~Compiler can't find an extension method if something with the same name already exists in the class.~~
  5. FIXED ~~You have to cast the delegate to successfully call the Count2 method.~~

Here is the code with all the mentioned problems (commented out):

using System;
using System.Collections;

static
{
	public static mixin CountMixin<TList, TValueType>(this TList list, delegate bool(TValueType) comparer)
		where TList : IEnumerable<TValueType>
	{
		list.Count2(comparer)
	}

	public static int Count<TList, TValueType>(this TList list, delegate bool(TValueType) comparer)
		where TList : IEnumerable<TValueType>
	{
		return list.Count2(comparer);
	}

	public static int Count2<TList, TValueType>(this TList list, delegate bool(TValueType) comparer)
		where TList : IEnumerable<TValueType>
	{
		int count = 0;
		// ERROR: Type 'TList' must contain a 'GetEnumerator' method or implement an IEnumerator<T> interface
		//for (let item in list)
		for (let item in list.GetEnumerator())
		{
			if (comparer(item))
				count++;
		}
		return count;
	}
}

namespace test5
{
	class Program
	{
		public static int Main(String[] args)
		{
			int n = 0;

			List<int> test = scope .();
			test.Add(10);
			test.Add(11);
			test.Add(10);

			// ERROR: Cannot find mixin
			//n = test.CountMixin!(scope (x) => x == 10);

			// CRASH: To reproduce, try to add a 0 in the end of the next line
			//n = test.Count((delegate bool(int)) scope (x) => x == 10

			// ERROR: Cannot perform invocation on type 'int'
			//n = test.Count(scope (x) => x == 10);

			// ERROR: Unable to determine generic argument 'TValueType'
			//n = test.Count2(scope (x) => x == 10);

			// Works fine
			n = test.Count2((delegate bool(int)) scope (x) => x == 10);
			Runtime.Assert(n == 2);

			return 0;
		}
	}
}

Igoorx avatar Jan 11 '21 20:01 Igoorx

Issue 1 fixed at https://github.com/beefytech/Beef/commit/9510faafca9f6d5119eb104f79d1c964b356a8e6. You also have to add the new concrete constraint to TList.

bfiete avatar Jan 13 '21 17:01 bfiete

On issue 5- this also doesn't work in C#. This would require that the compiler examine the lambda code and decide that x == 10 probably means that you want x to be an int. That's not the kind of inference we can (nor do I think should) do.

Oh wait actually I misread this example.

bfiete avatar Jan 13 '21 17:01 bfiete

Ok, 5 is also fixed actually, too.

public static int Count2<TList, TValueType>(this TList list, delegate bool(TValueType) comparer)
	where TList : concrete, IEnumerable<TValueType>
{
	int count = 0;
	for (let item in list)
	{
		if (comparer(item))
			count++;
	}
	return count;
}

bfiete avatar Jan 13 '21 17:01 bfiete

I just noticed something, with the latest IDE version, the (unmodified) code of this issue shows an error in the IDE but compiles fine. image

Igoorx avatar Jan 14 '21 20:01 Igoorx

The enumeration issue above should be fixed in the next nightly.

bfiete avatar Jan 16 '21 14:01 bfiete