The Worksheet.Columns property only accepts the index (column) number as far as I can see in the documentation.
Nowhere in the documentation does it say the Columns
property takes a parameter, and indeed, it would be wrong to mention that, because it doesn't have any:

Like Worksheet.Rows
, Worksheet.Columns
yields a Range
object. So when you "parameterize" it, what's really happening is this:
Set foo = ws.Columns.[_Default](value)
Any argument you provide, get interpreted as arguments to an implicit default member call against the Range
object that was returned by the call to Columns
.
You may have read somewhere that the default member of a Range
is its Value
- and that is not true. The default member of a Range
is a hidden property named [_Default]
(square brackets are required in VBA if you want to invoke it explicitly, because no legal VBA identifier can begin with an underscore), that takes two optional parameters:

When you read ("get") this default property without providing any arguments, this default property does get you the Range.Value
(i.e. a single Variant
value for a single cell, or a 2D Variant
array for multiple cells). When you assign to this default property, you are assigning the Range.Value
.
But when any arguments are provided when reading ("get") this default property, what you get is a call to the very standard Range.Item
indexer property:

So what Columns
does, is simply take your input range, and yield a Range
object laid out in such a way that it can be accessed using a RowIndex
argument - we can prove this using named arguments, which show that this code is illegal:
?Sheet1.Range("A1:C1").Columns.Item(ColumnIndex:=2).Address
>> "wrong number of arguments"
As is this equivalent code:
?Sheet1.Range("A1:C1").Columns(ColumnIndex:=2).Address
>> "error 1004"
Note that the _Default
property yields a Variant
, so the above .Address
member call can only be resolved at run-time (and you don't get any intellisense for it, and the compiler will not flinch at any typo, even with Option Explicit
specified - you will get error 438 at run-time though).
Best stick to safe early-bound land, and pull the returned object reference into a local variable:
Dim foo As Range
Set foo = ws.Columns(1)
Debug.Print foo.Address '<~ early-bound w/intellisense & compile-time validation
TL;DR: You're being prompted for a RowIndex
argument because you are making a call (albeit an implicit one) to a hidden _Default
property that accepts a RowIndex
argument.