Proposal: Syntax and compiler support for decorator pattern #907
Replies: 3 comments
-
Why must there be any formal contract? It's not that uncommon for a decorator to bypass the implementation for what it has wrapped, e.g. a caching/memoizing decorator. If this behavior is something that you want to enforce within your projects I would suggest writing an analyzer. |
Beta Was this translation helpful? Give feedback.
-
I don't see any visual distinction. Reading the call site code, I wouldn't know whether these guarantees are in place or not. |
Beta Was this translation helpful? Give feedback.
-
Given the frequency that I hear this, we need to rename this repo |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Note: this is my first time making a proposal here. If I have omitted an important part of this process, please let me know. :)
For this proposal, I use the term decorator to mean a function that modifies the behavior of a provided function by wrapping it in additional behavior. It may return a new function or it may execute the function.
Examples
Most of my usage for decorators falls in these categories:
IDisposable
(e.g. may throw exceptions)A real (but simplified) example from work:
Problem
These decorator methods imply that the input function is wrapped or executed, but there is no formal contract guaranteeing this is the case. For example:
In this case, the code compiles, but the intent was violated.
Or, an example showing how the compiler cannot guarantee the input function is executed:
Proposal
I propose syntax indicating that an input function MUST be executed within the scope the method call.
Here, the closure keyword would indicate that the argument must be invoked before the method returns. The logic should be similar to supplying the return value for a method (i.e. must return unless an exception is thrown, etc.).
To support the partial function use case (i.e. filling arguments and returning a function with a smaller argument list), I think we would need an additional keyword that indicates that the return value must be a lambda (method, Action, Func, ...) that guarantees execution of the input function:
Thus, the compiler would ensure that:
Also:
Other considerations
Would multiple closures be allowed as multiple arguments?
public void DoStuff(closure Action<int> fun1, closure Action<int> fun2){ ... }
Can you return an object with the decorated closure as a member variable?
public decorator Tuple<int, Action> WrapStuff(Action<int> function) { return Tuple.Create(10, () => function(10)); }
Or do you use the decorator keyword on the return type?
public Tuple<int, decorated Action> WrapStuff( ... ) { ... }
What about decorating multiple closures?
public void Wrap(Action<int> fun1, Action<string> fun2, out decorated Action funA, out decorated Action funB) ...
What about closures as default arguments?
null
as the default - but how do you guaranteenull
is invoked?What about asynchronous execution?
Task
is complete, the method has been invoked?Extra credit (syntactic sugar)
With closure syntax in place, you could also support closure argument shorthand.
Current syntax:
Proposed syntax (a la groovy):
Note: by allowing closures to come after default arguments (and ensuring no closure can have a default), you could at least ensure that all other arguments are assigned before passing in the lambda:
Beta Was this translation helpful? Give feedback.
All reactions