Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat is the best pattern to curry delegate parameters (using .NET 2.0 or later)?
    text
    copied!<p>Sometimes it is useful to take a method call, complete with parameters, and turn it into a MethodInvoker which will invoke the indicated function with those parameters, without having to specify the parameters at the time. At other times, it's useful to do something similar, but leaving some parameters open. This type of action is called "Currying". What is the best pattern for doing this in VB?</p> <p>It's possible to use lambda expressions in VB 2010, but lambda expressions aren't compatible with edit-and-continue, and the closures they create can have unexpected by-reference behaviors. An alternative approach is to define some generic methods such as shown here:</p> <pre><code>Public Module CurryMagic Delegate Sub Action(Of T1, T2)(ByVal P1 As T1, ByVal P2 As T2) Delegate Sub Action(Of T1, T2, T3)(ByVal P1 As T1, ByVal P2 As T2, ByVal P3 As T3) Class CurriedAction0(Of FixedType1, FixedType2) Dim _theAction As Action(Of FixedType1, FixedType2) Dim _FixedVal1 As FixedType1, _FixedVal2 As FixedType2 Sub Exec() _theAction(_FixedVal1, _FixedVal2) End Sub Sub New(ByVal theAction As Action(Of FixedType1, FixedType2), _ ByVal FixedVal1 As FixedType1, ByVal FixedVal2 As FixedType2) _theAction = theAction _FixedVal1 = FixedVal1 _FixedVal2 = FixedVal2 End Sub End Class Class CurriedAction1(Of ArgType1, FixedType1, FixedType2) Dim _theAction As Action(Of ArgType1, FixedType1, FixedType2) Dim _FixedVal1 As FixedType1, _FixedVal2 As FixedType2 Sub Exec(ByVal ArgVal1 As ArgType1) _theAction(ArgVal1, _FixedVal1, _FixedVal2) End Sub Sub New(ByVal theAction As Action(Of ArgType1, FixedType1, FixedType2), _ ByVal FixedVal1 As FixedType1, ByVal FixedVal2 As FixedType2) _theAction = theAction _FixedVal1 = FixedVal1 _FixedVal2 = FixedVal2 End Sub End Class Class ActionOf(Of ArgType1) Shared Function Create(Of FixedType1, FixedType2)(ByVal theSub As Action(Of ArgType1, FixedType1, FixedType2), ByVal FixedVal1 As FixedType1, ByVal FixedVal2 As FixedType2) As Action(Of ArgType1) Return AddressOf New CurriedAction1(Of ArgType1, FixedType1, FixedType2)(theSub, FixedVal1, FixedVal2).Exec End Function End Class Function NewInvoker(Of FixedType1, FixedType2)(ByVal theSub As Action(Of FixedType1, FixedType2), ByVal FixedVal1 As FixedType1, ByVal FixedVal2 As FixedType2) As MethodInvoker Return AddressOf New CurriedAction0(Of FixedType1, FixedType2)(theSub, FixedVal1, FixedVal2).Exec End Function End Module </code></pre> <p>If I want to create a MethodInvoker which will perform Foo(5, "Hello"), I can create one using</p> <pre><code>MyInvoker = NewInvoker(AddressOf Foo, 5, "Hello") </code></pre> <p>and if I want to turn MyAction(X) into Boz(X, "George", 9), where X is a Double, I can use</p> <pre><code>MyAction = ActionOf(Of Double).Create(AddressOf Boz, "George", 9) </code></pre> <p>All pretty slick, except that it's necessary to have a huge amount of boilerplate code to accommodate different numbers of fixed and non-fixed parameters, and there's nothing inherent in the delegate-creation syntax which makes clear which parameters are fixed and which are non-fixed. Is there a way to improve the pattern?</p> <p><b>Addendum</b>: What is the mechanism if a delegate is created from a struct member function? It appears the delegate gets its own copy of the struct, but I don't know whether that copy is boxed or unboxed. If it's not boxed, replacing CurryAction0 and CurryAction1 with structs would avoid the need to allocate a CurryAction0 or CurryAction1 as a separate heap object when creating the delegate. If it's going to be boxed, though, using a struct would add the overhead of copying the struct to the boxed instance while not saving anything. </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload