[This post is part of a series, “wish-list for future versions of VB“]


IDEA: Reflect on your caller with __CALLER_MEMBER__. Introduce three new “optional parameter defaults” which are called __CALLER_FILE__, __CALLER_LINE__ and __CALLER_MEMBER__. (The names are ugly! We’d like suggestions for better ones!) If a callsite doesn’t provide an argument, then the compiler files it out with the appropriate string/integer/MethodInfo as appropriate.


SCENARIO: You want to write a “log” function, like you did in C++ macros, which prints the current file and line number. This code shows how you might do it. Note how useful it is to have them as “optional parameter defaults”. It lets us write a wrapper function “log(e As Exception)” which passes its caller’s information on down to the underlying function “log(s As String)”.

    Sub log(s As String,
            Optional file As String = __CALLER_FILE__,

            Optional line As Integer = __CALLER_LINE__,
Optional caller As MethodInfo = __CALLER_MEMBER__)

                                            String.Format(“{0}:{1}#{2} – {3}{4}”, file, caller.Name, line, s, vbCrLf),

    End Sub


    Sub log(e As Exception,
            Optional file As String = __CALLER_FILE__,
            Optional line As Integer = __CALLER_LINE__,
            Optional caller As MethodInfo = __CALLER_MEMBER__)

        log(e.Message, file, line, caller)

    End Sub


SCENARIO: You want to save boilerplate code in your property templates, and want to be able to write a general-purpose function “GetMyName()” which returns the name of the property. Currently the best you can do is call MethodBase.GetCurrentMethod. But this feature would allow something more elegant:

    WriteOnly Property p As Integer

        Set(ByVal value As Integer)

            Dim propName = GetMyName()

            log(propName & “:=” & value)

        End Set

    End Property


    Function GetMyName(Optional ByVal caller As MethodInfo = __CALLER_MEMBER__) As String

        If Not caller.IsSpecialName Then Return caller.Name

        Dim prop = (From p In caller.DeclaringType.GetProperties() Where p.GetAccessors().Contains(caller)).FirstOrDefault

        If prop IsNot Nothing Then Return prop.Name

        Return caller.Name

    End Function



Provisional evaluation from VB team: On the one hand, this looks like it’d help a common scenario. On the other hand, it feels like a hack. Also note that it’d be impossible to make it work with late-bound dispatch. Please chime in with your opinions. Do you like this? Can you see other scenarios for it? We think the idea is only worth considering if we here more compelling scenarios, or more compelling demand from users.


Comments (2)

  1. Dzonny says:

    What I like is to have set of operators to get reflection object or name of anything. Like GetType. And to get reflection object and name for current context for simplicity. Have dozen of  special-purposeoperators (GetType, GetPropery, GetParameter; GetTypeName, GetPropertyName, GetParameterName etc.) or have a few general-purpose operators (Get, GetName)? – that’s question. Both has advantages and disadvantages.

    Introducing pseudo-literals (like in PHP) is not bad idea. But make them in two versions – for name and for reflection object. Disadvantage is that pseudo-literal cannot be used for anything out of context.


    Public Sub AcceptsObject(ByVal obj As Object)

       If obj Is Nothing Then Throw New ArgumentNullException(GetName(obj))

    End Sub

    Benefit of this and many other scenarios where name of member must be passed as string is that it is verified by compiler. If I from any reason change the name of the member and forget to change this particular reference to it, the project won’t compile and I know that something is bad in compile-time rather than in run-time.

    This will help solve some scenarios when we are attempting to get executing method but we are getting some completely different method because of some JIT optimization.

    My original idea – http://dzonny.cz/Software/Blog/tabid/93/EntryID/41/language/cs-CZ/Default.aspx

  2. Kevin Ryall says:

    To be honest, this just looks like a more complicated way of achieving the basic ‘NameOf’ requirement outlined by Bill MacCarthy. The name is really all I’d want – the file and line number are not really important to me.

    Being able to get the name of a parameter simply would prevent me having to hard-code the name into the assert calls we use to verify pre-requisites (non-null, etc.).  At the moment, to get a proper error message I have to pass the parameter name as well as the parameter itself to the assertion method, and this is obviously unsafe (although we do have an automated check for wrong names). If we could make the call:

    AssertNonNull(surname, NameOf(surname))

    instead of:

    AssertNonNull(surname, “surname”))

    it would be so much better – as long as the name  evaluation was efficient (done at compile time?).