Conversation started Oct 29, 2019 at 21:03.
Oct 29, 2019 21:03
Is the default member access inspection correct? bar = fooSheet.Cells(inputRow, inputColumn).Value2 is coming up as a result. I'm not using the Excel.Range._Default member since I'm explicitly using the Value2 member. What am I missing?
Well, there also is that they introduced a completely new API for 32bit.
You really do not want to do that again today.
That would probably explain why there is so little VB5 code transitioned to VB6 code. At least the API stuff.
@IvenBach It is the indexed one, right?
Indexed one?
ÌndexedDefaultMemberAccessInspection
Oct 29, 2019 21:06
Yes. That is the inspection.
You might want to have a look at the documentation for Range.Cells, which I extended two weeks ago.
To make it short, Cellsreturns a range and has no parameters.
Cells(a,b) is Cells.Item(a,b).
The result is correct and only a hint since default member access for collection access is an understandable and quite transparent use case.
Is that the same for Range, Range.Columns, Range.Rows and pretty much everything else that returns a range object?
I have a braintickle telling me you let me know this already.
Actually, Cells(a,b) is Cells.[_Default](a,b), but that forwards to Item.
Yes, and it is in the documentation, now.
Cells just changes the internal state of the range to consist of single cells.
hmm weird - it says it's merged but this still seems to be the old
^ I've been reading the commit to better grok your examples.
Oct 29, 2019 21:17
Argh, I did not read far enough. It is not transferred yet.
Your example for columnsRange with the 3 explicit Debug.Print was very helpful.
It is merged to master, but they only merge master to life at distant points in time.
Basically, their master is our next.
i have to say that it's kind of confusing
If you're not expecting that behavior.
I usually think of master as the primary trunk and the next / dev / whatever you call it as the growing stem
Oct 29, 2019 21:23
Never realized how pervasive default member access still is. Even after learning what it is and trying to avoid it I have a lot.
Oct 29, 2019 21:34
I think it is OK for collection access as long as you are aware that it happens.
The completely implicit default member access fot Let coercion is the evil one.
The danger is "as long as you are aware that it happens." and it wasn't realizing it was happening. Even with .Cells() I wasn't understanding it.
That is really the most confusing one, along Columns and Rows.
Range.Columns.Item(RowIndex:= ,[ColumnIndex:= ]) is doubly confusing since RowIndex isn't required.
Yes, RowIndex is the relative column index here.
Range.Columns.Item("2:3") barfs while Range.Rows.Item("2:3") is perfectly fine.
Oct 29, 2019 21:40
Oh, you can do that?
Then my changes on the documentation are still uncomplete.
Range.Columns.Item(2).Resize(ColumnSize:=2) is the workaround I've found for that difference.
You can do Range.Columns("B:C").
don't they always have a R1C1 alternate?
Not for this.
@M.Doerner WTF... I would have never thought of doing that. #TIL.
Oct 29, 2019 21:42
how fun
At least, as far as I know.
Excel is stranger than I realized.
See, I thought it only works for the Columns one.
It kinda-sorta make sense.
In my ignorance, I did write a routine to convert a number into a letter for accessing the column. It really chafes me that I had to do it myself when it should have been provided by Excel OM.
Oct 29, 2019 21:43
You surprised me with the Rows equivalent.
(of course, now that I've written this, I'll probably learn about a super secret sauce way of converting a number to letter)
docs.microsoft.com/en-us/office/vba/api/… was my derp moment when I found out about it.
um. That presupposes there's a formula, doesn't it?
(i'm just using it for addressing)
I only found out about the Columns version when rewriting the documentation for Item.
but I guess I could just wrap it with "=" & whatever, convert it then strip the =.... Clunky.
Oct 29, 2019 21:49
^ I know it's not always applicable.
I use formulas with cell references so for me it was a no-brainer.
That's an example of one responsibility too much right there
How so?
well, I wanted a conversion from A1 to R1C1 style (or vice versa)
but to use that function, I have to make a formula, then strip it away to get the result I wanted.
Yeah.
Now I see what you're saying.
in actuality, I should be calling Application.ConvertColumn(), whatever
and the Application.ConvertFormula() could then call the Application.ConvertColumn() as part of its conversion.
e.g. do one thing only and do it well.
but it's OK! Excel OM is totally intuitive! Fun! Simple!
Oct 29, 2019 21:57
I think Rows, Columns and Cells should really return Ranges and Item should always work as for single cell ranges.
However, that will never change.
Regarding a For Each cell in FooBarArea depending on how FooBarArea is originally set that determines whether it's looping through each Range.Row, Range.Column, or Range.Cells?
Yes
If it comes from someRange.Columns, it will iterate over the columns, for someRange.Rowsover the rows, both times only over the first area, and for someRange.Cells`over all individual cells.
Quite enlightening if you're not expecting that. So many times I've done set foo = BarSheet.Range("A1:D15") without realizing implicitly .Cells was part of the For Each loop.
That is why it makes sense to always iterate over FooBarArea.Cells if you want individual cells.
32 mins ago, by IvenBach
The danger is "as long as you are aware that it happens." and it wasn't realizing it was happening. Even with .Cells() I wasn't understanding it.
Oct 29, 2019 22:09
No, there is no implicit cells.
Now I am though.
If it's omitted it's implied, as far as I've understood.
Worksheet.Range just returns a range consisting of single cells.
No, you can save soemRange.Comlumnsin a range variable and iterate over it later.
That would iterate over the column ranges.
The kind of iteration behaviour and behaviour of Item is internal state of the range.
Yes, exactly.
I'd never understood all that adequately before to understand it correctly.
Oct 29, 2019 22:12
BTW, this is bad API design.
Because .Item get's really confusing and isn't actually doing what its claiming?
You basically have subtypes of Range violating the Liskov substitution principle.
Ah. You can't substitute a range object that a fooRange.Columns for a bar.Range.Rows and get the same behavior.
Whenever you see a range, Item should do an equivalent thing for the same parameters supplied.
^^Exactly
I also was not aware of this until recently.
@M.Doerner :click: That's what you meant.
Oct 29, 2019 22:14
I always just took ranges as parameters and never guarded against such differences.
Neither have I.
Then again I'm really the only one using my own code.
When the methods are only private, i is OK, because you will probably not produce bad ranges in your own code in the module, but for public ones, it might make sense to guard against it.
Well, thinking about this strange behaviour of Range I think one understands why there is the L in SOLID.
The most stupid thing about this mess is that supplying both arguments to Item for a range obtained via Columns actually causes an error.
Public Sub TestingVariousRanges()
    Dim sourceArea As Range
    Set sourceArea = Sheet1.Range("A1:J7")

    Dim rowRange As Range
    Set rowRange = sourceArea.Rows

    Dim columnRange As Range
    Set columnRange = sourceArea.Columns

    Dim cellsRange As Range
    Set cellsRange = sourceArea.Cells

    PrintNthItem rowRange, 1
    PrintNthItem columnRange, 1
    PrintNthItem cellsRange, 1
End Sub

Private Sub PrintNthItem(ByVal printRange As Range, ByVal NthItem As Long)
    Debug.Print printRange.Item(NthItem).Address
@M.Doerner ^ That returned the results I was expecting. Thanks for this enligtenment.
You are welcome!
 
Conversation ended Oct 29, 2019 at 22:23.