efcore icon indicating copy to clipboard operation
efcore copied to clipboard

ExpressionEqualityComparer and Parameter Names

Open ActivistInvestor opened this issue 1 year ago • 2 comments

I forked ExpressionEqualityComparer and slightly modified it because my definition of equality of two expressions must disregard differing parameter names.

I am wondering if anyone else has ever had the need to compare expressions without considering parameter (and variable) names.

For example, the change I made would cause these two expressions to be considered as being equal:

    Expression<Func<int,int>> a = foo => foo + 10;
    Expression<Func<int,int>> a = bar => bar + 10;

The mod also excludes parameter names from hashcode calculation. The change was fairly trivial:

Before:

private bool CompareParameter(ParameterExpression a, ParameterExpression b)
   => _parameterScope != null
       && _parameterScope.TryGetValue(a, out var mapped)
           ? mapped.Name == b.Name
           : a.Name == b.Name;

After:

private bool CompareParameter(ParameterExpression a, ParameterExpression b)
   => true;

Hashcode computation:

Before

case ParameterExpression parameterExpression:
  AddToHashIfNotNull(parameterExpression.Name);
  break;

After

case ParameterExpression parameterExpression:
  break;

So, I guess what I'm getting at here is to propose that ignoring parameter names be a parameterized option.

ActivistInvestor avatar Jun 30 '24 16:06 ActivistInvestor

IIUC you are suggesting that expressions should be considered equal modulo α-conversion.

I agree on that, but I should warn you that the updated CompareParameter would lead to considering equal even expressions that should probably be considered different, for example:

Expression<Func<int,int,int>> twice_x_plus_y = (x, y) => x + x + y;
Expression<Func<int,int,int>> x_plus_twice_y = (x, y) => x + y + y;

EDIT: updated the expressions so that all of the lambda parameters are used in the body to make it more obvious that the issue is the name confusion and not the param (non-)usage.

ranma42 avatar Jun 30 '24 19:06 ranma42

Related:

  • #30755

ranma42 avatar Jun 30 '24 19:06 ranma42

Thanks for your insight and advice. I'm now thinking about replacing the parameters in one expression with the parameters from the other expression, as one would have to do when combining the expression bodies, and then allowing them to be compared. I'm not sure what other ways there are to achieve this, but what I do know, is that for my purposes, the parameter names are inconsequential, as two otherwise-identical expressions are functionally-equivalent.

ActivistInvestor avatar Jul 01 '24 04:07 ActivistInvestor

I was partially mistaken about the issues. With the existing code, two expressions that use different parameter names but are otherwise identical do compare as equal. The problem was that I was using expressions as Dictionary keys and also storing them in HashSets, and because the existing code uses parameter names as ingredients in hashcode generation, it resulted in different hashcodes for expressions that compare as equal (when they use different parameter names).

The change to the hashcode generation code that I showed above is all that's needed, and the code that suppresses the comparison of parameter names isn't needed because the original code already deals with that correctly.

ActivistInvestor avatar Jul 02 '24 01:07 ActivistInvestor