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

Local Extension Methods #799

Closed
scalablecory opened this issue Aug 9, 2017 · 15 comments
Closed

Local Extension Methods #799

scalablecory opened this issue Aug 9, 2017 · 15 comments

Comments

@scalablecory
Copy link

I'd like to see local methods support the same this syntax to create extension methods. So this:

static void Main(string[] args)
{
    Console.WriteLine(Foo(2));
    int Foo(int bar) => bar * 2;
}

Could be written instead as:

static void Main(string[] args)
{
    Console.WriteLine(0.Foo());
    int Foo(this int bar) => bar * 2;
}

This currently fails saying that extension methods must defined in a static class. I see no reason to disallow it in local methods.

@svick
Copy link
Contributor

svick commented Aug 9, 2017

Related issues about expanding where extension methods can be declared: dotnet/roslyn#16271, dotnet/roslyn#4565 and #301.

@jnm2
Copy link
Contributor

jnm2 commented Aug 9, 2017

I don't know if I'd use this, but I'd definitely use static local methods.

@DavidArno
Copy link

@jnm2,

What would you use static local methods for? I can't (yet, until you enlighten me) imagine a use-case for them.

@HaloFour
Copy link
Contributor

In the normal case local methods are already static. Their code generation is quite different from that of lambdas, unless you also have a lambda in the same method that captures scope.

public void M() {
    int x = 1;
    int y = 2;
    int z = add(3);

    int add(int p) => x + y + p;
}

// translated into
    [CompilerGenerated]
    [StructLayout(LayoutKind.Auto)]
    private struct <>c__DisplayClass0_0
    {
        public int x;

        public int y;
    }

    public void M()
    {
        C.<>c__DisplayClass0_0 <>c__DisplayClass0_;
        <>c__DisplayClass0_.x = 1;
        <>c__DisplayClass0_.y = 2;
        C.<M>g__add0_0(3, ref <>c__DisplayClass0_);
    }

    [CompilerGenerated]
    internal static int <M>g__add0_0(int z, ref C.<>c__DisplayClass0_0 ptr)
    {
        return ptr.x + ptr.y + z;
    }

What would marking a local function as static do? Prevent capture?

@jnm2
Copy link
Contributor

jnm2 commented Aug 10, 2017

@DavidArno There have been a whole bunch of times where I refactored parts of a method implementation into static helper methods and then wished I could restrict the visibility to the sole method that needs it because the helper method is really an implementation detail meaningless outside the implementation of that one method.

I begrudgingly polluted the class's large method list rather than making the method non-static and local, because making it a local method didn't enforce method purity with regard to instance state and I really value that guarantee when reading code.

I have a strong desire similarly to nest types inside methods when those types are no more than some method's implementation details. It just keeps the class clean.

@jnm2
Copy link
Contributor

jnm2 commented Aug 10, 2017

@HaloFour It's not for performance, it's for code organization. Restricting what you can do inside the method as you write code, restricting the visibility of an implementation detail to just where it makes sense, and signaling the coding style to the reader.

@HaloFour
Copy link
Contributor

@jnm2

That doesn't really answer my question. What difference does marking the local function as static have? The function itself doesn't carry state, not even this, unless you capture it.

@DavidArno
Copy link

@jnm2,

You did indeed enlighten me 😁

Upvoted therefore as I agree that would be useful.

@HaloFour
Copy link
Contributor

Let me sort of correct myself there. If the local function does capture this the compiler does emit it as an instance method. However, I think that's just an implementation detail. The compiler could just have easily emitted the closure struct and made the reference one of the fields.

My understanding of local functions is that they aren't considered "methods" in that they don't really belong to any type. They're logically more like top-level functions that happen to be scoped to only within the declaring method. They support closures via lexical scope but otherwise they are completely independent of the type and method in which they are defined.

@jnm2
Copy link
Contributor

jnm2 commented Aug 10, 2017

@HaloFour

What difference does marking the local function as static have? The function itself doesn't carry state, not even this, unless you capture it.

It provides a compiler error if you reference an instance member or a local or parameter. They won't show up in intellisense. Code you refactor into the static local method will error if you missed something.

That doesn't really answer my question.

Ouch, I'm not sure how I failed you here. 😃 The answer I have is a restatement of what I said already.

@HaloFour
Copy link
Contributor

@jnm2

So ultimately you want static to be used to disable capture. Effectively that'd be lumping local functions in with lambdas in this proposal: #275

@jnm2
Copy link
Contributor

jnm2 commented Aug 10, 2017

@HaloFour Yes, contrary to what I thought back when I saw #275, I guess there have been a few times when I've thought about expressing a static lambda. Both would be cool but if I had to choose I'd definitely pick local methods.

@jnm2
Copy link
Contributor

jnm2 commented Aug 10, 2017

I wonder if this would go well with @tannergooding's static delegates.

@scalablecory
Copy link
Author

Thread jacked, closing issue.

@jnm2
Copy link
Contributor

jnm2 commented Aug 10, 2017

@scalablecory I'm sorry, not my intention. Did you want local extension methods to be non-static, able to capture locals and parameters?

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

5 participants