Attribute query methods and semantics

Does anyone else finds attribute query methods semantically confusing?

Hi,

Consider this code:

post = Post.new(:visible => true, :url => “http://com”)

if post.visible?

puts “ima visible!”

end

if post.url?

puts “ima url! (wait wat? o_0)”

end

Does this feel right to you? In case with post.url? i read it as “Hey post object, are you an url?” which is apparently not what the code will do.

So it seems like semantically perfect flag checks go together with totally confusing(for a reader) way of checking whether an attribute is present or not.

I would generate attribute query methods only for boolean attributes.

Regards, Max

I am not sure that I understand your point, but in Ruby anything that
is neither nil nor false is true. Thus returning the url string, if
not nil, is the same as saying that it is true but also allows access
to the actual data without having to send another message.

my point is about semantics, not truthiness/falseness of values

post.visible? - is asking post object if it is visible because it has

a flag(boolean attribute) named ‘visible’

post.url? - is checking if attribute named ‘url’ is present or not, and

that is exactly what i find confusing because even though

syntactically it is identical to flag check, semantically this line looks

like we’re asking post object if it is a url which makes no sense.

Regards, Max

I think Max’s point is that “post.visible?” could be read as “post is visible?” but “post is url?” carries a different meaning.

Sam

I would generate attribute query methods only for boolean attributes.

I am not sure that I understand your point, but in Ruby anything that

is neither nil nor false is true. Thus returning the url string, if

not nil, is the same as saying that it is true but also allows access

to the actual data without having to send another message.

I think Max’s point is that “post.visible?” could be read as “post is visible?” but “post is url?” carries a different meaning.

Maybe have query methods for boolean attributes and prefixed query methods for not. e.g.
post.visible?
post.has_url?

Or maybe leave the currently methods as they are, but add new prefixed methods, with different prefixes for boolean methods, e.g.

post.is_visible?
post.has_url?

I’m -1 on a has_* method

If we want to kill ? on non boolean attributes we should encourage standard @post.url.blank? and @post.url.present? be used instead. The originally proposed change makes sense to me. The question mark character adds nice semantics to boolean attributes. I agree it’s not clear what exactly that would do on non-boolean attributes. Removing the questionable methods would help decrease the method count.

Does anyone really need to use: @post.id?

+1 to Richard. Keep ? for booleans, get rid of the others and use .blank? and .present? as needed.

absolutely agree with all points. i just didn’t know if methods count

argument is relevant at all. imo it’s a nice side-effect of proposed

change.

I’d guess methods count is relevant based on this pull request:

https://github.com/rails/rails/pull/5763

Not using is_ is idiomatic:
http://devblog.avdi.org/2011/04/07/rspec-is-for-the-literate/ (look
for 'There is a different, but related, effect of using RSpec.')

Every Ruby object is truthy or falsey, and so treating them all as
possibly boolean is 100% okay as far as I'm concerned.

Actually the query attribute method does more than check if the value is present. It is very useful for legacy databases where the user persist boolean values as [0, 1], [“t”, “f”], [“true”, “false”] and more.

I don’t see this being removed from rails or changing your behavior.

Also removing it will not decrease the methods count because we still need to generate it for booleans.

Rafael Mendonça França
http://twitter.com/rafaelfranca
https://github.com/rafaelfranca

Actually the query attribute method does more than check if the value is present. It is very useful for legacy databases where the user persist boolean values as [0, 1], ["t", "f"], ["true", "false"] and more.

I don't see this being removed from rails or changing your behavior.

I agree with you on that

Also removing it will not decrease the methods count because we still need to generate it for booleans.

It would decrease because they would *only* be generated for boolean fields.

@ Rafael Mendonça França

legacy databases storage must be concern of corresponding database
adapter, if a field is of boolean type, whatever that means on storage

level of particular database, that field must be treated as boolean in rails

on the model level.

i’m not suggesting to drop such functionality for boolean attributes, only

for non-booleans where #{attribute}? literally makes no sense when you

read it.

methods count would be decreased because rails would generate query

method only for boolean attributes.

@ Steve Klabnik

syntactically you are correct

but if we decide that there doesn’t have to be semantical contribution to

your code from using attribute query methods then #{attribute}? is just

a shortcut for !!#{attribute} - so why do we need it in the first place?

saving 1 character is weird goal here.

if on the other hand we want query methods to provide semantics then

there is obvious conflict with non-boolean fields as semantics there are

different.

but if we decide that there doesn't have to be semantical contribution to
your code from using attribute query methods then #{attribute}? is just
a shortcut for !!#{attribute} - so why do we need it in the first place?
saving 1 character is weird goal here.

It's not saving a character. It's that !! is programmer talk, and ? is
human talk. Ruby prefers human talk.

I guess Rafael meant another thing. You have boolean fields in PostgreSQL but someone might prefer to use some old ANSI types, like INTEGER for storing such booleans for some reason.

And in these cases you don’t know if these fields are boolean or not. If you are choose to store the visible column as string [“yes”, "no] so you will not have the query method.

I like this method as it is. For me it is very useful and give me the possibility to not care about what is the datatype of the field.

Rafael Mendonça França
http://twitter.com/rafaelfranca
https://github.com/rafaelfranca

Actually PG do support the ANSI boolean type. But some will prefer
some other ANSI type because other databases don’t support the
boolean type:

http://en.wikipedia.org/wiki/SQL:1999#Boolean_data_types

Another way would add another annotation method to
ActiveRecord::Base, like:

boolean_field :incomplete, :disabled, :deleted

This would further document the model mapping and would also allow

better semantics.

Not that I really care about this as I don't even use ActiveRecord

:wink:

Cheers,

Rodrigo.

It’s not saving a character. It’s that !! is programmer talk, and ? is

human talk. Ruby prefers human talk.

well your kung-fu beats my kung-fu here

i just don’t think post.url? is talking proper human talk to me, i would

expect answer to that question to be “no, post is not a url” instead i

will get “yes, url attribute is not empty”.

I guess Rafael meant another thing. You have boolean fields in
PostgreSQL but someone might prefer to use some old ANSI types, like
INTEGER for storing such booleans for some reason.

i think that first of all this is rather an edge-case that shouldn’t force

us to go against least surprise principle

second - this directly goes against Steve’s assumption that

post = Post.new

post.id = 0

assert post.id?

should not fail (it fails because 0 is apparently false… since when?)

i personally think this smells a lot like PHP and it’s non-logical,

generally ugly and wrong truthiness/falseness checks

Maybe it is just me, but I don’t use features that I don’t like in rails, just like I avoid calling private methods. In that sense, there’s nothing that is preventing anyone from using post.body.present? instead of post.body?. My argument would be to let rational programmers decide what is best for their specific case. If you’re on a team, set a style guide that picks a winner.

Allen Madsen
http://www.allenmadsen.com