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

Permit declaring an extension method in a non-static class #16271

Closed
gafter opened this issue Jan 5, 2017 · 13 comments
Closed

Permit declaring an extension method in a non-static class #16271

gafter opened this issue Jan 5, 2017 · 13 comments

Comments

@gafter
Copy link
Member

gafter commented Jan 5, 2017

Please relax the language specification so that a (static) extension method may be declared in a class that is not static.

class SomeRandomClass
{
    void SomeRandomMethod(SomeType x)
    {
        x.HelperExtensionMethod();
    }

    static void HelperExtensionMethod(this SomeType x) {}
}
@alrz
Copy link
Member

alrz commented Jan 6, 2017

Could it bo non-static? A use case that I've encountered is in cross-language analyzers, e.g.

internal abstract class AbstractAnalyzer : ...
{
  // ...
  private void Analyze(SyntaxNode node)
  {
     if (node.IsApplicable(...))
     {
     }

     var newNode = node.ToSomethingElse();
  }

  protected abstract bool IsApplicable(this SyntaxNode node);
  protected abstract SyntaxNode ToSomethingElse(this SyntaxNode node);
}

@gafter
Copy link
Member Author

gafter commented Jan 6, 2017

@alrz that is a different feature request.

@jnm2
Copy link
Contributor

jnm2 commented Jan 6, 2017

How about relaxing further to allow extension methods in nested classes as well? This restriction is frustrating once in a while in general and frustrating frequently in C# scripts like Cake, where there is no way to declare an extension method.

@alrz
Copy link
Member

alrz commented Jan 6, 2017

@jnm2 That would be #9139.

@jnm2
Copy link
Contributor

jnm2 commented Jan 6, 2017

If we can't hit both, I'd prefer #9139 done over this because it relieves more pressing practical issues.

@alrz
Copy link
Member

alrz commented Jan 6, 2017

@gafter A minor point. Since "extension everything" is already queued up in the backlog, would it make sense to double down on regular extension methods?

class SomeRandomClass
{
    void SomeRandomMethod(SomeType x)
    {
        x.HelperExtensionMethod();
    }
   extension class SomeTypeExtensions : SomeType
   {
        public void HelperExtensionMethod() {}
   }
}

I think it even reads better (and also addresses #9139), plus all the goodies from #11159 (e.g. extension properties etc). I think actually the restriction is reasonable. Mixing extension/member methods doesn't seem to be as useful and structured as "extension everything" IMO.

@timopomer
Copy link

yea i never understood that one, this wouldnt break anything either! +1

@paulomorgado
Copy link

Would the recommendation to not define extension methods to extend on null still be in place?

For example, will string.IsNullOrEmpty() and string.IsNullOrWhiteSpace() be transformed into extension methods?

@alrz
Copy link
Member

alrz commented Jan 9, 2017

@paulomorgado That would be a breaking change because in that case, the following will no longer compile,

using static String;
class C {
  void F() { 
    if(IsNullOrEmpty("")) {}
  }
}

@timopomer
Copy link

@paulomorgado if the string is null you loose access to the non static functions in string, if its static you loose access to the this instance of the proposed extention method.

these days we need to create (useless wrappers honestly) for no reason

using System;
class stringwrapper{
  public string innerstring = null;
  public stringwrapper(string inp){this.innerstring = inp;}
  
  public bool isWhiteSpace() => this.innerstring == " ";

}
static class uselessStaticClass
{
    public static bool isNullOrWhiteSpace(this stringwrapper gottenVariable)=>gottenVariable.innerstring == null||gottenVariable.isWhiteSpace();
    
}
class MainClass {
  public static void Main (string[] args) {
stringwrapper a = new stringwrapper(" ");
Console.WriteLine($"a.isNullOrWhiteSpace(): {a.isNullOrWhiteSpace()}");
Console.WriteLine("------------");
stringwrapper b = new stringwrapper("hey");
Console.WriteLine($"b.isNullOrWhiteSpace(): {b.isNullOrWhiteSpace()}");
Console.WriteLine("------------");
stringwrapper c = new stringwrapper(null);
Console.WriteLine($"c.isNullOrWhiteSpace(): {c.isNullOrWhiteSpace()}");

  }
}

@paulomorgado
Copy link

@alrz, good point! Changing any static method to an extension method would be a breaking change due to using static.

So, I guess that this will be used only in new methods.

But, back to my question, does the recommendation to treat null instances in extension methods as if it was an instance method (throw NullReferenceException) still holds?

@sharwell
Copy link
Member

sharwell commented Jan 9, 2017

@paulomorgado The issue of null instances seems unrelated to this issue. In this issue, no changes are being suggested to the extension methods themselves, only to where they are allowed to be defined. Any guidance you currently follow on the topic of null handling shouldn't need to change.

@gafter
Copy link
Member Author

gafter commented Aug 24, 2017

We are now taking language feature discussion in other repositories:

Features that are under active design or development, or which are "championed" by someone on the language design team, have already been moved either as issues or as checked-in design documents. For example, the proposal in this repo "Proposal: Partial interface implementation a.k.a. Traits" (issue 16139 and a few other issues that request the same thing) are now tracked by the language team at issue 52 in https://github.com/dotnet/csharplang/issues, and there is a draft spec at https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md and further discussion at issue 288 in https://github.com/dotnet/csharplang/issues. Prototyping of the compiler portion of language features is still tracked here; see, for example, https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation and issue 17952.

In order to facilitate that transition, we have started closing language design discussions from the roslyn repo with a note briefly explaining why. When we are aware of an existing discussion for the feature already in the new repo, we are adding a link to that. But we're not adding new issues to the new repos for existing discussions in this repo that the language design team does not currently envision taking on. Our intent is to eventually close the language design issues in the Roslyn repo and encourage discussion in one of the new repos instead.

Our intent is not to shut down discussion on language design - you can still continue discussion on the closed issues if you want - but rather we would like to encourage people to move discussion to where we are more likely to be paying attention (the new repo), or to abandon discussions that are no longer of interest to you.

If you happen to notice that one of the closed issues has a relevant issue in the new repo, and we have not added a link to the new issue, we would appreciate you providing a link from the old to the new discussion. That way people who are still interested in the discussion can start paying attention to the new issue.

Also, we'd welcome any ideas you might have on how we could better manage the transition. Comments and discussion about closing and/or moving issues should be directed to #18002. Comments and discussion about this issue can take place here or on an issue in the relevant repo.


Please see dotnet/csharplang#301 for this request.

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

No branches or pull requests

6 participants