12

I am working on an legacy VBA/Excel app and stumbled over some lines of code where a long string (read from a file) is cut into pieces. Those lines look like this:

 Range("E16").Value = Mid(line, 49, [6])

Obviously, writing [6] means taking 6 characters, but I never saw this syntax to put square brackets around a number.

I did some tests and found out that putting those square brackets doesn't do any obvious to the number

Dim x As Double
x = 5.1
Debug.Print [2], [3.1], [-5], x
Debug.Print [3.1] * [x] * [-5]

>>  2             3.1          -5             5.1 
>> -79.05 

So, no truncation, no rounding, no abs-value.
I did some more tests to check if it does some magic similar to putting parentheses around a variable to prevent modifying a value that is passed by reference, but that's not the case:

    x = 5.1: test2 x: Debug.Print x
    x = 5.1: test2 (x): Debug.Print x
    x = 5.1: test2 [x]: Debug.Print x

Sub test2(ByRef y As Double)
    y = y * 2
End Sub

>> 10.2 
>> 5.1
>> 10.2

Surprised that the compiler even accepts this syntax: What is the meaning of using those brackets?

FunThomas
  • 23,043
  • 3
  • 18
  • 34

1 Answers1

16

Square brackets in VBA/VB6 are used for accessing "foreign identifiers", i.e. identifiers that would otherwise not be legal. For example:

Public Enum Foo
    Some
    Thing
    [Some Thing] ' please don't do this
End Enum

And hidden members whose name begins with an underscore:

Public Property Get NewEnum() As IUnknown
    Set NewEnum = myCollection.[_NewEnum]
End Property

However in the context of the code in this question, the square brackets are, as Scott indicated, essentially shorthand notation for [_Global].Evaluate, which ultimately resolves to Application.Evaluate... assuming we're not in a Worksheet module's code-behind, in which case it's shorthand for Worksheet.Evaluate - and both return a Variant, which means any chained member calls are blind, late-bound calls resolved at run-time: Option Explicit can't save you from a typo.

That's why Rubberduck (an open-source VBIDE add-in project I manage / contribute to) resolves them as "runtime expressions":

Rubberduck's context-sensitive toolbar showing 'A1' as a 'runtime expression'

In other words this:

Range("E16").Value = Mid(line, 49, [6])

Could just as well be written like this:

[E16] = Mid(line, [49], [6])

...which is arguably terrible code with a ton of redundant implicit operations going on.

There is never, NEVER any reason whatsoever to square-bracket an integer literal: it's nothing more than a rather roundabout way to turn an Integer literal into a Double (since worksheet numeric values are Variant/Double):

Debug.Print TypeName(42)
Integer

Debug.Print TypeName([42])
Double

Which is much better off done with an explicit conversion:

Debug.Print TypeName(CDbl(42))
Double

...or even with a (gasp) type hint:

Debug.Print TypeName(42#)
Double
Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • 3
    Also note-worthy in Excel is the fact that `Application.Evaluate` returns a `Variant`, so it has a nasty little side effect of implicitly removing the strong typing. The other side effect is that the literal for the number is implicitly converted to a `String` before being passed to evaluate, so the number you end up with is dependent on locale settings. – Comintern Feb 07 '19 at 18:16
  • 2
    This is very nitpicky but an implicit reference outside the worksheet's code-behind actually accesses `[_Global].Evaluate()`, not `Application.Evaluate()`. I'm sure it resolves to the same implementation but want to point this out because 1) that's yet another level of implicit operation and 2) it may lead to surprises when the `Evaluate()` in one context does X but in other context, does Y. – this Feb 07 '19 at 19:07
  • Small clarification; if `[blah]` is shorthand for `[_Global].Evaluate(blah)`, then why do we type `[E16]` to mean `.Evaluate("E16")` and not `["E16"]` with `"` speech marks. Does this work like [bang notation](https://stackoverflow.com/a/15958981/6609896) and always pass what's between brackets as a string literal? i.e. `[49]` is actually equivalent to `[_Global].Evaluate("49")` – Greedo Jan 04 '20 at 23:34
  • 1
    @Greedo `Evaluate` takes a string argument, yes. But whether a bracketed expression translates to a call to the host application's `Evaluate` method depends on a number of things, including whether the host has such a method - lookup "foreign identifiers" in MS-VBAL language specs for more info about them. – Mathieu Guindon Jan 04 '20 at 23:40