To my understanding, both local functions and private methods serve merely as implementation details - helpers for public methods. Why would I want to choose one over the other?
When using a private method, I create a semantic relation between the object and the method (although not seen from the outside), which is not always justified. That is why my first instinct is that local functions are the way to go unless more than one public method uses it, in which case I would go with private methods.
But are there any objective reasons to favor one of them? Are there any situations where one is preferable over the other? What are the pros and cons of using any of them?
Private methods are useful for breaking tasks up into smaller parts, or for preventing duplication of code which is needed often by other methods in a class, but should not be called outside of that class.
Local functions are methods of a type that are nested in another member. They can only be called from their containing member. Local functions can be declared in and called from: Methods, especially iterator methods and async methods. Constructors.
Generally you should expose as little as possible and make everything private that is possible. If you make a mistake and hide something you should be exposing, no problem, just make it public.
Private functions are defined as “a means of gathering individuals for the purpose of deliberation, education, instruction, entertainment, amusement, or dining, where specific invitation is a prerequisite to entry and where the event is not intended to be open to the public.” Houston, Tex., Ordinance 2006-1054 art.
It is all about code readability. Looking at the motivation of local function
Local functions make the intent of your code clear. Anyone reading your code can see that the method is not callable except by the containing method. For team projects, they also make it impossible for another developer to mistakenly call the method directly from elsewhere in the class or struct.
the main reason for local function is to give the intent: This code is only for this method; do not reuse it from other places. Stated otherwise: Private methods signal their potential reuse from other class methods.
There are some more use cases behind this language feature as discussed in the Roslyn-Rep here.:
- It is very common to write a helper method that is only used from one place, but it makes the code less clear to the reader because the association between the helper function and the thing it is helping is not explicit. Local functions makes the association part of the syntax.
- An iterator method that validates its arguments (write a non-iterator function to validate the arguments, and then return the result of invoking a local iterator function)
- A Task-returning method that has no async machinery in the common case where it doesn't need to "go async"
- You are writing a method that returns an array, but want the syntactic convenience of the iterator method syntax (yield return).
These use cases are explained in the Blog Post https://devblogs.microsoft.com/premier-developer/dissecting-the-local-functions-in-c-7/
Sometimes logic is huge and contains many repetitions, such as ...
public void ValidateCustomer(Customer customer){
if( string.IsNullOrEmpty( customer.FirstName )){
string error = "Firstname cannot be empty";
customer.ValidationErrors.Add(error);
ErrorLogger.Log(error);
throw new ValidationError(error);
}
if( string.IsNullOrEmpty( customer.LastName )){
string error = "Lastname cannot be empty";
customer.ValidationErrors.Add(error);
ErrorLogger.Log(error);
throw new ValidationError(error);
}
... on and on...
}
Such repetition can be replaced with local function,
public void ValidateCustomer(Customer customer){
void _validate(string value, string error){
if(!string.IsNullOrWhitespace(value)){
// i can easily reference customer here
customer.ValidationErrors.Add(error);
ErrorLogger.Log(error);
throw new ValidationError(error);
}
}
_validate(customer.FirstName, "Firstname cannot be empty");
_validate(customer.LastName, "Lastname cannot be empty");
... on and on...
}
If you look closely, you don't have to pass parameters to local function as they can reference everything in enclosing function, you have to only pass changed parameters. If you write private methods, you will have to pass many number of parameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With