match with anonymous/dynamic types #2321
Replies: 28 comments
-
Can you please give a description of this issue? What is the problem you're trying to solve, with examples? |
Beta Was this translation helpful? Give feedback.
-
done, sorry |
Beta Was this translation helpful? Give feedback.
-
No problem, thanks. |
Beta Was this translation helpful? Give feedback.
-
C# 8.0 should bring recursive matching of anonymous types as you're allowed to omit the type name when it's known by the compiler, but that would only work if the compiler knows that the variable is of the anonymous type and not a generic type or I want to say that the team has mentioned pattern matching on dynamic as something to consider but I can't find it in any of the notes. From what I recall the binding API behind dynamic doesn't really offer a way to test if a type supports the members, if it fails to bind then it throws. |
Beta Was this translation helpful? Give feedback.
-
I can definitely see the benefit of matching on some form of structural/duck typing. It would also be compile time verifiable, unlike using dynamic directly. However I wonder if there's anyway to generate the switch more efficiently than just using dynamic. I can't think of any. In general the lack of structural typing is actually a big issue in C# IMO. Nominative typing has its advantages, and is easier to implement without a dynamic runtime, but typescript has shown the power of structural typing when running on a dynamic runtime. It would be nice if there was a more general solution to this IMO |
Beta Was this translation helpful? Give feedback.
-
I expect that to come up as shapes/typeclasses get more attention. I can see it being somewhat tricky, though, as you'd have to be matching against the witness. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour |
Beta Was this translation helpful? Give feedback.
-
Even when DLR support would be nice there is another (compile time) approach for anonymous:
(see the use of class instead of dynamic in this cases)
as a way to refer to anonymous types |
Beta Was this translation helpful? Give feedback.
-
@marioilitio |
Beta Was this translation helpful? Give feedback.
-
At this point I have no idea, especially as some of the latest discussion around "roles" and "extension interfaces" seem to differ quite a bit from the discussions around "shapes" and "typeclasses". The newer discussion doesn't seem to dig a lot into the implementation details, so I'll base this example on shapes: public shape PersonLike {
string FirstName { get; }
string LastName { get; }
}
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}
class C {
static void M(Person person) {
if (person is PersonLike { FirstName: "Tim", LastName: var lastName }) {
Console.WriteLine($"Hello Mr. {lastName}!");
}
}
} The compiler would generate the witness struct as follows: public struct Person_PersonLike : PersonLike<Person> {
public static string get_FirstName(Person @this) => @this.FirstName;
public static string get_LastName(Person @this) => @this.LastName;
} And the compiler would emit something like the following for the match itself: Person_PersonLike witness = default;
if (person != null) {
string firstName = witness.get_FirstName(person);
if (firstName == "Tim") {
string lastName = witness.get_LastName(person);
Console.WriteLine($"Hello {lastName}!");
}
} |
Beta Was this translation helpful? Give feedback.
-
But that's all a case where we know the type, and hence the type of the witness. How would you match object against a shape? |
Beta Was this translation helpful? Give feedback.
-
You don't. As is the case here the only ways to do that are via reflection or dynamic binding, both very slow and error prone. |
Beta Was this translation helpful? Give feedback.
-
That's my point. |
Beta Was this translation helpful? Give feedback.
-
You mentioned that it would be "compile time verifiable" which would require that the compiler know about the type during compilation at which point it can emit the witness and plumb the match against that. Against |
Beta Was this translation helpful? Give feedback.
-
It would all be a compile time trick, but you can generate reflection code which looks for a suitable witness and tries to match against that. |
Beta Was this translation helpful? Give feedback.
-
Is it so problematic to compiler, to match itself whether two anonymous types are structurally compatible in terms of a match? |
Beta Was this translation helpful? Give feedback.
-
It's not a problem with the compiler. It's a problem with the runtime and the type system. |
Beta Was this translation helpful? Give feedback.
-
Problem in the looser sense of the word. I.e. that's just not how the type system works. There's alternative type systems, but they have their own issues. |
Beta Was this translation helpful? Give feedback.
-
How would the compiler look for a suitable witness if it doesn't know the type? It'd have to emit code at runtime to literally look at all possible implementations of the "shape" interface.
The compiler has to know that it's an anonymous type to begin with. Once you've assigned that anonymous type to an |
Beta Was this translation helpful? Give feedback.
-
@HaloFour |
Beta Was this translation helpful? Give feedback.
-
So, not "compile time checked" then. IMO that's not a reasonable way to negotiate types for a match. Dynamic binding would probably be more efficient. |
Beta Was this translation helpful? Give feedback.
-
As I can see, this anonymous object can live as the same citizen class as the others (int, string, etc.) on the last example I post before. If the compiler can match/infer a named type, I thing it could do the same for anonymous, which are, in the end, also named types (compile-time named types) |
Beta Was this translation helpful? Give feedback.
-
The compiler can only match with such an inference when the type is known at compile time. Once you've cast to |
Beta Was this translation helpful? Give feedback.
-
As I can see, this anonymous object can live as the same citizen class as the others (int, string, etc.) on the last example I post before. If the compiler can match/infer a named type, I thing it could do the same for anonymous, which are, in the end, also named types (compile-time named types) |
Beta Was this translation helpful? Give feedback.
-
It can't, because it doesn't know the name of the anonymous type. Their could be infinite anonymous types with the same signature. How does it know which is the correct one to use? |
Beta Was this translation helpful? Give feedback.
-
how is it done with delagates? there are also a lot of delegates with the same signatures, even though lambda expressions can be matched in compile time... is it not a similar compiling approach? |
Beta Was this translation helpful? Give feedback.
-
delegates cannot be matched: class Program
{
delegate int A(int a);
delegate int B(int a);
static int M1(int a) => 42;
static void M()
{
B b = M1;
if (b is A a) Console.WriteLine("true"); //Will not compile
if ((object)b is A a) Console.WriteLine("true"); else Console.WriteLine(false); //prints false
}
} When you create a lambda it is target typed, meaning the compiler will look how it is used to decide which type to create, but that has nothing to do with this scenario. |
Beta Was this translation helpful? Give feedback.
-
useful.
works but slow |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
consider the following example:
in this case myobject (of any unknown type) can be matched with any type that have "some" structure in their properties.
Beta Was this translation helpful? Give feedback.
All reactions