<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/more-on-safe-substitution-in-r/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.win-vector.com/blog/2017/06/more-on-safe-substitution-in-r/"> R – Win-Vector Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Let’s worry a bit about substitution in <a rel="nofollow" href="https://cran.r-project.org/" target="_blank"><code>R</code></a>. Substitution is very powerful, which means it can be both used and mis-used. However, that does not mean every use is unsafe or a mistake.</p>
<p><span></span></p>
<p>From <a rel="nofollow" href="http://adv-r.had.co.nz/Computing-on-the-language.html#substitute" target="_blank"><em>Advanced R</em> : substitute</a>:</p>
<div>
<center><br>
<a rel="nofollow" href="http://adv-r.had.co.nz/Computing-on-the-language.html#substitute" target="_blank"><img alt="" src="https://i2.wp.com/www.win-vector.com/blog/wp-content/uploads/2017/06/advrsubs.png?w=660" data-recalc-dims="1"></a><br>
</center>
</div>
<p>We can confirm the above code performs no substitution:</p>
<div>
<pre><code>a &lt;-<span> </span><span>1</span>
b &lt;-<span> </span><span>2</span>
<span>substitute</span>(a +<span> </span>b +<span> </span>z)</code></pre>
</div>
<pre><code>## a + b + z</code></pre>
<p>And it appears the effect is that substitute is designed to not take values from the global environment. So, as we see below, it isn’t so much what environment we are running in that changes substitute’s behavior, it is what environment the values are bound to that changes things.</p>
<div>
<pre><code>(function() {
  a &lt;-<span> </span><span>1</span>
  <span>substitute</span>(a +<span> </span>b +<span> </span>z, 
             <span>environment</span>())
})()</code></pre>
</div>
<pre><code>## 1 + b + z</code></pre>
<p>We can in fact find many simple variations of substitute that work conveniently.</p>
<div>
<pre><code><span>substitute</span>(a +<span> </span>b +<span> </span>z, 
           <span>list</span>(<span>a=</span><span>1</span>, <span>b=</span><span>2</span>))</code></pre>
</div>
<pre><code>## 1 + 2 + z</code></pre>
<div>
<pre><code><span>substitute</span>(a +<span> </span>b +<span> </span>z, 
           <span>as.list</span>(<span>environment</span>()))</code></pre>
</div>
<pre><code>## 1 + 2 + z</code></pre>
<p>Often <code>R</code>‘s documentation is a bit terse (or even incomplete) and functions (confusingly) change behavior based on type of arguments and context. I say: always try a few variations to see if some simple alteration can make &quot;base-R&quot; work for you before giving up and delegating everything to an add-on package.</p>
<p>However, we in fact found could not use <code>substitute()</code> to implement <a rel="nofollow" href="https://cran.r-project.org/package=wrapr" target="_blank"><code>wrapr::let()</code></a> effects (that is re-mapping non-standard interfaces to <a rel="nofollow" href="http://www.win-vector.com/blog/2016/12/parametric-variable-names-and-dplyr/" target="_blank">parametric interfaces</a>). There were some avoidable difficulties regarding quoting and un-quoting of expressions. But the killing issue was: <code>substitute()</code> apparently does not re-map left-hand sides:</p>
<div>
<pre><code><span># function that print all of its arguments (including bindings)</span>
f &lt;-<span> </span>function(...) {
  args &lt;-<span> </span><span>match.call</span>()
  <span>print</span>(<span>paste</span>(<span>&quot;f() call is:&quot;</span>, <span>capture.output</span>(<span>str</span>(args))))
}

<span># set up some global variables</span>
X &lt;-<span> </span><span>2</span>
B &lt;-<span> </span><span>5</span>

<span># try it</span>
<span>f</span>(<span>X=</span><span>7</span>, <span>Y=</span>X)</code></pre>
</div>
<pre><code>## [1] &quot;f() call is:  language f(X = 7, Y = X)&quot;</code></pre>
<div>
<pre><code><span># use substitute to capture an expression</span>
captured &lt;-<span> </span><span>substitute</span>(<span>f</span>(<span>X=</span><span>7</span>, <span>Y=</span>X))
<span># print the captured expression</span>
<span>print</span>(captured)</code></pre>
</div>
<pre><code>## f(X = 7, Y = X)</code></pre>
<div>
<pre><code><span># evaluate the captured expression</span>
<span>eval</span>(captured)</code></pre>
</div>
<pre><code>## [1] &quot;f() call is:  language f(X = 7, Y = X)&quot;</code></pre>
<div>
<pre><code><span># notice above by the time we get into the function </span>
<span># the function arguments have taken there value first</span>
<span># from explicit argument assignment (X=7) and then from</span>
<span># the calling environment (Y=X goes to 2).</span>

<span># now try to use substitute() to re-map values</span>
xform1 &lt;-<span> </span><span>substitute</span>(captured, 
                     <span>list</span>(<span>X=</span> <span>as.name</span>(<span>'B'</span>)))
<span># doesn't look good in printing</span>
<span>print</span>(xform1)</code></pre>
</div>
<pre><code>## captured</code></pre>
<div>
<pre><code><span># and substitutions did not happen as the variables we</span>
<span># are trying to alter are not free in the word &quot;captured&quot;</span>
<span># (they are in the expression the name captured is referring to)</span>
<span>eval</span>(xform1)</code></pre>
</div>
<pre><code>## f(X = 7, Y = X)</code></pre>
<div>
<pre><code><span># can almost fix that by calling substitute on the value</span>
<span># of captured (not the word &quot;captured&quot;) with do.call()</span>
subs &lt;-<span> </span><span>do.call</span>(substitute, 
                <span>list</span>(captured,  <span>list</span>(<span>X=</span> <span>as.name</span>(<span>'B'</span>))))
<span>print</span>(subs)</code></pre>
</div>
<pre><code>## f(X = 7, Y = B)</code></pre>
<div>
<pre><code><span>eval</span>(subs)</code></pre>
</div>
<pre><code>## [1] &quot;f() call is:  language f(X = 7, Y = B)&quot;</code></pre>
<div>
<pre><code><span># notice however, only right hand side was re-mapped</span>
<span># we saw &quot;f(X = 7, Y = B)&quot;, not &quot;f(B = 7, Y = B)&quot;</span>
<span># for some packages (such as dplyr) re-mapping</span>
<span># left-hand sides is important</span>
<span># this is why wrapr::let() exists</span>

wrapr::<span>let</span>(
  <span>c</span>(<span>X=</span> <span>'B'</span>),
  <span>f</span>(<span>X=</span><span>7</span>, <span>Y=</span>X)
)</code></pre>
</div>
<pre><code>## [1] &quot;f() call is:  language f(B = 7, Y = B)&quot;</code></pre>
<p>Re-mapping left hand sides is an important capability when trying to program over <code>dplyr</code>:</p>
<div>
<pre><code><span>suppressPackageStartupMessages</span>(<span>library</span>(<span>&quot;dplyr&quot;</span>))

d &lt;-<span> </span><span>data.frame</span>(<span>x =</span> <span>1</span>:<span>3</span>)
mapping &lt;-<span> </span><span>c</span>(<span>OLDCOL=</span> <span>'x'</span>,
             <span>NEWCOL=</span> <span>'y'</span>)
wrapr::<span>let</span>(
  mapping,
  d %>%
<span> </span><span>mutate</span>(<span>NEWCOL =</span> OLDCOL*OLDCOL)
)</code></pre>
</div>
<pre><code>##   x y
## 1 1 1
## 2 2 4
## 3 3 9</code></pre>
<p><code>wrapr::let()</code> is based on string substitution. This is considered risky. Consider <code>help(substitute, package='base')</code></p>
<blockquote>
<p>Note</p>
<p>substitute works on a purely lexical basis. There is no guarantee that the resulting expression makes any sense.</p>
</blockquote>
<p>And that is why <code>wrapr::let()</code> takes a <a rel="nofollow" href="http://www.win-vector.com/blog/2017/06/in-defense-of-wraprlet/#comment-66548" target="_blank"><em>large</em> number of precautions</a> and vets user input before performing any substitution.</p>
<p>The idea is: <code>wrapr::let()</code> is more specialized than <code>substitute()</code> so in addition to attempting extra effects (re-mapping left hand sides) it can introduce a lot of checks to ensure safe invariants.</p>
<p>And that is a bit of my point: when moving to a package look for specificity and safety in addition to &quot;extra power.&quot; That is how <code>wrapr::let()</code> is designed and whey <code>wrapr::let()</code> is a safe and effective package to add to your production work-flows.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://www.win-vector.com/blog/2017/06/more-on-safe-substitution-in-r/"> R – Win-Vector Blog</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...

	<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/FgCA63vg6KI" height="1"></a></div>