Skip to content

Proposal: Nested local functions and type declarations #259

Closed
@gafter

Description

@gafter
Member

Extend the languages to support the declaration of functions and types in block scope. Local functions would be capable of using captured variables from the enclosing scope.

Activity

added this to the C# 7 and VB 15 milestone on Feb 5, 2015
alanfo

alanfo commented on Feb 6, 2015

@alanfo

There have certainly been occasions in the past where I've wished that C# supported nested methods which had automatic access to the variables declared in the outer scope without the need to pass them as parameters.

Even in old BASIC programming one could do something similar with the crude but effective GOSUB command.

As we already have anonymous methods and lambda expressions, it doesn't seem much of a conceptual jump to support 'named' nested methods as well so I'd certainly be in favor of that part of the proposal

However, I don't remember ever wishing that I could declare whole types within a method which, unless they were restricted in some way, would add significant extra complexity to the language.

Are there any particular use cases you think such a feature would address?

Incidentally, I know that Java supports something called 'local classes' but, on the rare occasions I've needed to program in that language, I've never found a use for them.

AlgorithmsAreCool

AlgorithmsAreCool commented on Feb 6, 2015

@AlgorithmsAreCool

I think the local function problem is pretty well solved by C#'s closures

void Foo()
{
   int myNumber = 42;
   Predicate localFunction = (int num) =>{
       return num > myNumber
   };
...
    myArray.Where(localFunction);
}

The local class problem isn't one i encounter often, but sometimes i need a narrowly scoped class to fulfill an interface contract. Aside from interface shims i can't think of any good use cases for local classes that are not solved by C#'s anonymous classes already.

alanfo

alanfo commented on Feb 6, 2015

@alanfo

Named nested methods would have one advantage over anonymous methods or lambda expressions in that you wouldn't need to assign them to a compatible delegate before you could invoke them.

As you know, if there's no suitable predefined delegate type in the .NET framework, you have to come up with your own.

On the other hand, you'd need to specify all parameter types because there would be no way that the compiler could infer them.

Anonymous methods also have some restrictions - you can't use params in the parameter list and you can't capture ref or out parameters of the enclosing method. However, it's possible that these same restrictions would also apply to nested methods if the underlying implementation were similar.

mirhagk

mirhagk commented on Feb 6, 2015

@mirhagk

you wouldn't need to assign them to a compatible delegate before you could invoke them.

Action and Func cover any delegates you'll need (unless you have more than 16 parameters which would be giant code smell). And the syntax for doing it really isn't much different:

Func<int,int,int> foo = ((a,b) => 
{
    return a+b;
});
int foo(int a, int b)
{
    return a+b;
}

I don't see a benefit here that justifies the complexity.

I do see somewhat of the point of having the local class (and more importantly struct) simply because anonymous classes have readonly fields, but I don't think there are very many algorithms that actually need them. Most of those algorithms would probably be better off with LINQ and immutable types.

axel-habermaier

axel-habermaier commented on Feb 6, 2015

@axel-habermaier
Contributor

@mirhagk: No, unfortunately they don't. Consider ref, out, pointer, or params parameters. Those are not valid generic arguments and therefore Action and Func can't be used.

alanfo

alanfo commented on Feb 6, 2015

@alanfo

Although Action and Func can deal with most things, they can't deal with ref or out parameters as @axel-habermaier just said:

using System;

delegate void MyDelegate(ref int a);

class Program
{
   static int a = 2;

   static void Main()
   {
       MyMethod();
   }

   static void MyMethod()
   {
       MyDelegate d = (ref int b) => ++b;
       d(ref a);
       Console.WriteLine(a); // 3           
   }
}

If you tried to replace MyDelegate with Func<int, int>, then it wouldn't compile.

If nested methods were introduced, I imagine that the above program would look like this if one uses C# 6.0's 'expression bodied' function feature:

using System;

class Program
{
   static int a = 2;

   static void Main()
   {
       MyMethod();
   }

   static void MyMethod()
   {
       void Nested(ref int b) => ++b;
       Nested(ref a);       
       Console.WriteLine(a); // 3           
   }
}

A bit cleaner, perhaps :)

mirhagk

mirhagk commented on Feb 6, 2015

@mirhagk

Okay that makes sense.

If this is to happen, I'd like to see it in tandem with allowing statements at the top level, ie that class/method definitions are basically treated on the same level as statements. That would allow you to define functions outside of a class, allow for this, and allow statements at the top level (which makes it possible to treat C# as a scripting language, mentioned in #98).

68 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @bbarry@giggio@paulomorgado@qwertie@gulshan

      Issue actions

        Proposal: Nested local functions and type declarations · Issue #259 · dotnet/roslyn