Code Focused

C# Goes Back to BASICs with Local Functions

C# finally gets the BASIC GOSUB feature through local functions, but local functions take that GOSUB-like capability up a few notches.

If you're an old-timer like me, you probably remember the original implementations of the BASIC language, including the coveted GOSUB statement. This feature allowed you to temporarily jump to a block of code, do some processing, and return to the point just after the initial jump:

100 PRINT "Enter Your First Name: ";
110 GOSUB 400

200 PRINT "Enter Your Last Name: ";
210 GOSUB 400

300 PRINT "Hello, "; FIRSTNAME$; " "; LASTNAME$
310 END


GOSUB was nice because it allowed you to reuse a chunk of logic without the need to retype that code repeatedly. In more advanced BASIC implementations, named functions could do the same thing. But even in such procedures, having a subordinate, nearby, repeatable block of code was both quick to enter and easy to use.

Visual Basic lost its own GoSub keyword in the move to the .NET Framework, but something similar is now included in C# 7. The feature is called local functions. In truth, these nested functions aren’t like the old GOSUB statement -- they're better! Whereas the old BASIC feature provided little more than a jump destination in its syntax, local functions in C# are full methods, complete with parameters, return values and, if you want, asynchronous execution. The code in Listing 1 uses a local function to append a comma to a string only when needed.

Listing 1: Building a String with Local Functions
string FormatAddress(AddressDetail theAddress)
  string result;

  // ----- Local function that adds a comma when needed.
  string AddComma(string origContent)
    if (string.IsNullOrEmpty(origContent))
      return "";
    else if (origContent.Trim().EndsWith(","))
      return origContent;
      return origContent + ", ";

  // ----- Build an address from parts.
  result = theAddress.Line1;
  if (!string.IsNullOrEmpty(theAddress.Line2))
    result = AddComma(result) + theAddress.Line2;
  if (!string.IsNullOrEmpty(theAddress.Unit))
    result = AddComma(result) + "Unit " + theAddress.Unit;
  if (!string.IsNullOrEmpty(theAddress.City))
    result = AddComma(result) + theAddress.City;
  if (!string.IsNullOrEmpty(theAddress.State))
    result = AddComma(result) + theAddress.State;
  if (!string.IsNullOrEmpty(theAddress.Zip))
    result = (result + " " + theAddress.Zip).Trim();
  return result;

My obvious phobia of the String.Join method notwithstanding, the FormatAddress function could’ve been designed with a traditional external method doing the comma stuff. Because local functions are essentially just methods, it shouldn't be surprising that an external variation would work. But local functions do have other advantages, including the ability to access local variables within their surrounding block. Consider a rewrite of the AddComma local function that references the outer result variable directly instead of through the origContent named parameter:

void AddComma()
  if (string.IsNullOrEmpty(result))
    result = "";
  else if (!result.Trim().EndsWith(","))
    result += ", ";

The calling code would need to change to avoid the lack of return value:

if (!string.IsNullOrEmpty(theAddress.Line2))
  result += theAddress.Line2;

This all looks like magic, but the compiler is in effect adding a by-reference parameter to the local function, and passing the result variable through that reference:

// ----- Here's what the compiler does to the declaration:
string AddComma(ref string result)

// ----- And it's doing this to the calling code:
AddComma(ref result);

Another advantage of local functions is that they're limited in scope. Code outside of the FormatAddress method doesn't know that the AddComma local function even exists. This allows you to craft a method that has a highly specific use case, all without worrying if some future programmer is going to mistake it for a general-purpose function.

As with other recent grammar additions to C#, local functions provide new ways of doing things you could already do before. But in certain coding situations, local functions hide a lot of boilerplate scaffolding behind a direct, clean syntax, and isn't that what C# programming is supposed to be about? You know, more like BASIC.

About the Author

Tim Patrick has spent more than thirty years as a software architect and developer. His two most recent books on .NET development -- Start-to-Finish Visual C# 2015, and Start-to-Finish Visual Basic 2015 -- are available from He blogs regularly at

comments powered by Disqus


  • Multi-Class Classification Using PyTorch: Model Accuracy

    Dr. James McCaffrey of Microsoft Research continues his four-part series on multi-class classification, designed to predict a value that can be one of three or more possible discrete values, by explaining model accuracy.

  • Python in VS Code Adds Data Viewer for Debugging

    The January 2021 update to the Python Extension for Visual Studio Code is out with a short list of new features headed by a data viewer used while debugging.

  • GitHub Ships Enterprise Server 3.0 Release Candidate

    It's described as "the biggest ever change to Enterprise Server," with improvements to Actions, Packages, mobile, security and more.

  • Attacks on .NET Apps Grow in Number, Severity, Says Security Firm

    .NET apps were found to have more serious vulnerabilities and suffer more attacks last year, according to data gathered by Contrast Labs.

Upcoming Events