Roslyn: The semantic of constant pattern

Created on 14 Jan 2017  Â·  5Comments  Â·  Source: dotnet/roslyn

I propose to change the semantic of constant pattern match from current:
```c#
foo is 42 /* == */ object.Equals(foo, 42)

…to the opposite:
```c#
foo is 42 /* == */ object.Equals(42, foo)

And this is how object.Equals(object, object) is implemented:
c# public static bool Equals(Object objA, Object objB) { if (objA==objB) { return true; } if (objA==null || objB==null) { return false; } return objA.Equals(objB); }

The reasons behind proposed change:

  1. Currently the "constant patterns" are not that "constant": generated code involves the execution of arbitrary 'object.Equals(object)' implementation on foo instance (in the case it is not null), since object.Equals(object, object) invokes it on first argument.
  2. The idiom foo is null do not actually means ((object) foo) == null as most of users would expect. It is easy to define a type that would pass foo is null check while being not-null (how would this play with future non-nullable types and their dataflow analysis?).
  3. You won't be able to get rid of suboptimal code for constant patterns of reference types #13247, since such optimizations would change the semantic of matching.
  4. If the arguments of object.Equals() would be reversed, the nice property of is expression would be restored — if right operand (type or pattern) has a type, the is expression only produce true if the left operand is of implicitly convertible type. Constant patterns do have types, literal expression do have types, 42 is of type int… who would expect (int) foo after successful foo is 42 check to throw InvalidCastException?

p.s. Maybe it's a good idea to behave like F#: literal patterns of type int are only allowed when pattern is matched against the value of int type (but that's because of ML's "no implicit conversions" rule, I think).

cc @gafter

4 - In Review Area-Compilers Bug New Language Feature - Pattern Matching _Product-level triaged

Most helpful comment

foo is 42 /* == */ object.Equals(42, foo)

Or maybe just 42.Equals(foo) which avoids the unnecessary null check goo.

All 5 comments

foo is 42 /* == */ object.Equals(42, foo)

Or maybe just 42.Equals(foo) which avoids the unnecessary null check goo.

@mikedn Modulo performance, those have the same behavior. I'm sympathetic to this change and will bring it to the LDM.

+1 for 42.Equals(foo) if this would eliminate boxing of constant value.
The current codegen seems to be implemented very lazily :(

The LDM approved this proposed change today.

Was this page helpful?
0 / 5 - 0 ratings