7 Replies - 10874 Views - Last Post: 26 October 2012 - 07:22 AM

#1 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2220
  • View blog
  • Posts: 4,671
  • Joined: 11-December 07

Arrays of Sub

Posted 26 October 2012 - 05:00 AM

This is a mess I shouldn't have got into in the first place. But I have so I'm fixing it.

I have a bunch of similar subs that I call one after the other

            method1()
            method2()
            method3()
            method4()
            method5()
            method6()
            method7()
            method8()
            method9()
            method10()



So far so ugly. The real problem is that I have to add exception handling. Basically, any of them could throw an exception. If it does I have to log it and continue with the next one. I only want to code exception handling once not ten times.

As I said, it should never have ended up like this so first I have to get it working. Once I've done that I'll refactor it. I'll make an abstract class that handles the exceptions and move these 10 methods into concrete implementations.

But my interim solution is to make an array of lambdas and iterate over them. I know VB.NET can use either functions or subs as lambdas. The problem lies in that I can work out how to make an array of functions but not an array of subs. What I did was change all those subs to functions and add this:

        Dim methods() As Func(Of Boolean) = {
            AddressOf method1,
            AddressOf method2,
            AddressOf method3,
            AddressOf method4,
            AddressOf method5,
            AddressOf method6,
            AddressOf method7,
            AddressOf method8,
            AddressOf method9,
            AddressOf method10
           }

        For Each f In methods
            Try
                f()
            Catch ex As NamLineNotFoundException
                ' TODO log the exception
            End Try
        Next



It seems to work. I'll make my abstract class and refactor. By the time the client sees it, it will all be pristine.

But I want to know, is it possible to create arrays of subs in the same way I can create an array of functions?

Is This A Good Question/Topic? 0
  • +

Replies To: Arrays of Sub

#2 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon

Reputation: 2290
  • View blog
  • Posts: 9,529
  • Joined: 29-May 08

Re: Arrays of Sub

Posted 26 October 2012 - 05:38 AM

Action(Of T) is a method that doesn't doesn't return anything, so its a Sub.

AddressOf is not a lambda its creates a delegate to a method.

Quote

By the time the client sees it, it will all be pristine.

You're so naive and innocent. :baaa:

This post has been edited by AdamSpeight2008: 26 October 2012 - 05:43 AM

Was This Post Helpful? 1
  • +
  • -

#3 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon

Reputation: 2290
  • View blog
  • Posts: 9,529
  • Joined: 29-May 08

Re: Arrays of Sub

Posted 26 October 2012 - 06:09 AM

Another way using an extension method approach
Public Module Ext
  <Runtime.CompilerServices.Extension()>
  Public Sub ErrorLog(ByVal method As Action)
    Try
      method()
    Catch ex As Exception
      Console.Write(ex.ToString)
    End Try
  End Sub
End Module


But that has the appearance in the code that the error log is happening after the method call.

Imports ConsoleApplication6.Ext
Module Module1

  Sub Main()
    CType(AddressOf DoThis, Action).ErrorLog()
  ' using a lambda statement '
 Dim er As Action(Of Action) = Sub(method As Action)
                                    Try
                                      method()
                                    Catch ex As Exception
                                      Console.WriteLine(ex.ToString)
                                    End Try
                                  End Sub
    er(AddressOf DoThis)
  End Sub
  Public Sub DoThis()
    Console.WriteLine("Hello World! {0}", 0 / 10)
  End Sub
End Module


This makes it clearer that the error logging is for the method called.


Or using inheritance
Public MustInherit Class Doer
  Public Sub DoAction()
    Try
      WhatToDo()
    Catch ex As Exception

    End Try
  End Sub
  Friend MustOverride Sub WhatToDo()
End Class


Then implement the override of the WhatToDo method.

This post has been edited by AdamSpeight2008: 26 October 2012 - 06:16 AM

Was This Post Helpful? 2
  • +
  • -

#4 cfoley  Icon User is offline

  • Cabbage
  • member icon

Reputation: 2220
  • View blog
  • Posts: 4,671
  • Joined: 11-December 07

Re: Arrays of Sub

Posted 26 October 2012 - 06:21 AM

Thanks, that's useful. The inheritance version is my eventual target but I think Action is what I was looking for just now.

So, VB delegates. They always seemed to do what I understand a lambda to be. However, I know that VB has separate concepts of delegate and lambda and I've never been able to get to the bottom of the differences. Any chance you could explain?

Quote

You're so naive and innocent.


Yes, yes I am.
Was This Post Helpful? 0
  • +
  • -

#5 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon

Reputation: 2290
  • View blog
  • Posts: 9,529
  • Joined: 29-May 08

Re: Arrays of Sub

Posted 26 October 2012 - 06:47 AM

Think of a Delegate as type safe GC pointer to a method.
Action and Func of both inherit from Delegate, so you can do the following.
    Dim f1 As Func(Of Integer) = Function() 42
    Dim s1 As Action(Of Integer) = Sub(xx As Integer) Console.WriteLine(xx)
    Dim d As [Delegate]() = {f1, s1}




A lambda is an Expression and doesn't have a type (per se), but get its type from the target type. Similar to what Nothing and Array Initialisers.
Dim l = Function(x As Integer) As Integer
          Return 2* x
        End Function


Doesn't compile as Object isn't a Delegate type, and the lambda could either be
Dim l As Func(Of Integer,Integer)

or
Dim l as Expression(Of Func(Of Integer, Integer)

which returns the expression tree of the lambda.
Then you can do more complex things with the tree then re-compile the expression on the fly.

    Dim f2 As Expressions.Expression(Of Func(Of Integer)) = Function() 42
    Dim result = f2.Compile()


This post has been edited by AdamSpeight2008: 26 October 2012 - 06:50 AM

Was This Post Helpful? 0
  • +
  • -

#6 lucky3  Icon User is offline

  • Friend lucky3 As IHelpable
  • member icon

Reputation: 233
  • View blog
  • Posts: 770
  • Joined: 19-October 11

Re: Arrays of Sub

Posted 26 October 2012 - 06:52 AM

Delegates are type-safe method pointers, meaning they can point only to same signature methods.

Module Module1
    Public Delegate Sub PrintDelegate(ByVal message As String)

    Sub Main()
        Dim message As New PrintDelegate(AddressOf Print)
        Dim printMessage As String = "something"

        message(printMessage)

        'lambda is on the right side of = sign, left side of = is delegate
        Dim lambdaViaDelegate As Func(Of String, String) = Function(x) String.Format("1:{0} 2:{0}", x)

        Console.WriteLine(lambdaViaDelegate(printMessage))

        Console.ReadKey()
    End Sub

    Public Sub Print(ByVal message As String)
        Console.WriteLine(message)
    End Sub
End Module


Was This Post Helpful? 0
  • +
  • -

#7 AdamSpeight2008  Icon User is offline

  • MrCupOfT
  • member icon

Reputation: 2290
  • View blog
  • Posts: 9,529
  • Joined: 29-May 08

Re: Arrays of Sub

Posted 26 October 2012 - 07:05 AM

More lucky3's PrintDelegate has the type signature String -> ()

so can point to any number of methods have the same type signature.
    Dim del As PrintDelegate = [Delegate].Combine(New PrintDelegate(AddressOf Print),
                                    New PrintDelegate(AddressOf Console.WriteLine))
    del("Hello World!")


Try it and see what happens.
Was This Post Helpful? 0
  • +
  • -

#8 lucky3  Icon User is offline

  • Friend lucky3 As IHelpable
  • member icon

Reputation: 233
  • View blog
  • Posts: 770
  • Joined: 19-October 11

Re: Arrays of Sub

Posted 26 October 2012 - 07:22 AM

...and if you're having Option Strict On, you need to convert it from System.Delegate to PrintDelegate:

        Dim del As PrintDelegate = CType(System.Delegate.Combine(New PrintDelegate(AddressOf Print), New PrintDelegate(AddressOf Console.WriteLine)), PrintDelegate)
        del("Hello World!")


Was This Post Helpful? 0
  • +
  • -

Page 1 of 1