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 Added Object#presence that returns the object if it's #present? other… · rails/rails@1c47d04 · GitHub

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