https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112017-08-16T12:44:42ZRuby Issue Tracking SystemRuby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=662032017-08-16T12:44:42Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>I am not sure that using a special-purpose operator would make a lot of sense.</p>
<p>I myself use nil primarily as means to indicate a default, "non-set" value. The<br>
moment it is set to a boolean, be it false or true, is for me an indication<br>
that it has been "upgraded" (or set by a user on the commandline etc...)</p>
<p>I do also tend to explicitely query for .nil? on some objects.</p>
<p>By the way, did you actually propose an actual syntax? The two '?'?</p>
<p>I do not think that ?? has any realistic chance for implementation due to<br>
? already being used in ruby - in method definitions or ternary<br>
operator for example. People may wonder why there are so many ? coming out<br>
of nowhere. (For the record, I also consider || to be not pretty ... I<br>
strangely end up using a more verbose but explicit way to set or ensure<br>
defaults in ruby code. I would never write a line such as "<br>
port = opts[:port] || (https ? 443 : 80)" simply because it takes my<br>
brain too long to process what is going on there; my code always ends<br>
up being so simple that I do not have to think about it much at all).</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=662072017-08-16T21:56:08Zphluid61 (Matthew Kerwin)matthew@kerwin.net.au
<ul></ul><p>In perl I find <code>$x // $y</code> useful vs <code>$x || $y</code> because sometimes you want to accept <code>""</code> and <code>0</code> as values.</p>
<p>In ruby the only 'defined' falsey value is <code>false</code>, so I'm not sure how useful this feature is here.</p>
<p>If you're pulling options from a hash, for example, it's probably better to use a signal like <code>h.fetch 'x', y</code> to show that you accept falsey values from the hash, and/or <code>x.nil? ? y : x</code> to show that you explicitly only don't want <code>nil</code></p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=662092017-08-16T23:45:23Zwilliamn (William Newbery)
<ul></ul><p>shevegen (Robert A. Heiler) wrote:</p>
<blockquote>
<p>By the way, did you actually propose an actual syntax? The two '?'?</p>
</blockquote>
<p>Not really personally set on any given syntax, just <code>??</code> and <code>//</code> are familiar to me from other programming. Although actually for <code>??</code> specifically, I guess the fact Ruby uses it in both methods and ternary causes a conflict rather than just one or the other (<code>x.nil?? "was nil" : "not nil"</code>). I wouldn't know if the parser can figure that out or not.</p>
<p>But more the concept that any specific syntax.</p>
<blockquote>
<p>I myself use nil primarily as means to indicate a default, "non-set" value. The<br>
moment it is set to a boolean, be it false or true, is for me an indication<br>
that it has been "upgraded" (or set by a user on the commandline etc...)</p>
</blockquote>
<p>Hmm, maybe I didn't explain clearly. That is pretty much the pattern I come across repeatedly in Ruby code, and it fails for the <code>false</code> value because false is not "upgraded" when people do "x || my_default".</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="s2">"a truthy value"</span> <span class="o">||</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># The operator also short circuits so the method `foo` will never even get called</span>
<span class="kp">false</span> <span class="o">||</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># Left side is falsy, so evaluate the right side, but is often not the intent</span>
<span class="kp">nil</span> <span class="o">||</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># Nil is also falsy, so evaluate the right side</span>
<span class="s2">"a truthy value"</span> <span class="p">??</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># String is true and not nil, so nothing changes here</span>
<span class="kp">false</span> <span class="sc">??</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># This changes. Left side is not nil, so the right side is never evaluated</span>
<span class="kp">nil</span> <span class="sc">??</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># Like with `||`, left side is nil so evaluate the right side</span>
<span class="c1"># so this "does the right thing", as far as my maybe not great example goes</span>
<span class="n">https</span> <span class="o">=</span> <span class="n">opts</span><span class="p">[:</span><span class="n">https</span><span class="p">]</span> <span class="p">??</span> <span class="kp">true</span>
</code></pre>
<p>phluid61 (Matthew Kerwin) wrote:</p>
<blockquote>
<p>In perl I find <code>$x // $y</code> useful vs <code>$x || $y</code> because sometimes you want to accept <code>""</code> and <code>0</code> as values.<br>
But not <code>false</code>?</p>
</blockquote>
<p>While <code>hash.fetch</code> is nice, I still see <code>||</code> used a lot, in places that maybe wont convert so nice. Also it wont short circuit, in the event the default is not trivial (e.g. with say active record stuff, its easy to have something that goes to the DB without really thinking about it).</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">opts</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="o">||</span> <span class="vi">@foo_config</span> <span class="o">||</span> <span class="no">App</span><span class="p">.</span><span class="nf">config</span><span class="p">.</span><span class="nf">foo</span> <span class="c1"># Occasionally I see 3 or more chained together</span>
<span class="nb">hash</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="o">||=</span> <span class="n">fetch_foo</span> <span class="c1"># fetch doesn't assign the value like this does, and it wont short circuit `fetch_foo`</span>
<span class="vi">@lazy</span> <span class="o">||=</span> <span class="n">calc_lazy</span> <span class="c1"># Sometimes used with non-hashes</span>
</code></pre>
<p>But yes your right, they can all be done other ways, and maybe the better answer is to discourage <code>||</code> in the first place, but I struggled finding ones as tidy to suggest instead.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">opts</span><span class="p">.</span><span class="nf">fetch</span><span class="p">(</span><span class="ss">:foo</span><span class="p">,</span> <span class="o">!</span><span class="vi">@foo_config</span><span class="p">.</span><span class="nf">nil?</span> <span class="vi">@foo_config</span> <span class="p">:</span> <span class="no">App</span><span class="p">.</span><span class="nf">config</span><span class="p">.</span><span class="nf">foo</span><span class="p">)</span>
<span class="nb">hash</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="o">=</span> <span class="n">fetch_foo</span> <span class="k">if</span> <span class="o">!</span><span class="nb">hash</span><span class="p">.</span><span class="nf">has_key?</span><span class="p">(</span><span class="ss">:foo</span><span class="p">)</span>
<span class="vi">@lazy</span> <span class="o">=</span> <span class="n">calc_lazy</span> <span class="k">if</span> <span class="vi">@lazy</span><span class="p">.</span><span class="nf">nil?</span>
<span class="vi">@lazy</span> <span class="c1"># needed because get nil if the if condition is false</span>
<span class="k">if</span> <span class="vi">@lazy</span><span class="p">.</span><span class="nf">nil?</span>
<span class="vi">@lazy</span> <span class="o">=</span> <span class="n">calc_lazy</span>
<span class="k">end</span>
<span class="vi">@lazy</span>
</code></pre> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=662102017-08-17T00:01:23Zphluid61 (Matthew Kerwin)matthew@kerwin.net.au
<ul></ul><p>williamn (William Newbery) wrote:</p>
<blockquote>
<p>phluid61 (Matthew Kerwin) wrote:</p>
<blockquote>
<p>In perl I find <code>$x // $y</code> useful vs <code>$x || $y</code> because sometimes you want to accept <code>""</code> and <code>0</code> as values.</p>
</blockquote>
<p>But not <code>false</code>?</p>
</blockquote>
<p>Not in perl ;)</p>
<blockquote>
<p>While <code>hash.fetch</code> is nice, I still see <code>||</code> used a lot, in places that maybe wont convert so nice. Also it wont short circuit, in the event the default is not trivial (e.g. with say active record stuff, its easy to have something that goes to the DB without really thinking about it).</p>
</blockquote>
<p>Yes, short-circuit is handy. It's why I was a proponent of <code>&.</code>. Maybe it's okay to add <code>//</code> even if it's only used sometimes.</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=662242017-08-18T00:16:34Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>williamn (William Newbery) wrote:</p>
<blockquote>
<p>shevegen (Robert A. Heiler) wrote:</p>
<blockquote>
<p>By the way, did you actually propose an actual syntax? The two '?'?</p>
</blockquote>
<p>Not really personally set on any given syntax, just <code>??</code> and <code>//</code> are familiar to me from other programming. Although actually for <code>??</code> specifically, I guess the fact Ruby uses it in both methods and ternary causes a conflict rather than just one or the other (<code>x.nil?? "was nil" : "not nil"</code>). I wouldn't know if the parser can figure that out or not.</p>
</blockquote>
<p><code>??</code> is a string literal, and <code>//</code> is a regexp literal.</p>
<blockquote>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">**</span><span class="n">opts</span><span class="p">)</span>
<span class="n">host</span> <span class="o">=</span> <span class="n">opts</span><span class="p">[</span><span class="ss">:host</span><span class="p">]</span> <span class="o">||</span> <span class="n">default_host</span>
<span class="n">https</span> <span class="o">=</span> <span class="n">opts</span><span class="p">[</span><span class="ss">:https</span><span class="p">]</span> <span class="o">||</span> <span class="kp">true</span>
<span class="n">port</span> <span class="o">=</span> <span class="n">opts</span><span class="p">[</span><span class="ss">:port</span><span class="p">]</span> <span class="o">||</span> <span class="p">(</span><span class="n">https</span> <span class="p">?</span> <span class="mi">443</span> <span class="p">:</span> <span class="mi">80</span><span class="p">)</span>
</code></pre>
</blockquote>
<p>Why not keyword arguments?</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=852922020-04-25T20:39:16Zswrobel (Stefan Wrobel)
<ul><li><strong>Subject</strong> changed from <i>Add a nill coalescing operator</i> to <i>Add a nil coalescing operator</i></li></ul> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=853222020-04-29T20:05:58Zbsarrazin (Ben Sarrazin)
<ul></ul><p>Kotlin has this feature, Swift has this feature, many other languages have this feature.<br>
Ruby <em>needs</em> this feature :D</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="s2">"a truthy value"</span> <span class="o">||</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># The operator also short circuits so the method `foo` will never even get called</span>
<span class="kp">false</span> <span class="o">||</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># Left side is falsy, so evaluate the right side, but is often not the intent</span>
<span class="kp">nil</span> <span class="o">||</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># Nil is also falsy, so evaluate the right side</span>
<span class="s2">"a truthy value"</span> <span class="p">??</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># String is true and not nil, so nothing changes here</span>
<span class="kp">false</span> <span class="sc">??</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># This changes. Left side is not nil, so the right side is never evaluated</span>
<span class="kp">nil</span> <span class="sc">??</span> <span class="n">foo</span><span class="p">(</span><span class="s2">"something else"</span><span class="p">)</span> <span class="c1"># Like with `||`, left side is nil so evaluate the right side</span>
<span class="c1"># so this "does the right thing", as far as my maybe not great example goes</span>
<span class="n">https</span> <span class="o">=</span> <span class="n">opts</span><span class="p">[:</span><span class="n">https</span><span class="p">]</span> <span class="p">??</span> <span class="kp">true</span>
</code></pre>
<p>This is exactly why Ruby needs this feature. The lack of type safety, combined with the fact that many tools are taking "false" string as input is compelling argument to add this to the language.</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=853252020-04-30T02:50:34Zshyouhei (Shyouhei Urabe)shyouhei@ruby-lang.org
<ul></ul><p>bsarrazin (Ben Sarrazin) wrote in <a href="#note-7">#note-7</a>:</p>
<blockquote>
<p>Kotlin has this feature, Swift has this feature, many other languages have this feature.</p>
</blockquote>
<p>No. Kotlin does not have this feature (distinguish <code>false</code> and <code>null</code>). It is a really bad idea for you to refer Kotlin to have something like that. Kotlin is a statically typed language, and its <code>||</code> operator does not take nullable values. No confusion over <code>false</code> versus <code>null</code> must happen. That is why they need <code>?:</code> operator; they need something similar to <code>||</code> which also work for nullables.</p>
<p>So if you want a ruby operator because <code>false</code> and <code>nil</code> are confusing, that's a totally different story than Kotlin's.</p>
<p>PS. I'm not against the feature itself. I'm just telling that other languages have their own design that do not immediately apply here.</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=853282020-04-30T09:00:59Zsawa (Tsuyoshi Sawada)
<ul></ul><p>Your proposal to distinguish <code>nil</code> from <code>false</code> is ad hoc, and is not a real solution for your use case, which is to add a value to a hash only when it does not yet have a corresponding key.</p>
<p>Following your way of doing it, you would still not be able to distinguish <code>opts1</code> that explicitly has a key-value pair <code>:foo</code> => <code>nil</code> and <code>opts2</code> that lacks such pair.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">opts1</span> <span class="o">=</span> <span class="p">{</span><span class="ss">foo: </span><span class="kp">nil</span><span class="p">}</span>
<span class="n">opts2</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">opts1</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="c1"># => nil</span>
<span class="n">opts2</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="c1"># => nil</span>
</code></pre>
<p>Particularly, applying your code to update <code>opts1</code> would overwrite the explicit <code>nil</code> value (<code>??</code> stands for your proposed feature):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">opts1</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="p">?</span><span class="sc">?=</span> <span class="s2">"foo"</span>
<span class="n">opts1</span><span class="p">[:</span><span class="n">foo</span><span class="p">]</span> <span class="c1"># => "foo"</span>
</code></pre>
<p>Ruby is aware of such use case, and has already prepared a real solution: the <code>Hash#key?</code> method. The correct way of doing it is:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">opts1</span><span class="p">[</span><span class="ss">:foo</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"foo"</span> <span class="k">unless</span> <span class="n">opts1</span><span class="p">.</span><span class="nf">key?</span><span class="p">(</span><span class="ss">:foo</span><span class="p">)</span>
</code></pre>
<p>Another way of doing it is:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">opts1</span> <span class="o">=</span> <span class="p">{</span><span class="ss">foo: </span><span class="s2">"foo"</span><span class="p">}.</span><span class="nf">merge</span><span class="p">(</span><span class="n">opts1</span><span class="p">)</span>
</code></pre> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=878362020-10-01T08:41:34Zakim (Akim Demaille)
<ul></ul><p>I second this proposal.</p>
<p>Sure, it is not <em>needed</em>, we can always write things in a different way. As a matter of fact, with such an argument, hardly any improvement should be accepted.</p>
<p>In practice when people use <code>||</code>, they do mean <code>??</code> (whatever its spelling). It just so happens that <em>most of the time</em>, it does what you want, because you happen to not be dealing with Booleans. But the semantics you mean to express is not about "truthness", but about "nilness". And occasionally you get bitten because <code>false</code> does exist, and behaves differently.</p>
<p>Wrt syntax, <code>??</code> chains much more naturally than conditionals.</p>
<p>Many of the new languages make the difference, and support this explicitly.</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=878372020-10-01T08:47:06Zakim (Akim Demaille)
<ul></ul><p>shyouhei (Shyouhei Urabe) wrote in <a href="#note-8">#note-8</a>:</p>
<blockquote>
<p>bsarrazin (Ben Sarrazin) wrote in <a href="#note-7">#note-7</a>:</p>
<blockquote>
<p>Kotlin has this feature, Swift has this feature, many other languages have this feature.</p>
</blockquote>
<p>No. Kotlin does not have this feature (distinguish <code>false</code> and <code>null</code>).</p>
</blockquote>
<p>I disagree. Kotlin does have the feature which is the topic of this page: a null coalescing operator (<a href="https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator" class="external">https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator</a>). And you are rightfully stating it:</p>
<blockquote>
<p>That is why they need <code>?:</code> operator</p>
</blockquote>
<p>which exactly corresponds to the proposal about <code>??</code>.</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=909382021-03-15T23:50:08Zlamont (Lamont Granquist)lamont@scriptkiddie.org
<ul></ul><p>This would cut down on a lot of bugs dealing with lazy initialization of values where <code>false</code> is valid and needs to be remembered:</p>
<pre><code># hammers on the expensive determination method if it returns false
def should_dosomething?
@should_dosomething ||= expensively_determine_if_should_do_something
end
# correctly remembers either false or true
def should_dosomething?
@should_dosomething ??= expensively_determine_if_should_do_something
end
</code></pre>
<p>This happens more than you might expect because people learn to use <code>||=</code> in that situation and wind up accidentally writing the buggy code when they're faced with this problem of remembering an expensive thing that returns booleans.</p>
<p>The ??= operator should be introduced into the language and really the idiom should switch to consistently use it all the time to avoid this bug.</p> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=909392021-03-16T00:07:51Zlamont (Lamont Granquist)lamont@scriptkiddie.org
<ul></ul><p>Here's example code which works around the lack of a ??= operator in the wild:</p>
<p><a href="https://github.com/chef/chef/blob/4d3b847aee1b917bb139862c623e9633d180fb31/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb#L43-L48" class="external">https://github.com/chef/chef/blob/4d3b847aee1b917bb139862c623e9633d180fb31/lib/chef/chef_fs/file_system/chef_server/data_bag_dir.rb#L43-L48</a></p>
<pre><code> def exists?
if @exists.nil?
@exists = parent.children.any? { |child| child.name == name }
end
@exists
end
</code></pre> Ruby master - Feature #13820: Add a nil coalescing operatorhttps://bugs.ruby-lang.org/issues/13820?journal_id=909442021-03-16T15:34:51Zp8 (Petrik de Heus)
<ul></ul><p>This is also related to the Hash#fetch_set proposal</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">cache</span><span class="p">.</span><span class="nf">fetch_set</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="p">{</span> <span class="n">calculation</span> <span class="p">}</span>
</code></pre>
<p><a href="https://bugs.ruby-lang.org/issues/17342" class="external">https://bugs.ruby-lang.org/issues/17342</a></p>