dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.02k stars 4.03k forks source link

Negating a function #16613

Closed bjorn-ali-goransson closed 1 year ago

bjorn-ali-goransson commented 7 years ago

It would be nice to be able to negate a function when doing this:

.Where(i => !imageBank.Images.Contains(i))

So I only have to write this:

.Where(!imageBank.Images.Contains)
DavidArno commented 7 years ago

Currently, when you write .Where(imageBank.Images.Contains), the compiler follows the rules in §6.6 Method group conversions, from the language specification, So if the compiler can select a method from that group that is compatible with the delegate, D, specified by Where(D), then it substitutes the expression with that method.

What you are requesting would be a whole new conversion, along the lines of: if the expression E (!imageBank.Images.Contains in this case) is formed of ! followed by a method group, then if that group contains a method that both returns a bool and is compatible with the delegate D, then substitute E for a new lambda i => !SelectedMethod(i) and then apply the existing lambda rules to this new expression.

So not impossible, but not a trivial change either.

bjorn-ali-goransson commented 7 years ago

Yes, actually, having ! in front of a Function<,,, bool> reference could negate it, creating another lambda.

Func<int, bool> zero = i => i == 0;
Func<int, bool> nonZero = !zero;

Converted to:

Func<int, bool> nonZero = i => !zero(i);

So it could be useful to more than method groups.

iam3yal commented 7 years ago

@bjorn-ali-goransson

Today the following is an assignment:

Func<int, bool> zero = i => i == 0;
Func<int, bool> nonZero = zero;

but what you're proposing is for the following:

Func<int, bool> zero = i => i == 0;
Func<int, bool> nonZero = !zero;

to be a function call?

bjorn-ali-goransson commented 7 years ago

No, it would create a new function with a negated result of the first one.

2017-01-19 14:26 GMT+01:00 Eyal Solnik notifications@github.com:

@bjorn-ali-goransson https://github.com/bjorn-ali-goransson

So the following would be an assignment:

Func<int, bool> zero = i => i == 0; Func<int, bool> nonZero = zero;

whereas the following:

Func<int, bool> zero = i => i == 0; Func<int, bool> nonZero = !zero;

would be a function call?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/roslyn/issues/16613#issuecomment-273775574, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoyAPS5Nckj1BRXtxL9XtERLHonjDusks5rT2SMgaJpZM4Ln9fB .

HaloFour commented 7 years ago

If "Extension Everything" could cover delegates you might be able to define a unary negation operator on the target delegate types.

Having the operator apply to arbitrary method groups seems a little overkill, especially given that the compiler has to work out what !imageBank.Images.Contains means and its expression type before it can concern itself with resolving any specific methods. Also, applying the operator by wrapping the delegate in another delegate which would handle the negation would cause a performance penalty. Seems complicated for something solved so easily already.

bjorn-ali-goransson commented 7 years ago

Yes, but please remember that once you start utilizing method group expression substitution ie in Linq, it quickly becomes very addictive.

tors 19 jan. 2017 kl. 15:22 skrev HaloFour notifications@github.com:

If "Extension Everything" could cover delegates you might be able to define a unary negation operator on the target delegate types.

Having the operator apply to arbitrary method groups seems a little overkill, especially given that the compiler has to work out what !imageBank.Images.Contains means and its expression type before it can concern itself with resolving any specific methods. Also, applying the operator by wrapping the delegate in another delegate which would handle the negation would cause a performance penalty. Seems complicated for something solved so easily already.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/roslyn/issues/16613#issuecomment-273788201, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoyALKZ7oiZ_6ZGgc78mool4zgLwTFEks5rT3GNgaJpZM4Ln9fB .

DavidArno commented 7 years ago

@bjorn-ali-goransson,

It's important to remember that:

.Where(imageBank.Images.Contains)

is not shorthand for:

.Where(i => imageBank.Images.Contains(i))

it's shorthand for:

.Where(new Func<Image, bool>(imageBank.Images.Contains))

What you are requesting is the auto-creation of lambdas from method groups, which is a different thing.

Thaina commented 7 years ago

If I need to do something like this I would prefer add this to corefx instead

public static IEnumerable<T> WithOut(this IEnumerable<T> items,Func<bool,T> func) { ... }
////
list.WithOut(imageBank.Images.Contains);

Or maybe

list.GroupBy(imageBank.Images.Contains).First((group) => !group.Id);
CyrusNajmabadi commented 1 year ago

Closing this out. We're doing all language design now at dotnet/csharplang. If you're still interested in this idea let us know and we can migrate this over to a discussion in that repo. Thanks!