proposing Object#nonblank? (analogous to Ruby's Numeric#nonzero?)

All,

I'd like to propose the Object#nonblank? in ActiveSupport, layered
over the blank? method. This has been working well for us in the past
year and hopefully others will find it useful enough to include in
core.

It is analogous to Ruby's Numeric#nonzero? method: it either returns
the object itself (if not blank) or nil (if blank). This makes it easy
to treat blank parameters the same as missing ones, and allows
chaining:

For example, this:

  state = params[:state] unless params[:state].blank?
  country = params[:country] unless params[:country].blank?
  region = state || country || 'US'

becomes:

  region = params[:state].nonblank? || params[:country].nonblank? ||
'US'

The ticket is here:

https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/3620-objectnonblank-analogous-to-rubys-numericnonzero#ticket-3620-2

along with a patch that includes full documentation and tests.

We already have Object#present? :slight_smile:

But you can’t chain Object#present? together the way Colin is suggesting. Object#present? returns true, not the object. I suggested something like this a while ago, Object#or_if_blank, and it got shot down because it “smelled” – it’s in git://github.com/ryana/rails_ext.git :slight_smile:

Cheers,
Ryan

We already have Object#present? :slight_smile:

True, but present? is just the inverse of blank?. What we've found
very useful is to have a method that treats blank parameters the same
as missing ones, and allows chaining.

Check out the example:

  state = params[:state] unless params[:state].blank?
country = params[:country] unless params[:country].blank?
region = state || country || 'US'

Rewriting with present? isn't any more expressive:

  state = params[:state] if params[:state].present?
country = params[:country] if params[:country].present?
region = state || country || 'US'

But nonblank? makes it more concise and expressive IMO:

region = params[:state].nonblank? || params[:country].nonblank? ||
'US'

We've been using it this way for the last year and it really has
cleaned up a lot of code. More importantly it has become a reflex to
use it inline--as shown above--that has helped us avoid bugs where we
might think a parameter was present but really it was just there with
an empty value.

I suppose we could keep the method name present? but switch its
behavior to match what's proposed here for nonblank?. But that
contract change could break someone's code who was depending on a
boolean being returned. Also I prefer that nonblank? has a name that
parallels nonzero? from Ruby.

I like the symmetrical pair of nonzero? and nonblank? because they map
values (0, empty/blank string respectively) to nil that are typically
equivalent to not being present at all. Other languages like Python
found it convenient to have 0 and empty string treated as false for
just this reason I think.

-Colin

I see. But it does feel like code smell to me. And, you can always do
something like :

region = [params[:state], params[:country], 'US'].detect(&:present?)

Including all the items in an Array and picking the first present one circumvents any opportunity to use logic short-circuiting to avoid unnecessary, potentially expensive calculation, not to mention unnecessary allocation of container objects and the overhead of symbol-to-proc.

+1 for nonblank?

My biggest concern with nonblank? is that idiomatic Ruby is to return a boolean from question mark methods. I like Pratik’s solution, and would like to see a scenario where the short-circuit logic is important (and common enough to justify an core class extension).

Yehuda Katz
Developer | Engine Yard
(ph) 718.877.1325

A predicate returns a true or false value. Albeit an implementation may choose some particular true or false value for convenience, I think it is not a good practice for client code to depend on it.

I am -1 because I think a predicate should document only a boolean contract.

On the other hand it is something you can easily add to your app, as you've been doing.

I've also been adding a nonblank? method as soon as I find it useful on a project.

As for predicate methods returning true or false, the Numeric#nonzero? to which the OP compares nonblank? is a perfect counter example. The way that it was explained to me (by Jim Weirich, iirc) was that a predicate should return either false/true or nil/"not nil" (where "not nil" is typically a useful object). This is precisely how Numeric#nonzero? behaves.

I like nonblank? for the same reason that I dislike present? -- I *know* that " ".blank? is true, but " ".present? doesn't strike me as necessarily false like " ".nonblank? does.

-Rob

I see. But it does feel like code smell to me. And, you can always do
something like :

region = [params[:state], params[:country], 'US'].detect(&:present?)

Including all the items in an Array and picking the first present one
circumvents any opportunity to use logic short-circuiting to avoid
unnecessary, potentially expensive calculation, not to mention unnecessary
allocation of container objects and the overhead of symbol-to-proc.

Yes, that's too much overhead, Here's the benchmark:

state=nil; country='Canada';
Benchmark.bm(10) do |bm|
  bm.report("nonblank?") { n.times { region = state.nonblank? || country.nonblank? || 'US' } }
  bm.report("detect ") { n.times { region = [state.nonblank?, country, 'US'].select &:present? } }
end

                user system total real
nonblank? 0.210000 0.000000 0.210000 ( 0.212206)
detect 2.320000 0.070000 2.390000 ( 2.487010)

Over 10X slower! The above example doesn't emphasize short-circuiting
either. You could easily find examples that were 100X slower because
of complex expressions.

I definitely wouldn't write it that way. If I had to live without
nonblank?, this is what I'd write:

  region = (params[:state] unless params[:state].blank?) ||
               (params[:country] unless params[:country].blank?) ||
               'US'
but you can see that's not DRY since every argument is mentioned
twice. That's what led us to add nonblank?. It's concise, DRY, and
performs well.

My biggest concern with nonblank? is that idiomatic Ruby is to return a
boolean from question mark methods.

Generally that's true, but Ruby has nonzero? which behaves exactly
like nonblank?: you get a value back that is _equivalent_ to boolean
but has other uses too. Another Ruby example is =~ which returns nil
or an index, although that doesn't end in ?.

I like Pratik's solution, and would like to see a scenario where the short-circuit logic is important

I just grep'd our company's code base (65K LOC) and found 190 usages
of nonblank?, not including the definition and tests. About 70% are
using it as a boolean (we haven't used present? since that was
introduced in Rails 2.2 and we were on 2.1 until the end of the
summer) but 30% are the pattern discussed here. For example, from our
EmailAddress class:

  @friendly_name = tmail.name.nonblank? || friendly_name

I also found several cases where the mapping to nil was explicitly
important (because we wanted it to the be the same as "not present")
as in

  vid = cookies[:vid].nonblank?

Of the 70% that treat nonblank?'s result as a boolean, I didn't find a
single case that put !! in front to force the result to a proper
boolean. Likely that's because when you really want a true boolean, !
blank? reads best.

-Colin

ColinDKelley escreveu:

...
For example, this:

  state = params[:state] unless params[:state].blank?
  country = params[:country] unless params[:country].blank?
  region = state || country || 'US'

becomes:

  region = params[:state].nonblank? || params[:country].nonblank? || 'US'
  

...

Changing the subject a bit, I've just remembered a feature of Groovy's language that I like and think that Ruby lacks...

In Groovy:

result = object?.method?.another

would mean in Ruby something like:

result = object && object.method && object.method.another

I wonder if it would be possible to have a similar constructor in Ruby that was more DRY like in Groovy. Groovy's syntax would not be an option to Ruby since Ruby's methods accept method names ending with '?', which is not possible in Groovy. That is a good think but I can't think in an expressive annotation to be added to Ruby...

Maybe "object#.method?#.to_s". It definitely has nothing to do with Rails, but maybe there is some way of getting a similar result that is already implemented in ActiveSupport and that I don't know, so I hope you don't mind I ask it here...

If you do so, I'm sorry and I promise I won't do it again.

Regards,

Rodrigo.

I can see the use case, but I strongly dislike the use of the
predicate to get there. nonblank is a nasty method name too. I don't
think nonzero? is a great example of API design for us to follow. This
hinges on getting a stellar name that really sums it up and makes it
immediately apparent what's going on.

We just tried running through 20 candidates in the chat room and
didn't come up with anything worthwhile. We need something that's a
single word, like "present?" or "blank?" but doesn't use a predicate
and is exceptionally clear about what's going on.

DHH escreveu:

I can see the use case, but I strongly dislike the use of the
predicate to get there. nonblank is a nasty method name too. I don't
think nonzero? is a great example of API design for us to follow. This
hinges on getting a stellar name that really sums it up and makes it
immediately apparent what's going on.

We just tried running through 20 candidates in the chat room and
didn't come up with anything worthwhile. We need something that's a
single word, like "present?" or "blank?" but doesn't use a predicate
and is exceptionally clear about what's going on.

How about 'when_present' ?

Like:

object.when_present || another_object

It is not a single word, but it is expressive.

'or' would be great but there is a problem:

object.or another_object

The problem is that another_object would be evaluated always...

object.or || another_object # also does not look great...

What do you think?

Best regards,

Rodrigo.

We just tried running through 20 candidates in the chat room and
didn't come up with anything worthwhile. We need something that's a
single word, like "present?" or "blank?" but doesn't use a predicate
and is exceptionally clear about what's going on.

I gave it some more thought and came up with a great name:
Object#presence. It plays off the existing present? and offers
something nice and clear.

Commit is at http://github.com/rails/rails/commit/1c47d04ea5ac19601b316daf8fdc6f38c50eec73

Great suggestion, Colin. Love it with a great name.

Rodrigo,

Funny you should mention that! Hobo Support has the _? operator that
does just what you want. (They mention in the documentation that they
wanted it to be called ?, but had to go with ._? to be valid Ruby.)
We use _? extensively in our application and frankly couldn't live
without it. Here's a recent thread where I contributed a simplified
implementation of that method (inspired by ActiveRecord's
AssociationProxy BTW):

https://hobo.lighthouseapp.com/projects/8324/tickets/537-safenil-with-nil-public-methods-as-in-_to_i

Excellent! Glad it found a home. :slight_smile:

-Colin

No, no. Predicates return true or false _values_. The implementor
decides which one he wants to return, and it is not required/expected
that it is is one of the singletons true/false. In that sense nonzero?
is not a counter-example.

But you are not going to do arithmetic with the value returned by
nonzero? right?

Predicates should only have a boolean contract, the chosen returned
values shouldn't be documrented or relevant to client code.

ColinDKelley escreveu:


Changing the subject a bit, I've just remembered a feature of Groovy's
language that I like and think that Ruby lacks...
In Groovy:
result = object?.method?.another
would mean in Ruby something like:
result = object && object.method && object.method.another
I wonder if it would be possible to have a similar constructor in Ruby
that was more DRY like in Groovy. Groovy's syntax would not be an option
to Ruby since Ruby's methods accept method names ending with '?', which
is not possible in Groovy. That is a good think but I can't think in an
expressive annotation to be added to Ruby...

Rodrigo,
Funny you should mention that! Hobo Support has the _? operator that
does just what you want. (They mention in the documentation that they
wanted it to be called ?, but had to go with ._? to be valid Ruby.)
We use _? extensively in our application and frankly couldn't live
without it. Here's a recent thread where I contributed a simplified
implementation of that method (inspired by ActiveRecord's
AssociationProxy BTW):

Hi Colin, thank you for mentioning that.

Matt Jones has already pointed out me this in a private message shortly
after I sent this question.

Are there any chances this could make into ActiveResource too so that
we could benefit of using it in a vanilla Rails app?

I hope all of you have a great new year!

Best regards,

Rodrigo.

Well IMHO, I think it's more idiomatic Ruby to have a predicate only
worry about the truthiness or falsiness of what it returns. Any value
other than nil or false is a perfectly good, and true return value
from a predicate, and in many cases more useful.

Insisting that a predicate return either true or false, smells more
Java or C++ish than Rubyish to me.

But what do I know?

Wandering ever-more-offtopic, but does anybody know exactly why Ruby 1.9 whines when removing object_id? It warns that doing so "may cause serious problem", but I've never seen a discussion of exactly *what* problem. I noted (on the above ticket) that AssociationProxy and Scope carefully avoid undefining object_id, but is that solely because of the warning?

--Matt Jones