Surely you know about public, protected, internal and private. They are access modifiers often used in Object-Oriented Programming which indicate from where members can be accessed. If you’ve been following this blog you might have noticed I am a big fan of encapsulation. Previously I discussed how anonymous functions can be used to encapsulate reuseable logic within the scope of one function. This inspired me to look for more ways in which lambdas can be used for improved encapsulation.
Private access is the least permissive access level. Private members are accessible only within the body of the class or the struct in which they are declared. – msdn (.NET)
Some languages go a step further and support static locals, which allow a value to be retained from one call of a function to another with a static lifetime. The variable can only be accessed from within the function scope where it is declared. I have yet to find a language which supports the same, but with instance lifetime. Such a variable would only be visible to a single method within a single instance.
Function private?
Let’s call such a hypothetical accessibility ‘function private’. When would you use it? Consider those annoying light bulbs that burn out just as they’re turned on.

The _lifeTime variable is only relevant to the SwitchOn method. Notice how C# already offers a way to write the IsOn property in a concise way by using an auto-implemented property. This actually already limits the scope of its backing field beyond private! The auto-generated backing field can only be accessed from the getter and setter.
class LightBulb { public bool IsOn { get; private set; } private int _lifeTime = 100; public void SwitchOn() { if ( _lifeTime - 1 >= 0 ) { --_lifeTime; IsOn = true; } } public void SwitchOff() { IsOn = false; } }
What if the following would be possible? It would encapsulate lifeTime just to the scope where it’s needed.
public void SwitchOn() { private int lifeTime = 100; // function private variable // private static int staticVar; // add 'static' to create a static local if ( lifeTime - 1 >= 0 ) { --lifeTime; IsOn = true; } }
Lambda scope
A lambda is something peculiar. It can be used to create delegates, but how do they work? What happens behind the scenes? I asked the question on Stack Exchange, and got some really insightful answers. Relevant to this discussion are the following two points:
- The method that backs the delegate for a given lambda is always the same.
- The method that backs the delegate for “the same” lambda that appears lexically twice is permitted to be the same, but in practice is not the same in .NET 4.0.
The fact that every lambda has a unique backing method gives the possibility to use it as an identifier of the scope where it is defined.
Unsafe implementation
By ab(using) this behavior I was able to create the following working implementation. The Private class creates and keeps track of its instances by linking them to the delegates passed to the static constructor methods. The first time the method is called the instance is created. Subsequent calls the instance is retrieved by doing a lookup in static dictionaries based on the passed arguments.
public void SwitchOn() { Private<int> lifeTime = Private<int>.Instance( () => 100, this ); // function private // Private<int> staticVar = Private<int>.Static( () => 0 ); // static local if ( lifeTime.Value - 1 >= 0 ) { --lifeTime.Value; IsOn = true; } }
Why is it unsafe?
- This behavior is not guaranteed to be supported in later versions of .NET. As mentioned before: “The method that backs the delegate for “the same” lambda that appears lexically twice is permitted to be the same, but in practice is not the same in .NET 4.0.”
- Objects which use the code as it is now are never garbage collected. Using weak references could solve this issue. It seems a dictionary with weak references already exists.
- There is a small performance overhead doing the dictionary lookups. Ideally this feature would be supported at compile time.
I would think the next logical step would be for you to learn about closures. Apparently C# 3.0 supports them.