Replies: 22 comments
-
So would be an expander mid params? e.g. usage for RemoveConsecutiveTokens(
this IEnumerable<SyntaxAssignment> assignments,
params string[] tokens, // Tokens to remove
out int index) assignments.RemoveConsecutiveTokens(s0, s1, s2, s3, out int index);
assignments.RemoveConsecutiveTokens(s0, s1, s2, s3, s4, out int index);
assignments.RemoveConsecutiveTokens(s0, s1, s2, s3, s4, s5, out int index);
assignments.RemoveConsecutiveTokens(s0, s1, s2, s3, s4, s6, s7, out int index); |
Beta Was this translation helpful? Give feedback.
-
@benaadams Yep, that's how the method would be called. I'll update the description to clarify. |
Beta Was this translation helpful? Give feedback.
-
Just use a tuple to return both the enumeration and the index. That way you don't then need an out parameter, solving the "which should come last" problem without a language change: public static (IEnumerable<SyntaxAssignment> cleanedList, int index) RemoveConsecutiveTokens(
this IEnumerable<SyntaxAssignment> assignments,
params string[] tokensToRemove)
{
} |
Beta Was this translation helpful? Give feedback.
-
I don't get how that relates to this issue specifically. Yes, it's possible to use a tuple, but the same can be said of any scenario where Suppose there's an imaginary bug in the compiler that prevents someone from being able to use
The core issue for me is there does not seem to be a good reason why out/ref parameters are prohibited after |
Beta Was this translation helpful? Give feedback.
-
That was my point: The compiler currently requires |
Beta Was this translation helpful? Give feedback.
-
You not liking them does not make them a legacy feature. At no point has the team suggested or implied that tuples supplant |
Beta Was this translation helpful? Give feedback.
-
Indeed, I would say |
Beta Was this translation helpful? Give feedback.
-
I still haven't seen a satisfying alternative for the Out param if (int.TryParse("123", out var result))
{
Console.WriteLine(result + 5);
} Nullable int? result = int.TryParse("123");
if (result.HasValue)
{
Console.WriteLine(result.Value + 5);
} Value tuple (bool success, int value) = int.TryParse("123");
if (success)
{
Console.WriteLine(value + 5);
} |
Beta Was this translation helpful? Give feedback.
-
Also it's my preferred pattern when using a OneOf type: OneOf<int, string, Foo> x = ...;
if (x.TryGetItem1(out var number))
{
// ...
}
else if (x.TryGetItem2(out var text))
{
// ...
}
// etc |
Beta Was this translation helpful? Give feedback.
-
Since pattern matching (I'm guessing) will never be able to handle that API pattern. |
Beta Was this translation helpful? Give feedback.
-
Why not? This works today in F#: let x : Choice<int, string, Foo> = Choice1Of3 42
match x with
| Choice1Of3 number -> ()
| Choice2Of3 text -> ()
| _ -> () Why do you think pattern matching in C# will not be able to handle this pattern, once recursive patterns are introduced? |
Beta Was this translation helpful? Give feedback.
-
@svick Because I want to match on the names |
Beta Was this translation helpful? Give feedback.
-
And I'm dreaming I know, but oh the joy if I could have an expanded version of #894 and this was possible: OneOf<int ThisThing, int ThatThing, int TheOtherThing> x = ...
if (x.TryGetThisThing(out var thisThing))
{
// ...
}
else if (x.TryGetThatThing(out var thatThing))
{
// ...
}
// etc. You might ask why, since I can name the out vars? Because if I could give members derived aliases, I would choose this pattern instead: switch (x.Which)
{
case 1:
// Do something with x.ThisThing
case 2:
// Do something with x.ThatThing
// etc.
} It's faster and doesn't introduce unneeded locals. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 I know. Matching on simple type works today in C# (i.e. you have OneOf<int, string, Foo> x = ...;
switch (x)
{
case Item1(var number):
// …
case Item2(var text):
// …
} If you mean that |
Beta Was this translation helpful? Give feedback.
-
@svick
I already have scenarios where this is in use where they are not different types. 😃 |
Beta Was this translation helpful? Give feedback.
-
Your nullable example can be made far simpler (and as good as using an out var): if (int.TryParse("123") is int result)
{
Console.WriteLine(result + 5);
} Tuples are hampered by the inability to decompose them in an if (int.TryParse("123") is var (success, value) && success)
{
Console.WriteLine(value + 5);
} but it can still be expressed with a pattern: if (int.TryParse("123") is var tuple && tuple.success)
{
Console.WriteLine(tuple.value + 5);
} And using an if (int.TryParse("123") is Some<int> value)
{
Console.WriteLine(value + 5); // implicit conversion of Some<int> to int
}
What you want to do is already covered by the Succinc<T> library: var x = new Union<int, string, Foo>(1);
x.Match()
.CaseOf<int>().Do(...)
.CaseOf<string>().Do(...)
.CaseOf<Foo>().Do(...)
.Exec(); Though it won't support unions of the same type, eg var x = new Union<int, int>(1);
x.Match()
.Case1().Do(...)
.Case2().Do(...)
.Exec(); but it wouldn't compile on the first line as you'd end up with an overload conflict on the constructor. |
Beta Was this translation helpful? Give feedback.
-
@DavidArno and, that requires you to allocate lambda closure delegates which are not my favorite thing ever. I also have |
Beta Was this translation helpful? Give feedback.
-
No closures are involved (unless you want them to be, of course 😁) |
Beta Was this translation helpful? Give feedback.
-
Also it's worth pointing out that |
Beta Was this translation helpful? Give feedback.
-
You keep using that word. I do not think it means what you think it means. |
Beta Was this translation helpful? Give feedback.
-
If I need access to method locals, which is typical, I'd prefer to use a control flow statement rather than a capturing lambda or manually transforming my method state into a class, which are my other options. Re: (Edit: see #788 (comment) and #788 (comment). |
Beta Was this translation helpful? Give feedback.
-
I think we've gotten a little off-topic, everyone... your ideas are great, but tuples/nullables/pattern-matching/etc. are not a replacement for out/ref vars. Even if you think they are, I don't think this is a good issue to debate that. @VSadov Since you have worked on a lot of ref-related features like ref returns and readonly ref, which makes you an expert at this 😉, I'd like to hear if you have an opinion on this. When |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Currently, all
params
parameters must be the last in the parameter list. The rationale for this is because (I assume) otherwise, it would be very hard for the compiler and/or developer to tell which arguments at the callsite corresponded to which parameters.However, it's also very common/good practice to have ref/out parameters be the last in the parameter list. At the callsite, there is also no chance of confusing these arguments with ones that should be part of the
params
array, since ref/out arguments have to be explicitly preceded byref
/out
even at the callsite. However, the compiler currently prevents you from putting ref/out parameters afterparams
parameters. For example:Since
params
parameters and ref/out parameters both have to be last to allow the code to compile/maintain good practice, respectively, it's impossible to have a valid method where you combine them and maintain good practice. You need to workaround it like this:or
Can we allow ref/out parameters to come after
params
ones, to make the first code snippet valid? edit: That method could then be called like this:edit 2: We would not allow omitting the
params
arguments to mean passing in an empty array. e.g. Although this is valid:This would not be:
The reason for this is it's more plausible to forget about/overlook the
params
argument now that it can be sandwiched in between an arbitrary number of other arguments. And if the compiler doesn't remind us about it, then it could lead to more bugs. Disallowing it is just a minor inconvenience compared to the benefits it brings; users can circumvent it by passing inArray.Empty<T>()
ornew T[0]
.Beta Was this translation helpful? Give feedback.
All reactions