Skip to content
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

[Discussion] When clause on the methods #3807

Closed
KyouyamaKazusa0805 opened this issue Aug 19, 2020 · 6 comments
Closed

[Discussion] When clause on the methods #3807

KyouyamaKazusa0805 opened this issue Aug 19, 2020 · 6 comments

Comments

@KyouyamaKazusa0805
Copy link

KyouyamaKazusa0805 commented Aug 19, 2020

Consider the code:

private void Method(object sender, EventArgs e)
{
    if (sender is TextBox textBox)
    {
         // Do something using 'textBox'.
    }
}

Sometimes the model is useful and common, so I suggest the code be written like this:

private void Method(object sender, EventArgs e) when (sender is TextBox textBox)
{
    // Do something using 'textBox'.
}

Of course, if the method contains generic constraint...

private void Append<T>(this T @this, IEnumerable<T> values) where T : notnull
{
    if ((values?.Count() ?? 0) != 0)
    {
        // Do something.
    }
}

👇

public static void Append<T>(this T @this, IEnumerable<T> values) when ((values?.Count() ?? 0) != 0) where T : notnull
{
    // Do something.
}

It also can be used on the setters.

public int Age
{
    get { return _age; }
    set when (value is >= 0 and <= 150) { _age = value; }
}

// Or maybe
public int Age { get; set when (value is >= 0 and <= 150); }

On add or remove blocks:

public EventHandler TestEvent
{
    add when (value is not null);
    remove when (value is not null);
}

Adding brackets (T Method(parameters) when (when_clause)) is just like the exception-filtering when clause catch (Exception e) when (when_clause).

So... if the method-like members return non-void types, what behavior will these members act?
I think that we can bring these when clauses a condition. For instance, non-void cannot use when-clause.
In the other hands, we can also allow non-void-returning members use when clause, but returns default(T) if when clause itself returns false value (of throwing an exception).

For example, what does the following code mean?

public static string? Match(this string @this, string pattern) when (pattern.IsRegexPattern()) =>
    @this.Match(pattern, RegexOptions.None);

public static bool IsRegexPattern(this string @this)
{
    try
    {
        Regex.Match(string.Empty, @this);
        return true;
    }
    catch (ArgumentException)
    {
        return false;
    }
}
@Unknown6656
Copy link
Contributor

The big trouble I see is the following:

Conditions like you are proposing (sometimes called 'assertions', 'requirements', or 'contracts': dotnet/roslyn#119, #105) would be part of the member signature.
This would imply the following problems:

  • How does the compiler determine valid overloads at compile-time?
    static void M(int i) when (i < 100) => Console.WriteLine("i < 100");
    static void M(int i) when (i > 100) => Console.WriteLine("i > 100");
    
    static void Main()
    {
        M(42);
        M(420);
        // How does the compiler determine which method 'M' should be called?
        // The compiler needs to know this to emit the correct CIL instruction.
    }
  • How would reflection work on these members?
  • What happens if you try to call a member where no contract is met? e.g:
    static void M() when (false) => Console.WriteLine("M");
    
    static void Main()
    {
        M(); // Exception? Ignored? Compiler Error?
    }
  • If method contracts are part of the signature, how do we handle the same problems Java has with their checked-exceptions feature?

And these are the only issues I could think of in the first few moments of reading your proposal. I am sure that "veteran" C# designers will find more issues than I have.

@YairHalberstadt
Copy link
Contributor

@Unknown6656 I don't think the proposal is for these to be part of the signature, or even a contract. It's just a filter.

I think that is the real problem with this proposal. These filters are just code. They're not special code. It's just an ordinary if statement that happens to be at the beginning of a method. Why is that so special it demands it's own syntax - it's barely even any shorter.

@KyouyamaKazusa0805
Copy link
Author

@YairHalberstadt Your opinion sounds reasonable, because my original intention is just shorten the code. I think I miss the intention of exception filtering.

Just now I use exception filtering on Sharplab, but the result is quite different than what I thought. To my surprise, the inner implementation of when clause is not just C#-language level, but the IL level (IL uses the filter block)!

Anyway, thanks for your reply.

@KyouyamaKazusa0805
Copy link
Author

I'll close this issue.

@YairHalberstadt
Copy link
Contributor

@Sunnie-Shine
Exactly. When blocks in exceptions and switches do something very special - when they return false, instead of exiting the block, we continue to the next catch block/branch of the switch. This is something that is not possible just by writing an if.

@KyouyamaKazusa0805
Copy link
Author

@YairHalberstadt Now I got it! Thank you so much! 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants