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

69 views
Skip to first unread message

ColinDKelley

unread,
Dec 26, 2009, 9:19:01 PM12/26/09
to Ruby on Rails: Core
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.

Pratik

unread,
Dec 27, 2009, 8:37:51 AM12/27/09
to rubyonra...@googlegroups.com
We already have Object#present? :)

> --
>
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To unsubscribe from this group, send email to rubyonrails-co...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
>
>
>

--
Cheers!
- Pratik
http://m.onkey.org | http://twitter.com/lifo

Ryan Angilly

unread,
Dec 27, 2009, 11:37:31 AM12/27/09
to rubyonra...@googlegroups.com
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  :)


Cheers,
Ryan

ColinDKelley

unread,
Dec 27, 2009, 11:58:25 AM12/27/09
to Ruby on Rails: Core
> We already have Object#present? :)

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


On Dec 27, 5:37 am, Pratik <pratikn...@gmail.com> wrote:
> We already have Object#present? :)
>
>
>
>
>
> On Sun, Dec 27, 2009 at 7:49 AM, ColinDKelley <colindkel...@gmail.com> wrote:
> > 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/3...

Pratik

unread,
Dec 27, 2009, 12:19:18 PM12/27/09
to rubyonra...@googlegroups.com
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?)

Duncan Beevers

unread,
Dec 27, 2009, 1:43:00 PM12/27/09
to rubyonra...@googlegroups.com
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?

Yehuda Katz

unread,
Dec 27, 2009, 2:51:17 PM12/27/09
to rubyonra...@googlegroups.com
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

Xavier Noria

unread,
Dec 27, 2009, 3:20:22 PM12/27/09
to rubyonra...@googlegroups.com, Ruby on Rails: Core
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.

Sent from my iPhone

El 27/12/2009, a las 17:58, ColinDKelley <colind...@gmail.com>
escribió:

> To post to this group, send email to rubyonrails-
> co...@googlegroups.com.

Rob Biedenharn

unread,
Dec 27, 2009, 7:28:46 PM12/27/09
to rubyonra...@googlegroups.com
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

ColinDKelley

unread,
Dec 27, 2009, 8:30:35 PM12/27/09
to Ruby on Rails: Core
On Dec 27, 9:19 am, Pratik <pratikn...@gmail.com> wrote:
> 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?)

On Dec 27, 10:43 am, Duncan Beevers <duncanbeev...@gmail.com> wrote:
> 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.

On Dec 27, 11:51 am, Yehuda Katz <wyc...@gmail.com> wrote:
> 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

Rodrigo Rosenfeld Rosas

unread,
Dec 27, 2009, 8:31:21 PM12/27/09
to rubyonra...@googlegroups.com
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.

DHH

unread,
Dec 27, 2009, 8:37:24 PM12/27/09
to Ruby on Rails: Core
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

Rodrigo Rosenfeld Rosas

unread,
Dec 27, 2009, 8:55:28 PM12/27/09
to rubyonra...@googlegroups.com
DHH escreveu:
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.

DHH

unread,
Dec 27, 2009, 8:56:42 PM12/27/09
to Ruby on Rails: Core
> 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.
--
DHH

ColinDKelley

unread,
Dec 28, 2009, 12:37:07 AM12/28/09
to Ruby on Rails: Core
On Dec 27, 5:31 pm, Rodrigo Rosenfeld Rosas <rr.ro...@gmail.com>
wrote:

> 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):

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

ColinDKelley

unread,
Dec 28, 2009, 12:38:20 AM12/28/09
to Ruby on Rails: Core
Excellent! Glad it found a home. :-)

-Colin

On Dec 27, 5:56 pm, DHH <david.heineme...@gmail.com> wrote:
> > 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 athttp://github.com/rails/rails/commit/1c47d04ea5ac19601b316daf8fdc6f38...

Xavier Noria

unread,
Dec 28, 2009, 3:28:54 AM12/28/09
to rubyonra...@googlegroups.com
On Mon, Dec 28, 2009 at 1:28 AM, Rob Biedenharn
<rob.bie...@gmail.com> wrote:

> 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.

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.

Rodrigo Rosenfeld Rosas

unread,
Dec 28, 2009, 8:53:04 AM12/28/09
to rubyonra...@googlegroups.com
ColinDKelley escreveu:
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.

Rick DeNatale

unread,
Dec 28, 2009, 10:07:00 AM12/28/09
to rubyonra...@googlegroups.com
On Sun, Dec 27, 2009 at 2:51 PM, Yehuda Katz <wyc...@gmail.com> wrote:
> 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

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?

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Matt Jones

unread,
Dec 28, 2009, 10:27:45 AM12/28/09
to rubyonra...@googlegroups.com

On Dec 28, 2009, at 12:37 AM, ColinDKelley wrote:

>
> 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

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

Josh Susser

unread,
Dec 28, 2009, 1:04:33 PM12/28/09
to rubyonra...@googlegroups.com
This whole discussion is caused by the way Rails handles form
submissions of text fields. If a user enters no value, the controller
action gets a param that is an empty string instead of nil. That's
probably the simplest thing to do in most cases, but the implication
is that model attributes will have empty strings instead of nil in the
record. That means you can't do the idiomatic Ruby:

user.nickname || user.name

Now we have #presence which lets us do:

user.nickname.presence || user.name

That's reasonably concise, but just keep in mind that all of this is
just to make Ruby act more like Perl where empty strings are false-ish
values. I'm sure there are other use cases for #presence, but empty
strings that come from form submissions seem like at least 90% of the
issue.

--josh

> --
>
> You received this message because you are subscribed to the Google
> Groups "Ruby on Rails: Core" group.

> To post to this group, send email to rubyonrails-
> co...@googlegroups.com.


> To unsubscribe from this group, send email to rubyonrails-co...@googlegroups.com
> .

> For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en
> .
>
>

--
Josh Susser
http://blog.hasmanythrough.com

ColinDKelley

unread,
Dec 28, 2009, 5:35:35 PM12/28/09
to Ruby on Rails: Core
Josh,

I agree that this usage comes up often in controllers, but it is
common in models too. It seems to me that this issue comes up any
time you want to map the "empty"/"blank" value to be the same as the
"not present" value, whether those came from a form, the database, or
read from a file... Yes, if Ruby had chosen empty strings to be false-
ish (like Perl & Python) that would have helped.

Numeric is exactly parallel, where it's often appropriate to map 0 to
be the same as the "not present" value, nil. nonzero? does that,
which can make up for the fact that Ruby considers 0 to be true-ish.

(BTW whenever possible we choose our string attributes to be null =>
false in the DB so we don't have to write code that deals with two
types of empty. Of course there are cases when you really want a
blank/empty string to be one kind of empty and nil/NULL to be another,
but that is << 1% case IME.)

Do Rails forms have any convention for posting the "nil" value?
They've now got the special _delete key for nested forms. It seems
like it would be valuable to have a similar special representation to
indicate that a column should be set to nil. (We were doing some
composed_of attributes last month and really would have found that
handy. Instead we have ugliness in our controller to impose a
convention like that on the params values before updating the model.)

-Colin

Andrew White

unread,
Dec 29, 2009, 1:27:44 AM12/29/09
to rubyonra...@googlegroups.com
On 28 Dec 2009, at 18:04, Josh Susser wrote:

> That's reasonably concise, but just keep in mind that all of this is
> just to make Ruby act more like Perl where empty strings are false-ish
> values. I'm sure there are other use cases for #presence, but empty
> strings that come from form submissions seem like at least 90% of the
> issue.

Maybe we could eliminate that use case by nullifying blank strings where appropriate:

http://github.com/pixeltrix/nullify_blanks

The empty strings in my databases always bugged me so I wrote the above plugin to fix that. It only nullifies a blank string where a column exists, is a text column and accepts nulls.


Andrew

Allen Madsen

unread,
Dec 29, 2009, 7:40:03 AM12/29/09
to rubyonra...@googlegroups.com
Andrew,

I think the problem is that there is no way to distinguish between a nil value and a blank value coming from the request. They both look the same and they both have their uses. I don't think your solution solves this problem, because there are likely cases like above where blank has significance.
--

You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To post to this group, send email to rubyonra...@googlegroups.com.

Chris Cruft

unread,
Dec 29, 2009, 11:17:26 AM12/29/09
to Ruby on Rails: Core
Josh nailed it. This issue of empty strings coming back from forms
has been around for eons (in Rails' hyperspeed timeframe). Firing up
the wayback machine, we see this:

http://dev.rubyonrails.org/ticket/5694

BTW, here's my take on a solution using a before filter to recursively
coerce empty strings to nil:

http://gist.github.com/265388

Scratch the HTML forms itch, and perhaps the need for another method
on Object falls below the threshold of irritation.

One last thought: does Ruby 1.9 provide any guidance here?

Andrew White

unread,
Dec 29, 2009, 12:18:40 PM12/29/09
to rubyonra...@googlegroups.com
On 29 Dec 2009, at 12:40, Allen Madsen wrote:

> I think the problem is that there is no way to distinguish between a nil value and a blank value coming from the request. They both look the same and they both have their uses. I don't think your solution solves this problem, because there are likely cases like above where blank has significance.

In the case where a column is set to :null => false then the plugin won't nullify the value. I don't know about your end users but mine wouldn't understand the difference between a nil value and an empty string - relying on them to determine what a value should be is not something I want to push on them. Also blank number fields are already converted to nil.


Andrew

mdeering

unread,
Dec 29, 2009, 12:54:20 PM12/29/09
to Ruby on Rails: Core
I run a similar approach of normalizing the data to nil (or some base
standard) but do it at the model level rather then dealing with the
params directly. http://github.com/mdeering/attribute_normalizer
Error in the current docs returning from a block but you get the idea.

Cheers,
Mike D.

ColinDKelley

unread,
Dec 29, 2009, 1:00:23 PM12/29/09
to Ruby on Rails: Core
On Dec 28, 7:27 am, Matt Jones <al2o...@gmail.com> wrote:
> 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?

Yes, we've all been wondering what the risk is there. Worst case I
guess we could grep through the Ruby source I suppose.

Tom Locke on the Hobo project wondered

> OTOH maybe it's like crossing the [streams] in Ghostbusters: you just don't do it and you don't ask why : )

I've never been a fan of superstition though. Doesn't that just lead
to a "cargo cult?" :-)

I wondered if maybe Object#equal? used object_id to determine if the
two objects were the same. But that theory was disproven by a test
that undef'd it first: equal? ran just fine. I even tried def'ing
equal? to raise an exception and that showed it never got invoked by
equal? anyway.

-Colin

Allen Madsen

unread,
Dec 29, 2009, 1:22:37 PM12/29/09
to rubyonra...@googlegroups.com
I believe ruby uses it internally to track the objects. If you change or remove the object_id, then nothing will be referencing that object and the garbage collector will eat it up. All this is heresay though, until someone confirms it.
--

You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To post to this group, send email to rubyonra...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages