I only use VBA occasionally, and every time I come back to it I get caught out by some variation of the following:
I have a Range
object, currentCell
, that I use to keep track of what cell I'm working with in the spreadsheet. When I update this to point to a different cell, I write:
currentCell = currentCell.Offset(ColumnOffset:=1)
The problem is that I've forgotten the Set
keyword, so what the above line actually does is use the default property of the Range
objects:
currentCell.Value = currentCell.Offset(ColumnOffset:=1).Value
So the contents of the current cell are overwritten by what's in the new cell, and my currentCell
variable hasn't changed to point to a new cell, and I get filled with rage as I realize I've made the same mistake for the hundredth time.
There probably isn't a better answer than to put a post-it on my monitor saying "Have you remembered to use Set today?", but if anyone has any suggestions to help me, I'd appreciate hearing them. In particular:
- Is there any way to turn on warnings when you implicitly use default properties? I have never used them like this on purpose, I'd always call
Range.Value
if that's what I meant. - Is there any good practice for marking variables as "this should only be used to read from the spreadsheet"? In most code I write, almost all my variables are for gathering data, and it would be handy to get a warning if something starts inadvertently editing cells like this.
Whatever you choose to do, you'll need the post-it note, I'm afraid. After all, setting a range object's value to the value in another cell is a perfectly valid and common thing to do. The code has no way of knowing that you want it to do anything other than what you ask it to.
You could try checking your range object's address before and after you update it to make sure it's different, but if you remember to do that, you would be better off simply using the
set
keyword to update the object the way you intended.Now that this issue has enraged you to the point of posting your question, I imagine that you'll never forget it again, regardless of how much time goes by before your next visit to VBA. So maybe you won't need the post-it note after all.
Maybe write your own custom function and use it instead ?
Can be used like this:
I think enderland has highlighted the basic solution, which is to handle processing multiple cells in a loop. To take it further, I'd suggest using a For Next loop for cycling through cells. Probably on of the most common bits of code I write is something like:
This won't eliminate the need for Set, but may help remind you to use it, while making it clearer what's going on.
It took me a while to understand how you are running into problem since I do not think I have ever had this problem in spite of using range objects for years. After thinking about things, I realized I do the following 100% of the time when working with cells - I use the
offset
orcells
functions constantly - I rarely useSet
to redefine a current variable.If I have a loop I am iterating through to go through the spreadsheet, I may do something like
or
Either of these notations means I almost rarely have to use
Set
with a range object - almost always this happens once (if at all) and indicates the first cell in a range I will iterate over or reference.It is also really clear what the
offset
is - since you specify arow/column
- which makes it really straightforward what is happening in the code and easier to track since it references a single cell. You don't have to track down and trace backwards to the last 3 places you update acurrentCell
Range
object.Adopting a style of coding using these sorts of styles should eliminate nearly all these errors you are making. I am quite serious when I say I cannot remember ever having made a similar error in all my years coding VBA - I use the
offset
andcells
functions continuously in my code (loops in these examples, but I use similar methods with all other examples in code) rather than setting ranges to new ranges. The side effect is that when you are setting a range in your code, it is almost ALWAYS immediately following aDim
statement and much more clear.I would slightly change the wording on the Post It
"Are you sure you have not forgotten using Option Explicit and Error Handling?"
Otherwise trust me there is no better way! Having said that, I would like to confirm that "Using Set" is the least of your worries. What should be on the top of your main worries is "Writing Good Code" and this doesn't come overnight. It all comes by practice.
My advice to all beginners. Never assume! For example,
.Value
is the default property of the range sois correct. But still avoid using that.
For example, This works.
Now let's try the above code without using the Set command. Try the below code. What happens?
Recommended Read.
Topic: To ‘Err’ is Human
Link: http://siddharthrout.wordpress.com/2011/08/01/to-err-is-human/
No.
Well, you could make your own variable naming convention, à la Making Wrong Code Look Wrong, but you'll still have to check your own code visually and the compiler won't help you do that. So I wouldn't rely on this too much.
A better option is to circumvent the need for repeatedly redifining
currentCell
using.Offset
altogether.Instead, read the entire range of interest to a Variant array, do your work on that array, and then slap it back onto the sheet when you're done modifying it.
Voilà. No use of default properties or anything that could be confused as such. As a bonus, this will speed up your code execution.