2

VBA determines that IsEmpty(Range("A1")) implicitly uses the default property, so the expression is the same as IsEmpty(Range("A1").[_Default]). On the other hand, VBA determines that TypeName(Range("A1")) does not use the default property, so the expression is different from TypeName(Range("A1").[_Default]).

Question

How does VBA determine whether the default property is implicitly used or not?

anqooqie
  • 435
  • 3
  • 17
  • What do you exactly mean with the default property. There is no such notion in the docs for `TypeName()` https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/typename-function – Luuklag Oct 03 '18 at 07:27
  • The default property is also called as the default member. I am not sure whether these terms are officially used ones, but I can find [some uses of the terms in SO](https://stackoverflow.com/questions/32996772/is-value-actually-the-default-property-of-the-range-object). In some situations, the default property will be implicitly inserted into the code. For example, `Range` type has `_Default` property as the default property, so `Dim a As Range: Set a = Range("A1"): a = 42` is the same as `Dim a As Range: Set a = Range("A1"): a.[_Default] = 42`. – anqooqie Oct 03 '18 at 07:57
  • Basically what determines if a default member call is made. – QHarr Oct 03 '18 at 08:42
  • As was answered below, what determines whether a default member call is made depends on the types involved (watch for `Variant`). It's indeed confusing, and exactly why writing explicit code (i.e. use `Range.Value`/`.Value2` when you mean to get a cell's value) avoids this confusion. – Mathieu Guindon Oct 03 '18 at 11:49
  • 1
    This is described in sections [5.6.2](https://msdn.microsoft.com/en-us/library/ee156824.aspx) and [5.6.3](https://msdn.microsoft.com/en-us/library/ee199435.aspx) of the VBA language spec. – Comintern Oct 03 '18 at 12:21

1 Answers1

1

IsEmpty expects a data value, not an object type, so you get implicit Let-coercion, which will call the default property to try and get a simple data value.

Rory
  • 32,730
  • 5
  • 32
  • 35
  • How can I know whether a function expects a data value? Is there a way to programmatically check that, or all I can do is to read the documents one by one? – anqooqie Oct 03 '18 at 08:26
  • More specifically speaking, is there some kind of attribute to indicate whether the function expects a data value? – anqooqie Oct 03 '18 at 08:37
  • @anqooqie No, you'd have to read documentation, although it's typically fairly self-evident based on what the function does. Better yet, specify a property if you want a property. – Rory Oct 03 '18 at 08:55
  • 1
    I don't think this is correct. Take the procedure `Sub Test(arg As Variant): Debug.Print TypeName(arg): End Sub` and call it with `Test Range("A1")`. There is coercion occurring, but it is to a `Variant` and the default member is *not* called (`TypeName` outputs "Range"). The signature of the parameter list is identical, so there's no reason to think that the argument is coerced differently for `IsEmpty`. If there's a default member call, it's done internally in the `IsEmpty` function. – Comintern Oct 03 '18 at 12:37
  • @Comintern that's what I thought I said? I wasn't suggesting that the coercion occurred *prior* to the variable being passed to the function. – Rory Oct 03 '18 at 12:46
  • Variant arguments are not let-coerced. See [5.3.1.11](https://msdn.microsoft.com/en-us/library/ee156838.aspx): "If the declared type of the parameter is Variant, a reference parameter binding is defined within the procedure being invoked, with the same name as the parameter, referring to the variable referenced by the argument’s expression. This reference parameter binding is treated as having a declared type of Variant, except when used as the within Let-assignment or Set-assignment, in which case it is treated as having the declared type of the argument’s referenced variable." – Comintern Oct 03 '18 at 13:12