https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112016-12-24T17:08:39ZRuby Issue Tracking SystemRuby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=622292016-12-24T17:08:39Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-5 priority-4 priority-default closed" href="/issues/11286">Feature #11286</a>: [PATCH] Add case equality arity to Enumerable's sequence predicates.</i> added</li></ul> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=622342016-12-25T01:22:22Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>It affects <code>case</code>/<code>when</code> clause too, and breaks optparse and rubygems at least.</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gh">diff --git i/lib/optparse.rb w/lib/optparse.rb
index afeff80740..216dd38732 100644
</span><span class="gd">--- i/lib/optparse.rb
</span><span class="gi">+++ w/lib/optparse.rb
</span><span class="p">@@ -394,9 +394,9 @@</span>
#
class OptionParser
# :stopdoc:
<span class="gd">- NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
- RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
- OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
</span><span class="gi">+ NoArgument = [NO_ARGUMENT = :NONE, NilClass].freeze
+ RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, TrueClass].freeze
+ OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, FalseClass].freeze
</span> # :startdoc:
#
<span class="gh">diff --git i/object.c w/object.c
index 5f0055fb5a..c566bc57c5 100644
</span><span class="gd">--- i/object.c
</span><span class="gi">+++ w/object.c
</span><span class="p">@@ -1260,6 +1260,7 @@</span> true_to_s(VALUE obj)
/*
* call-seq:
* true & obj -> true or false
<span class="gi">+ * true === obj -> true or false
</span> *
* And---Returns <code>false</code> if <i>obj</i> is
* <code>nil</code> or <code>false</code>, <code>true</code> otherwise.
<span class="p">@@ -1297,6 +1298,7 @@</span> true_or(VALUE obj, VALUE obj2)
/*
* call-seq:
* true ^ obj -> !obj
<span class="gi">+ * false === obj -> !obj
</span> *
* Exclusive Or---Returns <code>true</code> if <i>obj</i> is
* <code>nil</code> or <code>false</code>, <code>false</code>
<span class="p">@@ -3603,7 +3605,7 @@</span> InitVM_Object(void)
rb_define_method(rb_cTrueClass, "&", true_and, 1);
rb_define_method(rb_cTrueClass, "|", true_or, 1);
rb_define_method(rb_cTrueClass, "^", true_xor, 1);
<span class="gd">- rb_define_method(rb_cTrueClass, "===", rb_equal, 1);
</span><span class="gi">+ rb_define_method(rb_cTrueClass, "===", true_and, 1);
</span> rb_undef_alloc_func(rb_cTrueClass);
rb_undef_method(CLASS_OF(rb_cTrueClass), "new");
/*
<span class="p">@@ -3618,7 +3620,7 @@</span> InitVM_Object(void)
rb_define_method(rb_cFalseClass, "&", false_and, 1);
rb_define_method(rb_cFalseClass, "|", false_or, 1);
rb_define_method(rb_cFalseClass, "^", false_xor, 1);
<span class="gd">- rb_define_method(rb_cFalseClass, "===", rb_equal, 1);
</span><span class="gi">+ rb_define_method(rb_cFalseClass, "===", true_xor, 1);
</span> rb_undef_alloc_func(rb_cFalseClass);
rb_undef_method(CLASS_OF(rb_cFalseClass), "new");
/*
</code></pre> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=622872016-12-27T15:55:14Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><p>\o/</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=622992016-12-28T04:05:18Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul></ul><p>Nobu, I think the benefit outpass the drawbacks.</p>
<p>Regarding your patch, I think <code>===</code> should be its own RDoc entries.</p>
<p>Matz.</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623052016-12-28T19:54:00Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Assignee</strong> set to <i>matz (Yukihiro Matsumoto)</i></li></ul><ol>
<li>
<p>This would break a lot of code. As an example, I found 13 instances of <code>when true/false</code> in Rails' code that would break.</p>
</li>
<li>
<p>There is no good replacement for the current uses of <code>when true</code> and <code>when false</code>. In particular, <code>when true</code> would basically require separate <code>if</code>.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># From rails/actionpack/lib/action_dispatch/middleware/ssl.rb</span>
<span class="c1"># Current:</span>
<span class="k">def</span> <span class="nf">normalize_hsts_options</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="k">case</span> <span class="n">options</span>
<span class="k">when</span> <span class="kp">false</span>
<span class="c1"># ...</span>
<span class="k">when</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">true</span>
<span class="c1"># ...</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Ugly rewrite necessary:</span>
<span class="k">def</span> <span class="nf">normalize_hsts_options</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="k">if</span> <span class="n">options</span> <span class="o">==</span> <span class="kp">true</span>
<span class="c1"># ...</span>
<span class="k">else</span>
<span class="k">case</span> <span class="n">options</span>
<span class="k">when</span> <span class="kp">nil</span>
<span class="c1"># repeated code from `options == true` above...</span>
<span class="k">when</span> <span class="kp">false</span> <span class="c1"># `nil` case must be already taken care of</span>
<span class="c1"># ...</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</li>
<li>
<p>This makes <code>when true</code> almost meaningless and very misleading. <code>when false</code> is not useful as it can already be written easily with <code>when false, nil</code></p>
</li>
<li>
<p>Increases the confusion of <code>true</code> vs "truthy" and <code>false</code> vs "falsey"</p>
</li>
<li>
<p>More importantly, I can not think of a single valid usecase.</p>
</li>
</ol>
<p><code>ary.grep(true)</code> was mentioned. I very much doubt there's much need to do that. We often want to exclude <code>nil</code> from a list (that's why we have <code>compact</code>), but excluding both <code>nil</code> and <code>false</code> seem odd, like the values were not computed properly. If there was such a need: <code>ary.select(&:itself)</code> works fine and is clear and concise enough.</p>
<p><code>ary.grep(false)</code> seems completely meaningless to me (what can be the use of an array of <code>nil</code> and <code>false</code> values?) but if it isn't, <code>ary.reject(&:itself)</code> works too.</p>
<p>In short, I find the proposal both completely useless and confusing. In case it is somehow deemed necessary, then please define <code>TRUTHY</code> and <code>FALSEY</code> instead of changing the definitions that have been valid for 20 years.</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623412016-12-31T16:37:31Zshevegen (Robert A. Heiler)shevegen@gmail.com
<ul></ul><blockquote>
<ol start="4">
<li>Increases the confusion of true vs "truthy" and false vs "falsey"</li>
</ol>
</blockquote>
<p>I think that the words "true" and "false" are a lot easier to understand than "truthy" and "falsy".</p>
<p>There should be some document that states the valid values for these in ruby.</p>
<p>Off the top of my head, true being everything except for:</p>
<ul>
<li>nil</li>
<li>false</li>
</ul>
<p>Perhaps I missed something, but that seems to be like a very small list to remember for<br>
what is false? I am confused about the confusion comment. I guess the part about code<br>
that breaks is a valid concern though. There is a long way to go for ruby 3.x anyway. ;)</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623562017-01-02T00:16:53Zsnood1205 (Eli Sadoff)snood1205@gmail.com
<ul></ul><p>I think that a possible middle ground replacement would be to introduce truthy and falsy constants into <code>TrueClass</code> and <code>FalseClass</code> respectively. You could then do, for example,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="mi">1</span>
<span class="k">when</span> <span class="kp">true</span> <span class="k">then</span> <span class="nb">puts</span> <span class="s1">'This will not match'</span>
<span class="k">when</span> <span class="no">TrueClass</span><span class="o">::</span><span class="no">TRUTHY</span> <span class="nb">puts</span> <span class="s1">'But this will'</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623692017-01-03T15:10:30Zsawa (Tsuyoshi Sawada)
<ul></ul><p>Marc-Andre Lafortune wrote:</p>
<blockquote>
<ol start="2">
<li>There is no good replacement for the current uses of <code>when true</code> and <code>when false</code>. In particular, <code>when true</code> would basically require separate <code>if</code>.</li>
</ol>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="c1"># From rails/actionpack/lib/action_dispatch/middleware/ssl.rb</span>
<span class="c1"># Current:</span>
<span class="k">def</span> <span class="nf">normalize_hsts_options</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="k">case</span> <span class="n">options</span>
<span class="k">when</span> <span class="kp">false</span>
<span class="c1"># ...</span>
<span class="k">when</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">true</span>
<span class="c1"># ...</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Ugly rewrite necessary:</span>
<span class="k">def</span> <span class="nf">normalize_hsts_options</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="k">if</span> <span class="n">options</span> <span class="o">==</span> <span class="kp">true</span>
<span class="c1"># ...</span>
<span class="k">else</span>
<span class="k">case</span> <span class="n">options</span>
<span class="k">when</span> <span class="kp">nil</span>
<span class="c1"># repeated code from `options == true` above...</span>
<span class="k">when</span> <span class="kp">false</span> <span class="c1"># `nil` case must be already taken care of</span>
<span class="c1"># ...</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
</blockquote>
<p>I think there is an alternative.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="n">options</span>
<span class="k">when</span> <span class="no">FalseClass</span>
<span class="o">...</span>
<span class="k">when</span> <span class="no">NilClass</span><span class="p">,</span> <span class="no">TrueClass</span>
<span class="o">...</span>
<span class="o">...</span>
<span class="k">end</span>
</code></pre>
<p>which is actually my preferred way of writing.</p>
<p>In fact, I had often felt there is redundancy, or unnecessary freedom, between writing <code>when true</code> etc. and <code>when TrueClass</code> etc., and had to wonder which one to use (before I came to the conclusion to use the latter). If they would mean different things, as would be the case if this proposal is implemented, then that would be a desired move, I think.</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623702017-01-03T18:24:20Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<ul></ul><p>IMO the backwards incompatibility risks outweigh the rewards.</p>
<p>As Marc-Andre says, <code>array.grep(true)</code> and <code>array.grep(false)</code> could be replaced with <code>array.select(&:itself)</code> and <code>array.reject(&:itself)</code>. Since <code>case / when</code> just sends <code>===</code>, we can use a proc like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span> <span class="n">val</span>
<span class="k">case</span> <span class="n">val</span>
<span class="k">when</span> <span class="kp">true</span>
<span class="s1">'true value'</span>
<span class="k">when</span> <span class="mi">1</span>
<span class="s1">'one'</span>
<span class="k">when</span> <span class="ss">:itself</span><span class="p">.</span><span class="nf">to_proc</span>
<span class="s1">'truthy'</span>
<span class="k">else</span>
<span class="s1">'falsy'</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="n">foo</span><span class="p">(</span><span class="kp">nil</span><span class="p">)</span> <span class="c1"># falsy</span>
<span class="nb">p</span> <span class="n">foo</span><span class="p">(</span><span class="kp">false</span><span class="p">)</span> <span class="c1"># falsy</span>
<span class="nb">p</span> <span class="n">foo</span><span class="p">(</span><span class="kp">true</span><span class="p">)</span> <span class="c1"># true value</span>
<span class="nb">p</span> <span class="n">foo</span><span class="p">(</span><span class="no">Object</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span> <span class="c1"># truthy</span>
<span class="nb">p</span> <span class="n">foo</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># one</span>
</code></pre>
<p>The <code>:itself.to_proc</code> doesn't look so great as an alternative, but maybe we could make <code>case / when</code> support <code>&:itself</code> syntax.</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623752017-01-03T20:44:20Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<ul></ul><p>While <code>:itself.to_proc</code> works, I still can't see when one would need it, and it's much easier and clearer to check for <code>nil</code> and <code>false</code></p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span> <span class="n">val</span>
<span class="k">case</span> <span class="n">val</span>
<span class="k">when</span> <span class="kp">true</span>
<span class="s1">'true value'</span>
<span class="k">when</span> <span class="mi">1</span>
<span class="s1">'one'</span>
<span class="k">when</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">false</span>
<span class="s1">'falsy'</span>
<span class="k">else</span>
<span class="s1">'truthy'</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=623862017-01-04T07:23:02Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<ul></ul><p>Aaron Patterson wrote:</p>
<blockquote>
<p>The <code>:itself.to_proc</code> doesn't look so great as an alternative, but maybe we could make <code>case / when</code> support <code>&:itself</code> syntax.</p>
</blockquote>
<p><code>case / when</code> isn't the original concern, but just an unexpected side effect.<br>
Everybody can write that <code>foo</code> method, and <code>select(&method(:foo))</code> and so on, but it won't look nice.</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=625752017-01-19T09:22:42Zmatz (Yukihiro Matsumoto)matz@ruby.or.jp
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Compatibility issue was bigger than I expected. I withdraw this proposal.</p>
<p>Matz.</p> Ruby master - Feature #13067: TrueClass,FalseClass to provide `===` to match truthy/falsy values.https://redmine.ruby-lang.org/issues/13067?journal_id=841852020-02-06T21:24:25Zjonathanhefner (Jonathan Hefner)jonathan@hefner.pro
<ul></ul><p>Although I like the minimalism and cleverness of <code>:itself.to_proc</code>, I don't think it reads as nicely. It also does not <code>inspect</code> nicely. For example,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">raise</span> <span class="s2">"value does not match </span><span class="si">#{</span><span class="n">pattern</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">"</span> <span class="k">unless</span> <span class="n">pattern</span> <span class="o">===</span> <span class="n">value</span>
</code></pre>
<p>Does not give a nice error message when <code>pattern</code> is <code>:itself.to_proc</code>.</p>
<p>Also, when you specifically want to match falsy values, <code>:itself.to_proc</code> must become <code>:!.to_proc</code>, which may not be obvious.</p>
<p>So, I think constants like <code>TRUTHY</code> and <code>FALSEY</code> would be helpful. Although they might not be appropriate as top-level constants. While trying to think of where they should be defined, I had the crazy idea of <code>TrueClass#thy</code> and <code>FalseClass#y</code>. In other words, <code>true.thy == TRUTHY</code> and <code>false.y == FALSEY</code>. That is too asymmetric and gimmicky, I think, but what about <code>true.ish == TRUTHY</code> and <code>false.ish == FALSEY</code>?</p>