This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
commit 6e98adfc8e19a39fa45d4acd94145d318d151964
tree 014c82461f81ee3bdf42e1a5574cef92e96051a2
parent 4f043a48381c142e308824e3b7e15435a61bbb53
tree 014c82461f81ee3bdf42e1a5574cef92e96051a2
parent 4f043a48381c142e308824e3b7e15435a61bbb53
... |
... |
|
... |
... |
|
... |
... |
|












Maybe I’m missing something, but isn’t returning nil essentially equivalent to returning false? Both will be handled the same in an
if o.new_record?context..This also doesn’t appear to address the original issue raised by ticket #1219.
Finally, the succeeding patch (remove defined?) will raise a warning when run in -w mode. I’m guessing that’s why the code was written that way originally…
While it is equivalent, the specific issue I encountered was the (possibly wrong) expectation that a method ending in ? should return either true or false. Sure Ruby evaluates nil & false the same, but if you are explicitly checking against false, getting a nil value back will not give you the expected results.
The original issue in 1219 seemed to be related to the new_record? issue, as I’m guessing somewhere rails was also expecting a false value but getting nils. But you are correct this fix does not necessarily mean the original issue has been fully addressed.
new_record? not returning false has tripped me up a few times. +1 this change.
methods ending in ? don’t have to return true or false afaik. The ? infers that the response can be used as such.
From Flanagan & Matz (section 6.2. Method Names): “Predicates typically return one of the Boolean values true or false, but this is not required, as any value other than false or nil works like true when a Boolean value is required. (The Numeric method nonzero?, for example, returns nil if the number it is invoked on is zero, and just returns the number otherwise.)”
They don’t have to, but a lot of people expect them to :)
But it is a wrong expectation :-), a predicate returns a boolean value, it is just a test. Any value may act as a boolean value in Ruby.
That’s why in general you don’t test against == (false|true), you just use the value returned by the predicate in boolean context.
“Predicates typically return”
Typical, principle of least surprise. Show me some code where treating the return value of a predicate as anything other than a boolean is a good idea.
superspoida: the issue in 1219 was that records returned (I’m guessing – no code was provided) from a
find_by_sqlwith a right join clause weren’t being marked as new. This doesn’t address that, as those records will now return false rather than nil, but not true as 1219 wanted them to. Quite frankly, the case in 1219 was sufficiently obscure that it probably shouldn’t be handled automatically.And I’d definitely agree with fxn – if you see
trueorfalsein Ruby code, someone is Doing It Wrong.@xaviershay they typically return the singletons true/false, but not always. Ruby has clear semantics for boolean values: false and nil are booleanly false, any other object is booleanly true.
So, you say
do_this if some_predicate?and you don’t care what type of object some_predicate? returns, in Ruby you care about its boolean interpretation.
argh – textile formatting ate my signs... It should have been true and == false above.
One situation where returning nil instead of false can trip you is if you’re comparing two predicates: if foo? == bar?. If one’s nil, and one’s false, you lose, and I don’t think such usage is a code smell.
drnic is right in that not all ?-methods return true/false, but as far as I know such instances are always explicitly documented in standard ruby.
+1 for this.
As I understand it, ?-methods that return `nil` as their “falsy” value return something other than `true` as their truthy value. `nonzero?` returns a number; `defined?` returns a string like “constant”.
So `new_record?` returning `nil` and `true` was definitely unidiomatic, and the change makes good sense.
The changes make sense for me also. In rspec, I would write:
user_one.new_record?.should be_true user_two.new_record?.should be_false
When I write:
user_three.new_record?.should be_nil
Seems smelly!
george-ogata but that test is broken! @foo?could return0andbar?return1or"bar".Equality has a meaning in Ruby, it compares objects in a certain way. Interpretation of values as booleans is a different business. You just do not compare boolean equivalence with
==in Ruby.If some code expects a precise value, for example filters halted returning exactly
falsesome versions ago, then you compare them that way. Otherwise you need to play by the rules of booleans in Ruby.josevalim: you need to test the boolean meaning of
new_record?. The test shouldn’t be looking specifically fornil.In fact, note that the documentation of
new_record?doesn’t even mention a keyword. It only says that returns true (English true, which is not necessarily the same astrue) if such and such.Problem in your example lies in RSpec usage itself. I am not into RSpec, but my understanding is that
be_falsetranslates to== falseso to speak. If that’s the case, that is not a test for predicates. It tests object equality, which is stronger than the contract of the predicate. I think you test for (English) true simply with.should be.Of course if you were the developer of the very predicate you could be interested in testing the exact expected value, not only its boolean interpretation, but that’s a different story.
josevalim, fxn: to test boolean truthiness, as opposed to the identity being == true or false, you can use the rspec #be matcher.
new_rec.new_record?.should be old_rec.new_record?.should_not be
Personally I prefer using the custom predicate matchers…
new_rec.should be_a_new_record old_rec.should_not be_a_new_record
Which should work with/without this commit afaik.
bterlson: sounds good.
Point is, a predicate returns either a true or false value. In the case of
new_record?the actual returned object is unespecified, and the predicate works correctly.In that sense I am -1 on this patch.
Try approaching it from the other direction
Does this look like bad code to you? Should the framework encourage this? Or should the framework behave in a “typical” manner?
For a more concrete example, principle of least surprise says the following should halt the filter chain:
xaviershay: the framework should use and encourage idiomatic Ruby.
It is not idiomatic Ruby to expect any particular object from predicates. In particular there’s no ground on expecting the singletons
true/false. You may not like that, but Ruby is designed that way.