<div class="gmail_quote">On Fri, Oct 28, 2011 at 5:32 PM, Matthew Dowle <span dir="ltr">&lt;<a href="mailto:mdowle@mdowle.plus.com">mdowle@mdowle.plus.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

<div class="im"><br>
On Fri, 2011-10-28 at 09:52 -0700, Muhammad Waliji wrote:<br>
&gt; &gt;From the user&#39;s perspective, DT2 &lt;- DT should either be a new copy or<br>
&gt; a new reference.  Anything in between is confusing.<br>
<br>
</div>Agreed. With picky caveat: even in base it&#39;s not at this point the copy<br>
is taken. It&#39;s later: copy-on-write. It&#39;s setkey and := that don&#39;t copy<br>
on write, not the (earlier) &lt;-.<br></blockquote><div><br></div><div>Hmm, I would prefer for these to have the same behavior.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">


<div class="im"><br>
&gt; How about this - add a new argument to data.table(), say max.cols.<br>
&gt; max.cols defaults to a couple orders of magnitude above the initial<br>
&gt; number of columns.  data.table allocates enough memory for max.cols<br>
&gt; column pointers.  If you try to add more than max.cols columns, it is<br>
&gt; either an error, or it creates a copy and produces a warning.<br>
<br>
</div>Very nice idea. To over allocate by default so that := can add columns<br>
fully by reference most of the time seems good to me since there&#39;s a<br>
very low cost to over allocating the vector of column pointers. Create<br>
the (shallow copy) and issue a warning, I&#39;m thinking, not error. The<br>
&quot;max.cols&quot; names seems a bit absolute, could it be &quot;alloc.cols&quot;?  We<br>
could have alloc(DT,2,ncol) or rowalloc(DT,n) and colalloc(DT,n), or<br>
realloc(...) so users can over alloc themselves before a loop that adds<br>
columns or inserts rows.  tables() could also report truenrow, and<br>
truencol as well as nrow and ncol.  What should alloc.cols be, by<br>
default? How about:  max(100,2*ncol)<br></blockquote><div><br></div><div>Fine with me. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
What about as.data.table.data.frame()?  Should that over-allocate, too,<br>
or for speed just change the class attribute as it does now.<br></blockquote><div><br></div><div>Yeah, I think any method of creating a data table should over-allocate.  If people want the speed gains, they can set explicitly set alloc.cols.</div>

<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
Maybe checking NAMED would work, in addition. If NAMED was 0, no need to<br>
warn. Only when NAMED was 1 (or 2) - (not too hot on NAMED) - would the<br>
warning be necessary.<br>
<div class="HOEnZb"><div class="h5"><br>
<br>
&gt;<br>
&gt; On Fri, Oct 28, 2011 at 1:10 AM, Matthew Dowle<br>
&gt; &lt;<a href="mailto:mdowle@mdowle.plus.com">mdowle@mdowle.plus.com</a>&gt; wrote:<br>
&gt;         Interesting one. Adding columns is a bit different to deleting<br>
&gt;         and<br>
&gt;         modifying columns. Here&#39;s how it works. Could make changes,<br>
&gt;         could<br>
&gt;         document it, or both, what do people think?<br>
&gt;<br>
&gt;         Just like data.frame there is a list vector holding pointers<br>
&gt;         to the<br>
&gt;         column vectors. A delete column op is done with a memmove to<br>
&gt;         budge up<br>
&gt;         the column pointers above the column by one place. That leaves<br>
&gt;         a gap at<br>
&gt;         the end. The length attribute of that vector (ncol(DT)) is<br>
&gt;         then<br>
&gt;         decremented and the spare 4 bytes (or 8 on 64bit) are left<br>
&gt;         unused at the<br>
&gt;         end.<br>
&gt;<br>
&gt;         An add column can&#39;t be fully by reference because the list<br>
&gt;         vector is<br>
&gt;         full. A new list vector has to be allocated, one slot larger,<br>
&gt;         the old<br>
&gt;         pointers memcpy&#39;d over, and the last spot assigned the pointer<br>
&gt;         to the<br>
&gt;         new column vector.  This copying is negligible because it&#39;s a<br>
&gt;         small list<br>
&gt;         of pointers fitting well within one page. [Unless, there are<br>
&gt;         many 1000&#39;s<br>
&gt;         of columns, which is why it&#39;s done as efficiently as possible<br>
&gt;         using<br>
&gt;         memcpy].<br>
&gt;<br>
&gt;         Aside : There is little known (I guess) distinction between<br>
&gt;         length and<br>
&gt;         truelength in R internals. Base R doesn&#39;t use it, but we could<br>
&gt;         in<br>
&gt;         data.table. A delete column sets length but leaves truelength<br>
&gt;         one<br>
&gt;         larger. When the next add column comes along, it could just do<br>
&gt;         the budge<br>
&gt;         up and insert the column. That may not be so advantageous for<br>
&gt;         (a small<br>
&gt;         number) of columns,  but the same logic could work for<br>
&gt;         insert() and<br>
&gt;         delete()ing rows.  Of course, this would mean whether a<br>
&gt;         visible copy or<br>
&gt;         not is taken depends on what happened previously, rather than<br>
&gt;         the<br>
&gt;         syntax. That&#39;s something we&#39;ve disliked before, in the same<br>
&gt;         way we<br>
&gt;         dislike drop=TRUE behaviour and so dropped drop. One way to<br>
&gt;         approach<br>
&gt;         this might be to advise &quot;:= add *may* not copy. Best to assume<br>
&gt;         it<br>
&gt;         doesn&#39;t; use copy()&quot;. If you get in the habbit of<br>
&gt;         &quot;DT2=copy(DT)&quot; then<br>
&gt;         that&#39;ll take a deep copy at the time and you&#39;re safe.<br>
&gt;<br>
&gt;         To illustrate the partial (maybe shallow copy is better word),<br>
&gt;         consider<br>
&gt;         the following :<br>
&gt;<br>
&gt;         &gt; DT = data.table(1:2,3:4)<br>
&gt;         &gt; DT2=DT<br>
&gt;         &gt; DT2[,y:=10L]<br>
&gt;             V1 V2  y<br>
&gt;         [1,]  1  3 10<br>
&gt;         [2,]  2  4 10<br>
&gt;         &gt; DT<br>
&gt;             V1 V2<br>
&gt;         [1,]  1  3<br>
&gt;         [2,]  2  4<br>
&gt;         &gt; DT2<br>
&gt;             V1 V2  y<br>
&gt;         [1,]  1  3 10<br>
&gt;         [2,]  2  4 10<br>
&gt;         &gt; DT2[1,V1:=99L]<br>
&gt;             V1 V2  y<br>
&gt;         [1,] 99  3 10<br>
&gt;         [2,]  2  4 10<br>
&gt;         &gt; DT<br>
&gt;             V1 V2<br>
&gt;         [1,] 99  3<br>
&gt;         [2,]  2  4<br>
&gt;         &gt;<br>
&gt;<br>
&gt;         Matthew<br>
&gt;<br>
&gt;<br>
&gt;         On Thu, 2011-10-27 at 11:46 -0700, Muhammad Waliji wrote:<br>
&gt;         &gt; I think this is a bug.  DT.2 &lt;- DT.1 doesn&#39;t seem to make a<br>
&gt;         copy in<br>
&gt;         &gt; all cases.<br>
&gt;         &gt;<br>
&gt;         &gt;<br>
&gt;         &gt; &gt; DT.1 &lt;- data.table(x=1, y=1)<br>
&gt;         &gt; &gt; DT.2 &lt;- DT.1<br>
&gt;         &gt; &gt;<br>
&gt;         &gt; &gt; # Both DT.1 and DT.2 are changed.<br>
&gt;         &gt; &gt; DT.2[, y := NULL]<br>
&gt;         &gt;      x<br>
&gt;         &gt; [1,] 1<br>
&gt;         &gt; &gt; DT.1<br>
&gt;         &gt;      x<br>
&gt;         &gt; [1,] 1<br>
&gt;         &gt; &gt; DT.2<br>
&gt;         &gt;      x<br>
&gt;         &gt; [1,] 1<br>
&gt;         &gt; &gt;<br>
&gt;         &gt; &gt; # Only DT.2 is changed<br>
&gt;         &gt; &gt; DT.2[, y := x]<br>
&gt;         &gt;      x y<br>
&gt;         &gt; [1,] 1 1<br>
&gt;         &gt; &gt; DT.1<br>
&gt;         &gt;      x<br>
&gt;         &gt; [1,] 1<br>
&gt;         &gt; &gt; DT.2<br>
&gt;         &gt;      x y<br>
&gt;         &gt; [1,] 1 1<br>
&gt;         &gt;<br>
&gt;         &gt;<br>
&gt;<br>
&gt;         &gt; _______________________________________________<br>
&gt;         &gt; datatable-help mailing list<br>
&gt;         &gt; <a href="mailto:datatable-help@lists.r-forge.r-project.org">datatable-help@lists.r-forge.r-project.org</a><br>
&gt;         &gt;<br>
&gt;         <a href="https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/datatable-help" target="_blank">https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/datatable-help</a><br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt;<br>
<br>
<br>
</div></div></blockquote></div><br>