views:

401

answers:

3

Hello,

I have a function Process(data, f) where data is a normal parameter and f is a function needed to process the data (passed as a delegate to Process)

The signature of f is int f(a,b,c), with a, b, c supplied by Process when it calls the delegate.

Up until here, standard delegate usage.

Now, I have a special but common case where I would like to call Process with a constant f function. So I would like to write SimpleProcess(data, k) so that the caller does not need to create a delegate in this case, just pass the constant k (the only information needed).

So I need to dynamically create a constant function, g(a,b,c) which takes 3 parameters (which are ignored) and always returns k. This has to be done within the SimpleProcess function, so that I can then simply call Process(data, g) from within that function, without the need to rewrite the whole Process function for this special case.

Is this possible, and how can I achieve it?

Thanks.

A: 

Have you considered separating the function into two with the different signatures. I presume that your delegate function will return the value that the constant supplies.

So your delegate version of the method would simply carry out the processing needed to calculate the "constant" value.

    Function Process(ByVal data As Object, ByVal f As MyDelegate) As Object
 Dim k As Integer
 ' Calculate k

 Return Process(data, k)
End Function

Function Process(ByVal data As Object, ByVal k As Integer) As Object
 Dim stuff As Object

 ' do stuff with k
 Return stuff
End Function

Delegate Function MyDelegate(ByVal a As Object, ByVal b As Object, ByVal c As Object) As Integer
Mark
Well yes, I have seperated into Process(data, d) and SimpleProcess(data, k). The "delegate function that will return the value that the constant supplied" is what I am trying to do. I am in SimpleProcess, I have this value k, how do I make my delegate d that always returns k?
Laurent
Reply to your edit: it's the opposite!! The whole point of using the delegate is that the Process function will call it many times with different parameters, therefore returning different values (in the general case) so I cannot simply calculate a constant "first".
Laurent
+2  A: 

EDIT: Okay, I didn't spot the "2005" bit in the title. My original answer is later on (under the line) - here's a complete answer for VB.NET 2005.

You can create a class (or struct, I guess) holding the constant value, and then use AddressOf to convert a function in that type into a delegate. You can make this simpler by creating a Shared function to put these two steps together.

Here's a short but complete program to demonstrate this:

Public Delegate Function Function3 (ByVal x As Integer, _
    ByVal y As Integer, ByVal z As Integer) As Integer

Public Class Constant

    Private value As Integer

    Public Sub New (ByVal value As Integer)
      Me.value = value    
    End Sub

    Public Function ReturnValue(ByVal x As Integer, _
        ByVal y As Integer, ByVal z As Integer) _
        As Integer
      Return value
    End Function

    Public Shared Function CreateFunction _
        (ByVal x As Integer) As Function3    
      Dim c As Constant = New Constant(x)
      return AddressOf c.ReturnValue
    End Function

End Class

Public Module Test
    Public Sub Main
      Dim func As Function3 = Constant.CreateFunction(3)
      Console.WriteLine(func(8, 9, 10))
    End Sub
End Module

In your case you would use it with:

Process(data, Constant.CreateFunction(g))


Original answer

You can use a lambda expression, although with three parameters it won't be terribly nice:

Process(data, Function(x as Integer, y as Integer, z as Integer) g)

Another alternative would be to write a function returning a function which returned a constant:

Public Function Constant(value as Integer) As MyDelegateType
    Return Function(x as Integer, y as Integer, z as Integer) value
End Function

Then call it with:

Process(data, Constant(g))

Apologies if some syntax is slightly off - I'm not a VB person really.

Jon Skeet
Are lambda expressions available in VB.NET 2005? But I agree, it would be very easy with lamda expressions (and trivial in functional languages like OCaml)
Laurent
So basically my problem is: how do I do that in VB.NET 2005, without lambda expressions?
Laurent
No, lambda expressions aren't available in VB 8. You'd probably have to create a class to hold a constant, then use AddressOf to get a delegate referring to a function which ignores its parameters and returns the value.
Jon Skeet
(Unfortunately I hadn't spotted the "VB.NET 2005" in the title. Editing...)
Jon Skeet
Perfect, thanks! So the trick is using a class instance to hold the value outside the function. In your solution I just replaced "return AddressOf c.ReturnValue" with "return new Function3(AddressOf c.ReturnValue)" (both work)
Laurent