Project

General

Profile

Actions

Feature #6180

closed

to_b for converting objects to a boolean value

Added by AaronLasseigne (Aaron Lasseigne) over 12 years ago. Updated over 12 years ago.

Status:
Rejected
Target version:
-
[ruby-core:43502]

Description

When a boolean return value is required it has become common practice is to use "!!" to convert the object. It would be more consistent to provide a "to_b" method on Object.


Related issues 1 (0 open1 closed)

Has duplicate Ruby master - Feature #8273: Make it possible to treat objects as falsy in order to make NullObjects more convenientRejectedActions

Updated by drbrain (Eric Hodel) over 12 years ago

Why do you need to convert objects to boolean values?

Updated by AaronLasseigne (Aaron Lasseigne) over 12 years ago

Typically this comes up when you have a method ending in a question mark to indicate a boolean return value.

def foo?
!!@foo
end

def has_vowel?
!!(value =~ /[aeiou]/)
end

Updated by naruse (Yui NARUSE) over 12 years ago

BasicObject#! is optimized by YARV as following:

% ruby -e'puts RubyVM::InstructionSequence.compile(%[!!foo]).disasm'
== disasm: <RubyVM::InstructionSequence:@>==========
0000 trace 1 ( 1)
0002 putself
0003 send :foo, 0, nil, 24, ic:0
0009 opt_not ic:3
0011 opt_not ic:4
0013 leave

% rb -e'puts RubyVM::InstructionSequence.compile(%[foo.to_b]).disasm'
== disasm: <RubyVM::InstructionSequence:@>==========
0000 trace 1 ( 1)
0002 putself
0003 send :foo, 0, nil, 24, ic:0
0009 send :to_b, 0, nil, 0, ic:1
0015 leave

As showed above, its byte code is shorter than with new method.

Updated by AaronLasseigne (Aaron Lasseigne) over 12 years ago

I think that "to_b" is more clear and fits well with the other to_*. Using "!!" isn't the most obvious choice for people looking to create a boolean. I am a bit disheartened to find out that it's slower.

Updated by drbrain (Eric Hodel) over 12 years ago

It is even shorter if you just omit the !! or the to_b altogether:

$ ruby20 -e'puts RubyVM::InstructionSequence.compile(%[foo]).disasm'
== disasm: <RubyVM::InstructionSequence:@>==========
0000 trace 1 ( 1)
0002 putself
0003 send :foo, 0, nil, 24, ic:0
0009 leave

For ruby, it will Just Work to return the object in a method ending in a ?. There's no need to explicitly convert to a boolean value.

Updated by hasari (Hiro Asari) over 12 years ago

Also, to_b is ambiguous. 'b' can stand for "bits", "bytes", "binary", just to name a few.

Updated by trans (Thomas Sawyer) over 12 years ago

Also, what you are asking for should probably be called #to_bool.

Where as #to_b can have a broader, and generally more useful definition, e.g.

"true".to_b #=> true
"yes".to_b #=> true
"on".to_b #=> true

1.to_b #=> true
0.to_b #=> false

and other such useful humanistic forms of expressing truth.

Updated by AaronLasseigne (Aaron Lasseigne) over 12 years ago

@drbrain (Eric Hodel) - Very true but it is nice to be consistent with return values. It makes testing a little easier and fits a little better with the principle of least surprise.

@hasari (Hiro Asari) - to_s could easily be string or symbol. It doesn't seem unreasonable to use to_b for boolean. However, I'm not opposed to to_bool or to_boolean if needed. It's a little ugly but it could even be something like to_tf (to true/false).

@trans (Thomas Sawyer) - It seems to me like that could become difficult to manage across languages and cultural expectations. Also, that could be covered with "true?" and "false?" methods similar to how Rails has "blank?" and "present?" for strings. In fact it strikes me as something that's more Rails like than Ruby like but I don't know exactly why.

"yes".true? #=> true
"no".true? #=> false

1.true? #=> true
0.false? #=> true

Updated by trans (Thomas Sawyer) over 12 years ago

The only problem with that is that Ruby defines #nil? which is a strict check for NilClass instance. Hence #true? and #false? make more sense doing the same for TrueClass and FalseClass.

Updated by drbrain (Eric Hodel) over 12 years ago

=begin
If you're testing that a method returns exactly true and not a true value you're probably being over-specific in your tests. An assertion that a method returns a true value and not exactly true will allow the tests to be used unmodified after refactoring. Being overly specific by forcing exactly true or exactly false limits the flexibility of the tests.

In other words:

assert word.has_vowel?

is a better test than

assert_equal true, word.has_vowel?

as it allows the implementation to be more flexible.
=end

Updated by spatulasnout (B Kelly) over 12 years ago

drbrain (Eric Hodel) wrote:

Issue #6180 has been updated by drbrain (Eric Hodel).

Why do you need to convert objects to boolean values?

  1. To avoid breaking encapsulation. For example:

def connected?
!! @sv
end

In the above, @sv is an internal resource the caller is never intended
to access.

  1. To avoid looking obnoxious in logging statements.

@logger.trace("#{self.class.name} - #{method}: forcing reconnect, current status: connected=#{client.connected?.inspect}")

I want that to print: "current status: connected=false"

Not: "current status: connected="

Personally I don't mind !! as once one learns the idiom, its intent
would seem to be fairly unambiguous.

Regards,

Bill

Updated by regularfry (Alex Young) over 12 years ago

On 21/03/12 01:44, trans (Thomas Sawyer) wrote:

Issue #6180 has been updated by trans (Thomas Sawyer).

Also, what you are asking for should probably be called #to_bool.

Where as #to_b can have a broader, and generally more useful definition, e.g.

"true".to_b #=> true
"yes".to_b #=> true
"on".to_b #=> true

1.to_b #=> true
0.to_b #=> false

and other such useful humanistic forms of expressing truth.

This would be most useful as a protocol for if statements so that
classes could define their own notion of falsity. This is not
dissimilar to my null proposal from a few months back.

--
Alex


Feature #6180: to_b for converting objects to a boolean value
https://bugs.ruby-lang.org/issues/6180#change-24992

Author: AaronLasseigne (Aaron Lasseigne)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:

When a boolean return value is required it has become common practice is to use "!!" to convert the object. It would be more consistent to provide a "to_b" method on Object.

Updated by aef (Alexander E. Fischer) over 12 years ago

I too would very much like to see a #to_bool method on every object.

In my opinion, if you define a public API, you should be as strict as possible about what each method returns, so that your users can rely on it, but also to minimize the possible usage scenarios of the API. The latter one helps me as developer to keep the API working for a maximum amount of users after I changed internal aspects. Because of this I always cast return values of question mark methods into true or false (some languages would call it Boolean for simplicity) with the double ! operator, which I think is ugly because its not so obvious what the operator does at first.

I do this because I imagine people using the output in ways that I surely didn't intend nor that I will support after changes. In some cases they could even circumvent my public API. I think that an object should protect its encapsulation so that, if you want to break the encapsulation (circumvent the public API) by force (which is possible most of the times in Ruby), you have to do it knowingly.

A small example:

object.value = "valid string"
object.value?

=> "valid string"

object.value?.insert(0, "in")
object.value?

=> "invalid string"

This works if the returned object is a String, Array, Hash, Set or any oder mutable object. To prohibit such usage I could use #freeze, which does not protect deep structures perfectly out of the box and may be unhandy for further usage of the returned object or I could #dup or #clone the object before giving it out, which will probably need more processing power than simply returning a boolean casted value, either through !! or #to_bool.

Updated by mame (Yusuke Endoh) over 12 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

Updated by matz (Yukihiro Matsumoto) over 12 years ago

  • Status changed from Assigned to Rejected

to_b is not acceptable, since it's very ambiguous.
to_bool might be more descriptive then !! but I am not sure where to use them.
And if (and other control structures) will never call bool conversion method in the future, for both simplicity and performance.

Matz.

Updated by AaronLasseigne (Aaron Lasseigne) over 12 years ago

I understand that the Ruby way leans on true and false like values rather than a strict use of true and false. The use case here is encapsulating data that you might not want to expose when returning from a "?" method and, at an individuals discretion, creating a less verbose return value that is slightly easier to read when debugging. In my opinion to_bool is a more consistent and understandable type conversion than "!!" in these situations. This is a fairly minor request and probably not worth more discussion. Thank you everyone for reviewing it in a timely manor.

P.S. Matz, congrats on your recent award.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0