-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Allow patterns in foreach statement #6067
Comments
The problem with this design is that if you try to override some method that has multiple overloads, compiler doesn't know which one you are overriding. So there should be a hint to the compiler about type of the target object. class Foo {
public virtual bool Equals(Bar bar) { ... }
}
class Baz : Foo {
// ambiguous between object.Equals(object) and Foo.Equals(Bar)
// **if Bar could be possibly a Foo**
public override bool Equals(case Foo foo) { ... }
// type hint
public override bool Equals(object case Foo foo) { ... }
} Although, this might be addressed by considering pattern compatibility of the |
I'm sorry but I can't understand what you're proposing. Can you provide more examples of producing/consuming code using this proposal? |
@paulomorgado The original post is all examples by the way! It's about inserting a
is equivalent to
|
If I understand the examples correctly, this seems very powerful and has a lot of potential. More clarification is needed for several of the examples however. void F(case (int a, int b)) {} different from void F(int a, int b) {} which is part of #347? The same questions apply to lambda expression examples. Also, what are the element types of enumerables in the This could be great, but I'm, not sure I understand it fully. |
The former is a tuple-pattern mentioned in #5154 comment. The latter uses regular parameters. Introducing In the |
In your original examples, none of the patterns are complete. So they all produce warnings? I'm not sure I understand the semantics of any of the proposals exhibited by your examples. |
@gafter Tuples, single case ADTs and active patterns are considered as a complete pattern in this context (depending on the static type of target object, just like F#). For event handlers |
But these declarations don't have a target object. Perhaps I need to understand your proposed overload resolution rules. Can you please at least give me a hint? |
It's the parameter. For example in Same rules apply to Overload resolution rules remain the same since there is a static parameter type for each public override bool Equals(object) => false;
public override bool Equals(case Foo foo) => Equals(foo); translates to: public override bool Equals(object obj) =>
obj match(case Foo foo: Equals(foo) case *: false); First method Second method might be ambiguous if there is another
In this example , the "Overloading via patterns" is not essentially part of this proposal and might be considered as an additional feature. |
I can't tell what is part of this proposal and what isn't.
How is this any different from the same syntax without |
@gafter I meant that this can be done without going through complexity of "multiple methods". F# supports patterns in method parameters but doesn't support this one — which is common in functional languages like Haskell: isEmpty [] = True
isEmpty _ = False |
You mean like |
I take this to mean that the purpose is to defer selection of the overload until runtime and then pattern match against the actual value to select the overload that will be invoked. Foo x = new Foo();
object y = new Foo();
var equal = x.Equals(y); then the value of If so, how is the following evaluated? class Foo
{
...
public override bool Equals(object o) => false;
public override bool Equals(case Foo foo) => Equals(foo);
public bool Equals(int i) => i % 2 == 0;
}
...
Foo foo = new Foo();
var equal = foo.Equals((object)4); I assume the result would be bool Equals(case int i) => i % 2 == 0; then it would be |
There is no overload and the translation occurs at compile-time.
this is simply an error because you are overriding the method for the second time. Note that I said the class Foo
{
...
public override bool Equals(case Foo foo) => Equals(foo);
public override bool Equals(case int i) => i % 2 == 0;
public override bool Equals(case *) => false;
} If
Then it will be ambiguous with |
I think the chances of us supporting a syntax that promotes the body of a method out into the surrounding context is practically nil. |
@gafter I think the chances of needing to write something like |
@alrz And I thought C# was Turing-complete... |
@alrz So what did you mean by "needing"? |
@gafter I meant that it would be very common, besides, what else would you do in Tuples, ADTs, records, patterns, all this come from functional paradigm, so normally you would always see this kind of features together in a language. Because when you have one, you will "need" the other. That is the way that it would make sense. for me at least. You're saying that it's a "syntax that promotes the body of a method out into the surrounding context" because you're looking at it from an object-oriented point of view, while in a functional language that's a totally reasonable feature. |
@alrz Yes, I can see how, if your tuples don't have member names like ours do, you'd benefit from promoting pattern matching into the declaration. But we do have names for our tuple members, and it conflicts with our desire to separate the method's contract (the header, outside its body) from its implementation (inside its body). |
@alrz I think he is saying this is unnecessary for tuples because you will be able to write tuples.Select(((a, b)) => ...) Where a and b are the names of the tuple elements. Also with regard to promoting the method body into the surrounding environment, I agree that it is a bad idea in a language with method overloading. Haskell does not have overloading. Scala which does, does not allow this either. |
@aluanhaddad No, that is not correct. We are not proposing to extend the parameter syntax. |
What you are using is deconstruction syntax, which is basically a pattern. That's not possible to use patterns directly in method parameters. But I proposed that it could be with a A lambda that takes a tuple as argument would be possible but probably like |
A syntactic sugar for
foreach
statement to be able to use patterns in place of the variable declaration,If the pattern was not fallible there would be no
else continue
in the translation.The text was updated successfully, but these errors were encountered: