I’m quite sure blank?
and friends are universally loved. But, just recently I’ve learned through an annoying bug that false.blank? == true
. This seems unexpected. Can anyone help me to understand the rationale for that?
The great question is: why is there a method that verifies if a value is blank, if that value could never, by definition, be blank?
Accordingly to the 7.0.4 docs: “An instance of ActiveSupport::TimeWithZone is never blank”
Of course that blank?
has at least another 3 different implementations in other classes, but in this case doesn’t make sense to me either.
I’ll keep digging into docs and implementation trying to answer that, but it oddingly seems a bug. Nice observation!
false.blank? == true
seems correct for me.
In Ruby only false
and nil
evaluate false
in a conditional. Everything else evaluates to true
. These semantics are simple but sometimes you want different semantics. You want things like an empty string or an empty array to evaluate to false. Therefore as an extension Rails adds the concept of “blank” to includes other things. But the false
and nil
are also considered blank. The new items added are in addition to what is already considered false
. Some languages/libraries uses the term “falsey” as this sort of extended version of false.
value | Ruby | Rails |
---|---|---|
nil | false | blank |
false | false | blank |
[] |
true | blank |
'' |
true | blank |
NOTE: There are other things that can evaluate to blank besides just []
and ''
. Really anything that responds to empty?
is blank?
. I just used []
and ''
as to common examples of things that are blank.
I disagree with this. The word “blank” to me means “has no value”. Boolean has 3 possible states - true, false, and nil. Nil is the absence of value, so it’s blank. True and false are both values, so neither are blank.
This confusion has caused a number of logic issues for me in Rails.
The docs define the meaning of blank.
https://apidock.com/rails/Object/blank%3F
While the word may mean different things to each of us, the “correct” meaning is what’s defined in the docs.
I agree this is bit confusing. If you’re testing a boolean, you could use nil?
to get the result you’re after.
@wale Yeah, I’m not debating how it’s implemented. My point is that I think how it’s implemented is not intuitive.
In Ruby there is no Boolean type. The boolean space is flat, with false
and nil
being false, and everything else being true.
The boolean semantics of a Ruby object do not matter for blank?
, as you can see by the amount of objects that are true and blank.
In the case of the singletons, false
is considered to be blank and true
is not. And this definition makes sense to me. You need to revise the definition of blank in your head to match what it truly means (which is not absence of value).
That said, I believe people tend to overuse blank?
, I prefer empty?
or nil?
or just evaluate the object in boolean context where that is enough.
I realize this is semantics and one person’s subjective interpretation of what words mean. It also doesn’t matter one bit what I think because there’s no way this is going to change at this point.
To me, the implementations of blank?
and present?
are both incorrect for a boolean false. The method present?
means “has value” in the context of a string, so why doesn’t it in the context of a boolean? The same argument for blank?
- it means “has no value” for a string but not for a boolean. That feels inconsistent.
For evidence to back up my case (and then I’ll give it a rest), you can’t validate the presence of a boolean. Instead you have to validate inclusion in [true,false]
and that just feels wrong. If there weren’t a presence validation that behaves incorrectly (IMO), I wouldn’t care at all.
I know what you’re saying, and from “a certain point of view”, you are absolutely correct. I used to believe that a boolean could only have two states, but a co-worker convinced me otherwise. It all depends on what you want that field to represent.
For many things, I often will use the database default to enforce that if it isn’t true, it is FALSE, and therefore never NIL. Example might be a published
boolean.
But that’s not the same thing as I might need for an approved
boolean. In that case, there are really three possible states: yes, no, and ‘haven’t decided’. A true (nullable) boolean can represent all of them. Perhaps that would be better modeled by an enum, with named states for the three possibilities, but that’s the example that opened my eyes.
Maybe we make it sweeter, and add a validates :my_field, boolean: true
to the framework. But would that be another bikeshed to paint?
Walter
Yes, exactly. You described my two scenarios perfectly. Sometimes I want to validate that the user explicitly answered a true/false question, and in that case the absence of true is not false, it’s nil, and assuming false is incorrect.
As I said, there’s a workaround for this so it’s a minor annoyance. The fact that we’re even debating such a small issue must mean that Rails is pretty great.
If you know it’s going to be one of nil
, false
, true
, you can validate the presence of a boolean with the nil?
predicate.
@joeldrapper Trying to understand what you mean. Can you give me an example?
@kiddrew sorry, I mean if you have a value that you know is a nullable boolean (nil
, false
or true
), then you can check if it “has a value” with the nil?
predicate.
true.nil? # → false
false.nil? # → false
nil.nil? # → true
@joeldrapper Aha, yeah I can write a custom validator. I just meant that you can’t use the built-in PresenceValidator for a boolean. As I said, it’s a minor annoyance.
I might be wrong here, but only nil
has no value in Ruby, so we already have a method answering that nil?
I find myself doing the same. It’s nice to see someone else feels the same .