<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Range Variables and Deleted Cells</title>
	<atom:link href="http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/feed/" rel="self" type="application/rss+xml" />
	<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/</link>
	<description>Daily posts of Excel tips…and other stuff</description>
	<lastBuildDate>Wed, 15 May 2013 18:27:05 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
	<item>
		<title>By: Nigel Heffernan</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85623</link>
		<dc:creator>Nigel Heffernan</dc:creator>
		<pubDate>Mon, 03 Sep 2012 17:19:21 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85623</guid>
		<description><![CDATA[Rob - 

Thank for confirming that... And the point about row insertions.

It worries me, that so few developers know about reverse-traversing collections when there&#039;s a deletion operation. Or, indeed, that *any* coder hasn&#039;t met the problem and thought about the implications.

Outside that specific coding point, everybone considers the question: &quot;What else will be affected by this action?&quot; so it&#039;s instinctive to think of ranges and names outside the loop which may be affected by deletions and insertions.

At least, I hope it is.]]></description>
		<content:encoded><![CDATA[<p>Rob &#8211; </p>
<p>Thank for confirming that&#8230; And the point about row insertions.</p>
<p>It worries me, that so few developers know about reverse-traversing collections when there&#8217;s a deletion operation. Or, indeed, that *any* coder hasn&#8217;t met the problem and thought about the implications.</p>
<p>Outside that specific coding point, everybone considers the question: &#8220;What else will be affected by this action?&#8221; so it&#8217;s instinctive to think of ranges and names outside the loop which may be affected by deletions and insertions.</p>
<p>At least, I hope it is.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: frank</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85608</link>
		<dc:creator>frank</dc:creator>
		<pubDate>Mon, 03 Sep 2012 04:30:06 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85608</guid>
		<description><![CDATA[Quote p. 414: &quot;the Item property is the default property of the Range object&quot;.

Maybe it should be &quot;the default property of the Range is the  reference   to an item&quot;.]]></description>
		<content:encoded><![CDATA[<p>Quote p. 414: &#8220;the Item property is the default property of the Range object&#8221;.</p>
<p>Maybe it should be &#8220;the default property of the Range is the  reference   to an item&#8221;.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: frank</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85607</link>
		<dc:creator>frank</dc:creator>
		<pubDate>Mon, 03 Sep 2012 04:26:27 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85607</guid>
		<description><![CDATA[&lt;&gt;

Rob, you wrote in your book (Excel 2003 VBA p. 414) that &lt;&gt; but maybe one should say the default property of the Range is the  reference &gt;bold\&gt; to an item. A range seems to refer to items without regard for their identity…

Range parents are loveless parents: they don’t see their children for whom they really are. Instead they are concerned with silly references, status if you like. If a child disappears but another one fits the reference, they’re happy to adopt the new child without a care in the world for the first one.  Because most of us are not brought up this way, this (st)range behavior unsettles us. 

Yes, we think it’s a bad pointer but the Range is ruthless enough to accept any new objet the Application objet throws in its arms.]]></description>
		<content:encoded><![CDATA[<p>&lt;&gt;</p>
<p>Rob, you wrote in your book (Excel 2003 VBA p. 414) that &lt;&gt; but maybe one should say the default property of the Range is the  reference &gt;bold\&gt; to an item. A range seems to refer to items without regard for their identity…</p>
<p>Range parents are loveless parents: they don’t see their children for whom they really are. Instead they are concerned with silly references, status if you like. If a child disappears but another one fits the reference, they’re happy to adopt the new child without a care in the world for the first one.  Because most of us are not brought up this way, this (st)range behavior unsettles us. </p>
<p>Yes, we think it’s a bad pointer but the Range is ruthless enough to accept any new objet the Application objet throws in its arms.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Colin Legg</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85573</link>
		<dc:creator>Colin Legg</dc:creator>
		<pubDate>Sat, 01 Sep 2012 09:19:59 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85573</guid>
		<description><![CDATA[Following on from Rob&#039;s point about inserting rows, you can get the same &#039;pending disposal state&#039; range as seen earlier by referencing a range which is then shifted off the worksheet, eg.
&lt;code&gt;
Sub foo()

    Dim r As Range
    
    Set r = Cells(Rows.Count, &quot;A&quot;)
    
    Range(&quot;A1&quot;).Insert shift:=xlShiftDown
    
    Stop
    
End Sub
&lt;/code&gt;]]></description>
		<content:encoded><![CDATA[<p>Following on from Rob&#8217;s point about inserting rows, you can get the same &#8216;pending disposal state&#8217; range as seen earlier by referencing a range which is then shifted off the worksheet, eg.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Sub foo()<br />
<br />
&nbsp; &nbsp; Dim r As Range<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; Set r = Cells(Rows.Count, &quot;A&quot;)<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; Range(&quot;A1&quot;).Insert shift:=xlShiftDown<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; Stop<br />
&nbsp; &nbsp; <br />
End Sub</div></div>
]]></content:encoded>
	</item>
	<item>
		<title>By: Rob Bovey</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85563</link>
		<dc:creator>Rob Bovey</dc:creator>
		<pubDate>Sat, 01 Sep 2012 00:48:18 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85563</guid>
		<description><![CDATA[Nigel:
The only time this issue can become a problem is when you delete a Range object that you have previously set a VBA object variable to reference. If you&#039;re going to be deleting ranges (as opposed to clearing them) in a loop then be sure to use a backwards working For...Each loop instead of a forward working For Each...Next loop. Also be sure to reset any range variables outside the loop that may have been affected by the deletion. If you really need to test a specific variable you can attempt to get its Address within On Error Resume Next and see if it works.

As a note of interest, you can get the opposite problem if you&#039;re inserting rows and don&#039;t do anything to eliminate it. Because everything shifts down when you insert, the next range the loop will evaluate after an insert is the row you just inserted. The following code will create an infinite loop if the value of either cell meets the Mod condition:

    For Each rngCell In Sheet1.Range(&quot;A1:A2&quot;)
        If rngCell.Value Mod 2 = 0 Then rngCell.EntireRow.Insert
    Next rngCell

Dick:
I agree with your theory of how VBA is working with ranges under the covers. As to why the same problem doesn&#039;t happen to the Worksheets collection, my guess is because the Worksheets collection debuted at the same time VBA did, so the folks at Microsoft made them work correctly together (and all other similar collections that appeared then or later). They may have been stuck with some legacy behavior with the grid that caused this range object weirdness. Joel Spolsky would be a good person to answer this question.]]></description>
		<content:encoded><![CDATA[<p>Nigel:<br />
The only time this issue can become a problem is when you delete a Range object that you have previously set a VBA object variable to reference. If you&#8217;re going to be deleting ranges (as opposed to clearing them) in a loop then be sure to use a backwards working For&#8230;Each loop instead of a forward working For Each&#8230;Next loop. Also be sure to reset any range variables outside the loop that may have been affected by the deletion. If you really need to test a specific variable you can attempt to get its Address within On Error Resume Next and see if it works.</p>
<p>As a note of interest, you can get the opposite problem if you&#8217;re inserting rows and don&#8217;t do anything to eliminate it. Because everything shifts down when you insert, the next range the loop will evaluate after an insert is the row you just inserted. The following code will create an infinite loop if the value of either cell meets the Mod condition:</p>
<p>    For Each rngCell In Sheet1.Range(&#8220;A1:A2&#8243;)<br />
        If rngCell.Value Mod 2 = 0 Then rngCell.EntireRow.Insert<br />
    Next rngCell</p>
<p>Dick:<br />
I agree with your theory of how VBA is working with ranges under the covers. As to why the same problem doesn&#8217;t happen to the Worksheets collection, my guess is because the Worksheets collection debuted at the same time VBA did, so the folks at Microsoft made them work correctly together (and all other similar collections that appeared then or later). They may have been stuck with some legacy behavior with the grid that caused this range object weirdness. Joel Spolsky would be a good person to answer this question.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Gary Waters</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85557</link>
		<dc:creator>Gary Waters</dc:creator>
		<pubDate>Fri, 31 Aug 2012 19:21:09 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85557</guid>
		<description><![CDATA[Dick,

  A range object in VBA should behave exactly like in the GUI interface and it is the calculation engine that update&#039;s all the data and cell references (just strings!). Type in cell A12 the formula &#039;=SUM(A1:A10)&#039; or create a named reference pointing to A1:A10. If you delete row one each time, the bottom of the list gets moved up by one until you are left with just one reference range, be it &#039;A1&#039; or &#039;A1:A1&#039;. Delete that and you are left with #REF! error or a named range that points to nothing like in VBA! So what are ranges? Just string tables (addresses). If you delete a row or column, it deletes that data and updates any string tables (addresses) that point to that by offsetting them. Any created range references from VBA into Excel are probably just temporary named references that only VBA can see while it&#039;s code is running. So Excel only updates the address&#039;s in the pointers for ranges.]]></description>
		<content:encoded><![CDATA[<p>Dick,</p>
<p>  A range object in VBA should behave exactly like in the GUI interface and it is the calculation engine that update&#8217;s all the data and cell references (just strings!). Type in cell A12 the formula &#8216;=SUM(A1:A10)&#8217; or create a named reference pointing to A1:A10. If you delete row one each time, the bottom of the list gets moved up by one until you are left with just one reference range, be it &#8216;A1&#8242; or &#8216;A1:A1&#8242;. Delete that and you are left with #REF! error or a named range that points to nothing like in VBA! So what are ranges? Just string tables (addresses). If you delete a row or column, it deletes that data and updates any string tables (addresses) that point to that by offsetting them. Any created range references from VBA into Excel are probably just temporary named references that only VBA can see while it&#8217;s code is running. So Excel only updates the address&#8217;s in the pointers for ranges.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Dick Kusleika</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85545</link>
		<dc:creator>Dick Kusleika</dc:creator>
		<pubDate>Fri, 31 Aug 2012 14:31:29 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85545</guid>
		<description><![CDATA[Hmm, interesting.

I was surprised that the target range was re-evaluated, but maybe I shouldn&#039;t have been.  The Range object is &lt;a href=&quot;http://www.dailydoseofexcel.com/archives/2004/07/07/the-strange-object/&quot; rel=&quot;nofollow&quot;&gt;strange&lt;/a&gt; in that it&#039;s an object and a collection of objects all in one.  Range objects adjust even without loops.

&lt;code lang=&quot;vb&quot;&gt;Sub ShiftingRange()
    
    Dim rRng As Range
    
    Set rRng = Sheet1.Range(&quot;A1:A10&quot;)
    
    Sheet1.Range(&quot;A5&quot;).EntireRow.Delete
    
    Debug.Print rRng.Address
    
End Sub&lt;/code&gt;

will return A1:A9.  So rngTable is just a Range object acting like a Range object.  Here&#039;s my new theory on what&#039;s happening under the covers.

&lt;code lang=&quot;vb&quot;&gt;Sub TestDelCell()
    
    Dim rCell As Range
    Dim rTable As Range
    Dim lLoopCount As Long
    
    Set rTable = Sheet1.Range(&quot;A1:A10&quot;)
    
    &#039;For Each rCell In rTable.Cells
    lLoopCount = 1
    Set rCell = rTable.Cells(lLoopCount)

StartLoop:

        rCell.EntireRow.Delete
    
    &#039;Next rCell
    lLoopCount = lLoopCount + 1
    If lLoopCount &lt;= rTable.Cells.Count Then
        Set rCell = rTable.Cells(lLoopCount)
        GoTo StartLoop
    Else
        GoTo EndLoop
    End If

EndLoop:
    
End Sub&lt;/code&gt;

Here&#039;s why that theory is wrong (or at least incomplete).

&lt;code lang=&quot;vb&quot;&gt;Sub DelSheets()
    
    Dim sh As Worksheet
    
    For Each sh In ThisWorkbook.Worksheets
        If sh.Name &lt;&gt; &quot;Sheet1&quot; Then
            sh.Delete
        End If
    Next sh
            
End Sub&lt;/code&gt;

If For Each just uses an internal counter, this should delete every other sheet.  It should &lt;code lang=&quot;vb&quot; inline=&quot;true&quot;&gt;Set sh = ThisWorkbook.Worksheets(lLoopCount)&lt;/code&gt; but it doesn&#039;t.  It deletes every sheet (leaving Sheet1 so I don&#039;t get an error).  Surely the Worksheets collection is &quot;adjusted&quot; after a deletion just like a Range &quot;collection&quot; is.  I have to believe that For Each compiles down to the same code control structure regardless of the object involved, so why do all the worksheets get deleted but not all the cells?

I can&#039;t think of a better use of a Friday than thinking about this stuff. :)]]></description>
		<content:encoded><![CDATA[<p>Hmm, interesting.</p>
<p>I was surprised that the target range was re-evaluated, but maybe I shouldn&#8217;t have been.  The Range object is <a href="http://www.dailydoseofexcel.com/archives/2004/07/07/the-strange-object/" rel="nofollow">strange</a> in that it&#8217;s an object and a collection of objects all in one.  Range objects adjust even without loops.</p>
<div class="codecolorer-container vb default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Sub</span> ShiftingRange()<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> rRng <span style="color: #151B8D; font-weight: bold;">As</span> Range<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Set</span> rRng = Sheet1.Range(<span style="color: #800000;">&quot;A1:A10&quot;</span>)<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; Sheet1.Range(<span style="color: #800000;">&quot;A5&quot;</span>).EntireRow.Delete<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> rRng.Address<br />
&nbsp; &nbsp; <br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Sub</span></div></div>
<p>will return A1:A9.  So rngTable is just a Range object acting like a Range object.  Here&#8217;s my new theory on what&#8217;s happening under the covers.</p>
<div class="codecolorer-container vb default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Sub</span> TestDelCell()<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> rCell <span style="color: #151B8D; font-weight: bold;">As</span> Range<br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> rTable <span style="color: #151B8D; font-weight: bold;">As</span> Range<br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> lLoopCount <span style="color: #151B8D; font-weight: bold;">As</span> <span style="color: #F660AB; font-weight: bold;">Long</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Set</span> rTable = Sheet1.Range(<span style="color: #800000;">&quot;A1:A10&quot;</span>)<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #008000;">'For Each rCell In rTable.Cells</span><br />
&nbsp; &nbsp; lLoopCount = 1<br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Set</span> rCell = rTable.Cells(lLoopCount)<br />
<br />
StartLoop:<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; rCell.EntireRow.Delete<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #008000;">'Next rCell</span><br />
&nbsp; &nbsp; lLoopCount = lLoopCount + 1<br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> lLoopCount &lt;= rTable.Cells.Count <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Set</span> rCell = rTable.Cells(lLoopCount)<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">GoTo</span> StartLoop<br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">GoTo</span> EndLoop<br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
<br />
EndLoop:<br />
&nbsp; &nbsp; <br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Sub</span></div></div>
<p>Here&#8217;s why that theory is wrong (or at least incomplete).</p>
<div class="codecolorer-container vb default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Sub</span> DelSheets()<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> sh <span style="color: #151B8D; font-weight: bold;">As</span> Worksheet<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> sh <span style="color: #8D38C9; font-weight: bold;">In</span> ThisWorkbook.Worksheets<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">If</span> sh.Name &lt;&gt; <span style="color: #800000;">&quot;Sheet1&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sh.Delete<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span><br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> sh<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Sub</span></div></div>
<p>If For Each just uses an internal counter, this should delete every other sheet.  It should <code class="codecolorer vb default"><span class="vb"><span style="color: #151B8D; font-weight: bold;">Set</span> sh = ThisWorkbook.Worksheets(lLoopCount)</span></code> but it doesn&#8217;t.  It deletes every sheet (leaving Sheet1 so I don&#8217;t get an error).  Surely the Worksheets collection is &#8220;adjusted&#8221; after a deletion just like a Range &#8220;collection&#8221; is.  I have to believe that For Each compiles down to the same code control structure regardless of the object involved, so why do all the worksheets get deleted but not all the cells?</p>
<p>I can&#8217;t think of a better use of a Friday than thinking about this stuff. <img src='http://dailydoseofexcel.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Nigel Heffernan</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85541</link>
		<dc:creator>Nigel Heffernan</dc:creator>
		<pubDate>Fri, 31 Aug 2012 12:44:34 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85541</guid>
		<description><![CDATA[For the record, I&#039;ve reproduced it.

The most disturbing aspect is that checking &lt;CODE&gt;Is Nothing&lt;/CODE&gt; gives no hint that there&#039;s a problem. As far as I know, there&#039;s no way of detecting the problem without raising and trapping an error.

Test in the Debug window prior to deleting the row:
&lt;CODE Lang=&quot;VB&quot;&gt;

?typename(r)
Range

?r is nothing
False

?objptr(r)
266041652 

?r.address
$C$3037
&lt;/CODE&gt;

Test in the Debug window after deleting the row:
&lt;CODE Lang=&quot;VB&quot;&gt;

?typename(r)
Range

?r is nothing
False

?objptr(r)
266041652 

?r.address
---------------------------
Microsoft Visual Basic
---------------------------
Run-time error &#039;424&#039;:

Object required
---------------------------
OK   Help   
---------------------------

&lt;/CODE&gt;

The take-home lesson from this is that I can&#039;t just paste in the same old &lt;CODE&gt;If rng Is Nothing&lt;/CODE&gt; and call my code error-tolerant without a second thought. 


...And a question for Rob Bovey: are there real-world consequences to this, in terms of memory leaks and stability?]]></description>
		<content:encoded><![CDATA[<p>For the record, I&#8217;ve reproduced it.</p>
<p>The most disturbing aspect is that checking</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Is Nothing</div></div>
<p>gives no hint that there&#8217;s a problem. As far as I know, there&#8217;s no way of detecting the problem without raising and trapping an error.</p>
<p>Test in the Debug window prior to deleting the row:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?typename(r)<br />
Range<br />
<br />
?r is nothing<br />
False<br />
<br />
?objptr(r)<br />
266041652 <br />
<br />
?r.address<br />
$C$3037</div></div>
<p>Test in the Debug window after deleting the row:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">?typename(r)<br />
Range<br />
<br />
?r is nothing<br />
False<br />
<br />
?objptr(r)<br />
266041652 <br />
<br />
?r.address<br />
---------------------------<br />
Microsoft Visual Basic<br />
---------------------------<br />
Run-time error '424':<br />
<br />
Object required<br />
---------------------------<br />
OK &nbsp; Help &nbsp; <br />
---------------------------</div></div>
<p>The take-home lesson from this is that I can&#8217;t just paste in the same old</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">If rng Is Nothing</div></div>
<p>and call my code error-tolerant without a second thought. </p>
<p>&#8230;And a question for Rob Bovey: are there real-world consequences to this, in terms of memory leaks and stability?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Rob Bovey</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85504</link>
		<dc:creator>Rob Bovey</dc:creator>
		<pubDate>Thu, 30 Aug 2012 22:46:11 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85504</guid>
		<description><![CDATA[Hi Dick,

I hadn&#039;t really dug into this and when I did it gets interesting in a geeky kind of way. The following test proves that VBA uses rngCell as a throwaway pointer. Notice how I try to set it to refer to A1 right before &quot;Next&quot; and it has no affect.

&lt;code lang=&quot;vb&quot;&gt;
Sub Test()

    Dim rngCell As Excel.Range
    Dim rngTable As Excel.Range
    
    Set rngTable = Sheet1.Range(&quot;A1:A10&quot;)
    
    For Each rngCell In rngTable
        Debug.Print rngCell.Address, rngTable.Address
        rngCell.EntireRow.Delete
        Set rngCell = Sheet1.Range(&quot;A1&quot;)
    Next rngCell

End Sub
&lt;/code&gt;

It also proves that VBA is dynamically updating the target range of the loop (I guess it uses some internal structure when you use somthing like Sheet1.Range(&quot;A1:A10&quot;) directly). In the Immediate Window you get:

$A$1          $A$1:$A$10
$A$2          $A$1:$A$9
$A$3          $A$1:$A$8
$A$4          $A$1:$A$7
$A$5          $A$1:$A$6

Where VBA fails is that its pointer tracking doesn&#039;t reflect the fact that the deletion operation has shifted everything back one position, which causes it to skip items (it seems to go strictly by address). I&#039;m even more convinced this is a bug. It&#039;s items that matter, not the fact the point hits each address one time. If the For...Each construct tracks deletions in the target range correctly there doesn&#039;t seem to be any reason why it can&#039;t adjust its pointer correctly.]]></description>
		<content:encoded><![CDATA[<p>Hi Dick,</p>
<p>I hadn&#8217;t really dug into this and when I did it gets interesting in a geeky kind of way. The following test proves that VBA uses rngCell as a throwaway pointer. Notice how I try to set it to refer to A1 right before &#8220;Next&#8221; and it has no affect.</p>
<div class="codecolorer-container vb default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #E56717; font-weight: bold;">Sub</span> Test()<br />
<br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> rngCell <span style="color: #151B8D; font-weight: bold;">As</span> Excel.Range<br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Dim</span> rngTable <span style="color: #151B8D; font-weight: bold;">As</span> Excel.Range<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Set</span> rngTable = Sheet1.Range(<span style="color: #800000;">&quot;A1:A10&quot;</span>)<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> rngCell <span style="color: #8D38C9; font-weight: bold;">In</span> rngTable<br />
&nbsp; &nbsp; &nbsp; &nbsp; Debug.<span style="color: #151B8D; font-weight: bold;">Print</span> rngCell.Address, rngTable.Address<br />
&nbsp; &nbsp; &nbsp; &nbsp; rngCell.EntireRow.Delete<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #151B8D; font-weight: bold;">Set</span> rngCell = Sheet1.Range(<span style="color: #800000;">&quot;A1&quot;</span>)<br />
&nbsp; &nbsp; <span style="color: #8D38C9; font-weight: bold;">Next</span> rngCell<br />
<br />
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Sub</span></div></div>
<p>It also proves that VBA is dynamically updating the target range of the loop (I guess it uses some internal structure when you use somthing like Sheet1.Range(&#8220;A1:A10&#8243;) directly). In the Immediate Window you get:</p>
<p>$A$1          $A$1:$A$10<br />
$A$2          $A$1:$A$9<br />
$A$3          $A$1:$A$8<br />
$A$4          $A$1:$A$7<br />
$A$5          $A$1:$A$6</p>
<p>Where VBA fails is that its pointer tracking doesn&#8217;t reflect the fact that the deletion operation has shifted everything back one position, which causes it to skip items (it seems to go strictly by address). I&#8217;m even more convinced this is a bug. It&#8217;s items that matter, not the fact the point hits each address one time. If the For&#8230;Each construct tracks deletions in the target range correctly there doesn&#8217;t seem to be any reason why it can&#8217;t adjust its pointer correctly.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Dick Kusleika</title>
		<link>http://dailydoseofexcel.com/archives/2012/08/28/range-variables-and-deleted-cells/#comment-85499</link>
		<dc:creator>Dick Kusleika</dc:creator>
		<pubDate>Thu, 30 Aug 2012 22:02:16 +0000</pubDate>
		<guid isPermaLink="false">http://www.dailydoseofexcel.com/?p=7451#comment-85499</guid>
		<description><![CDATA[I also think it&#039;s an unintended side effect of how For Each is compiled.  It has to be just like For Next where the offset from the start is correct, but since everything shifted it now points to the wrong place.

&lt;code lang=&quot;vb&quot;&gt;For Each rCell in Sheet1.Range(&quot;A1:A3&quot;).Cells
    rCell.EntireRow.Delete
Next rCell&lt;/code&gt;

It must evaluate &lt;code lang=&quot;vb&quot; inline=&quot;true&quot;&gt;Sheet1.Range(&quot;A1:A3&quot;).Cells&lt;/code&gt; and make an array of pointers to each object.  Then it keeps an internal counter for the loop and offsets from the first pointer.  On the second iteration, it would offset +1 from the first pointer, which would point to the new A2 (the previous A3).  But that would mean that the array of pointers would have to be re-evaluated every iteration, which doesn&#039;t seem right.]]></description>
		<content:encoded><![CDATA[<p>I also think it&#8217;s an unintended side effect of how For Each is compiled.  It has to be just like For Next where the offset from the start is correct, but since everything shifted it now points to the wrong place.</p>
<div class="codecolorer-container vb default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> rCell <span style="color: #8D38C9; font-weight: bold;">in</span> Sheet1.Range(<span style="color: #800000;">&quot;A1:A3&quot;</span>).Cells<br />
&nbsp; &nbsp; rCell.EntireRow.Delete<br />
<span style="color: #8D38C9; font-weight: bold;">Next</span> rCell</div></div>
<p>It must evaluate <code class="codecolorer vb default"><span class="vb">Sheet1.Range(<span style="color: #800000;">&quot;A1:A3&quot;</span>).Cells</span></code> and make an array of pointers to each object.  Then it keeps an internal counter for the loop and offsets from the first pointer.  On the second iteration, it would offset +1 from the first pointer, which would point to the new A2 (the previous A3).  But that would mean that the array of pointers would have to be re-evaluated every iteration, which doesn&#8217;t seem right.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
