Feature #12753
closedUseful operator to check bit-flag is true or false
Added by tagomoris (Satoshi Tagomori) over 8 years ago. Updated about 7 years ago.
Description
Ruby's 0 is truthy value. It's useful for many cases, but it's confusing and I made many bugs when I'm writing code to handle binary data, because my thought is almost same with one to write C code in such situation.
n = get_integer_value
if n & 0b10100000
# code for the case when flag is true
else
# never comes here :(
end
IMO it's very useful to have methods for such use-cases, like #and?
and #xor?
(#or?
looks not so useful... I can't imagine the use case of this operator, but it's better to have for consistency).
n = get_integer_value
case
when n.and?(0b10000000)
# negative signed char
when n.and?(0b01110000)
# large positive
else
# small positive
end
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
- Description updated (diff)
Updated by matz (Yukihiro Matsumoto) about 8 years ago
I understand the demand. But and?
is an unacceptable name.
Any idea?
Matz.
Updated by naruse (Yui NARUSE) about 8 years ago
What about bittest?
Updated by matz (Yukihiro Matsumoto) about 8 years ago
bittest?
sounds reasonable. Accepted.
Matz.
Updated by herwinw (Herwin Quarantainenet) about 8 years ago
I can't say the usage of bittest?
is directly clear to me. Does it test if resulting integer is not equal to 0
? And would we have to use it this way?
if (n & 0b10100000).bittest?
I think a name like Integer#binary_and?
(maybe shortened to #binand?
) would result in cleaner code
if n.binary_and?(0b10100000)
Of course this would require several other implementations as well, for all other binary operators
Updated by naruse (Yui NARUSE) about 8 years ago
Herwin Quarantainenet wrote:
I can't say the usage of
bittest?
is directly clear to me. Does it test if resulting integer is not equal to0
? And would we have to use it this way?if (n & 0b10100000).bittest?
Like
if n.bittest?(0b10100000)
I think a name like
Integer#binary_and?
(maybe shortened to#binand?
) would result in cleaner codeif n.binary_and?(0b10100000)
Of course this would require several other implementations as well, for all other binary operators
There's two AND, bitwise and logical.
Therefore it can be bit_and?
, but there's no reason to write logical AND as a method, which can be written with &&
.
Updated by herwin (Herwin W) about 8 years ago
if n.bittest?(0b10100000)
If I encountered that code without having the context of this case, I wouldn't know what what the equivalent behaviour would be:
if n & 0b10100000 != 0 #=> Is at least one bit of the argument set?
if n & 0b10100000 == 0b10100000 #=> Are all the bits of the argument set?
There's two AND, bitwise and logical.
Therefore it can be bit_and?, but there's no reason to write logical AND as a method, which can be written with &&.
I was actually thinking about the other bitwise/binary operators here, like |
and ^
Updated by naruse (Yui NARUSE) about 8 years ago
Herwin W wrote:
if n.bittest?(0b10100000)
If I encountered that code without having the context of this case, I wouldn't know what what the equivalent behaviour would be:
if n & 0b10100000 != 0 #=> Is at least one bit of the argument set? if n & 0b10100000 == 0b10100000 #=> Are all the bits of the argument set?
Above one.
There's two AND, bitwise and logical.
Therefore it can be bit_and?, but there's no reason to write logical AND as a method, which can be written with &&.I was actually thinking about the other bitwise/binary operators here, like
|
and^
I can't show a use case of |
.
^
is maybe useful but the name is difficult.
Updated by shugo (Shugo Maeda) about 8 years ago
Yui NARUSE wrote:
Herwin W wrote:
if n.bittest?(0b10100000)
If I encountered that code without having the context of this case, I wouldn't know what what the equivalent behaviour would be:
if n & 0b10100000 != 0 #=> Is at least one bit of the argument set? if n & 0b10100000 == 0b10100000 #=> Are all the bits of the argument set?
Above one.
IBM InfoSphere and MS FoxPro have BITTEST(), but its second argument is the bit position
to be tested.
http://www.ibm.com/support/knowledgecenter/SSZJPZ_11.3.0/com.ibm.swg.im.iis.ds.basic.doc/topics/r_dsbasic_BITTEST_function.html
https://msdn.microsoft.com/en-us/library/aa977348(v=vs.71).aspx
This behavior seems to fit the name bittest, compared to the proposed one.
Updated by shugo (Shugo Maeda) about 8 years ago
Shugo Maeda wrote:
IBM InfoSphere and MS FoxPro have BITTEST(), but its second argument is the bit position
to be tested.http://www.ibm.com/support/knowledgecenter/SSZJPZ_11.3.0/com.ibm.swg.im.iis.ds.basic.doc/topics/r_dsbasic_BITTEST_function.html
https://msdn.microsoft.com/en-us/library/aa977348(v=vs.71).aspxThis behavior seems to fit the name bittest, compared to the proposed one.
I didn't mean to propose this behavior.
I just meant to point out that bittest?
may not be suitable for the proposed behavior.
Updated by tagomoris (Satoshi Tagomori) over 7 years ago
How about bitmask_test?
or bitflag_test?
shugo (Shugo Maeda) wrote:
Shugo Maeda wrote:
IBM InfoSphere and MS FoxPro have BITTEST(), but its second argument is the bit position
to be tested.http://www.ibm.com/support/knowledgecenter/SSZJPZ_11.3.0/com.ibm.swg.im.iis.ds.basic.doc/topics/r_dsbasic_BITTEST_function.html
https://msdn.microsoft.com/en-us/library/aa977348(v=vs.71).aspxThis behavior seems to fit the name bittest, compared to the proposed one.
I didn't mean to propose this behavior.
I just meant to point out thatbittest?
may not be suitable for the proposed behavior.
Updated by akr (Akira Tanaka) about 7 years ago
How about Integer#has_allbits?(n), Integer#has_somebits?(n) and Integer#has_nobits?(n) ?
class Integer
def has_allbits?(n) self & n == n end
def has_somebits?(n) self & n != 0 end
def has_nobits?(n) self & n == 0 end
end
Updated by matz (Yukihiro Matsumoto) about 7 years ago
has_*
is not acceptable. It's not compatible with other method names.
I vote for allbit?
, anybit?
and nobit?
. I am not sure about plurality though.
Matz.
Updated by knu (Akinori MUSHA) about 7 years ago
Speaking of plurality, what about:
a.bit?(b)
→ a & b != 0
a.bits?(b)
→ a & b == b
Updated by phluid61 (Matthew Kerwin) about 7 years ago
I think plural makes most sense:
a.allbits? b #→ a & b == b
a.anybits? b #→ a & b != 0
a.nobits? b #→ a & b == 0
It introduces a strange paradox, though:
a.allbits? 0 #→ true
a.nobits? 0 #→ true
Updated by aycabta (aycabta .) about 7 years ago
phluid61 (Matthew Kerwin) wrote:
It introduces a strange paradox, though:
a.allbits? 0 #→ true a.nobits? 0 #→ true
I discussed it with @watson1978 (Shizuo Fujita) (Shizuo Fujita). We guess the behavior is not strange.
The allbits? means "The receiver checks that all standing bits of the argument don't sit on itself".
a.allbits? 0 #→ true
In this case, "all standing bits of the argument don't sit on the receiver " because "all standing bits of argument" is nothing. So it returns true. I think this is correct. If I have to choose a word, it's reasonable specification.
a.nobits? 0 #→ true
I think this is correct in the same way.
Updated by naruse (Yui NARUSE) about 7 years ago
- Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
- Target version set to 2.5
A patch is as follows:
diff --git a/numeric.c b/numeric.c
index 1858113c09..511155a3ac 100644
--- a/numeric.c
+++ b/numeric.c
@@ -3209,6 +3209,45 @@ int_even_p(VALUE num)
return Qfalse;
}
+/*
+ * call-seq:
+ * int.allbits?(mask) -> true or false
+ *
+ * Returns +true+ if all bits of <code>+int+ & +mask+</code> is 1.
+ */
+
+static VALUE
+int_allbits_p(VALUE num, VALUE mask)
+{
+ return rb_int_equal(rb_int_and(num, mask), mask);
+}
+
+/*
+ * call-seq:
+ * int.anybits?(mask) -> true or false
+ *
+ * Returns +true+ if any bits of <code>+int+ & +mask+</code> is 1.
+ */
+
+static VALUE
+int_anybits_p(VALUE num, VALUE mask)
+{
+ return num_zero_p(rb_int_and(num, mask)) ? Qfalse : Qtrue;
+}
+
+/*
+ * call-seq:
+ * int.nobits?(mask) -> true or false
+ *
+ * Returns +true+ if no bits of <code>+int+ & +mask+</code> is 1.
+ */
+
+static VALUE
+int_nobits_p(VALUE num, VALUE mask)
+{
+ return num_zero_p(rb_int_and(num, mask));
+}
+
/*
* Document-method: Integer#succ
* Document-method: Integer#next
@@ -5396,6 +5435,9 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, "integer?", int_int_p, 0);
rb_define_method(rb_cInteger, "odd?", int_odd_p, 0);
rb_define_method(rb_cInteger, "even?", int_even_p, 0);
+ rb_define_method(rb_cInteger, "allbits?", int_allbits_p, 1);
+ rb_define_method(rb_cInteger, "anybits?", int_anybits_p, 1);
+ rb_define_method(rb_cInteger, "nobits?", int_nobits_p, 1);
rb_define_method(rb_cInteger, "upto", int_upto, 1);
rb_define_method(rb_cInteger, "downto", int_downto, 1);
rb_define_method(rb_cInteger, "times", int_dotimes, 0);
diff --git a/test/ruby/test_integer_comb.rb b/test/ruby/test_integer_comb.rb
index 80d08cac04..1ad13dd31b 100644
--- a/test/ruby/test_integer_comb.rb
+++ b/test/ruby/test_integer_comb.rb
@@ -457,6 +457,30 @@ def test_even_odd
}
end
+ def test_allbits_p
+ VS.each {|a|
+ VS.each {|b|
+ assert_equal((a & b) == b, a.allbits?(b), "(#{a}).allbits?(#{b}")
+ }
+ }
+ end
+
+ def test_anybits_p
+ VS.each {|a|
+ VS.each {|b|
+ assert_equal((a & b) != 0, a.anybits?(b), "(#{a}).anybits?(#{b}")
+ }
+ }
+ end
+
+ def test_nobits_p
+ VS.each {|a|
+ VS.each {|b|
+ assert_equal((a & b) == 0, a.nobits?(b), "(#{a}).nobits?(#{b}")
+ }
+ }
+ end
+
def test_to_s
2.upto(36) {|radix|
VS.each {|a|
Updated by aycabta (aycabta .) about 7 years ago
Hi @naruse (Yui NARUSE), matz said below.
matz (Yukihiro Matsumoto) wrote:
I vote for
allbit?
,anybit?
andnobit?
. I am not sure about plurality though.
For your action, as you know, Dir.exists? and File.exists? are deprecated. What do you think about this?
Updated by phluid61 (Matthew Kerwin) about 7 years ago
aycabta (ayca bta) wrote:
Hi @naruse (Yui NARUSE), matz said below.
matz (Yukihiro Matsumoto) wrote:
I vote for
allbit?
,anybit?
andnobit?
. I am not sure about plurality though.For your action, as you know, Dir.exists? and File.exists? are deprecated. What do you think about this?
exist/exists is tense, bit/bits is plurality, so it is unrelated.
Updated by aycabta (aycabta .) about 7 years ago
phluid61 (Matthew Kerwin) wrote:
exist/exists is tense, bit/bits is plurality, so it is unrelated.
Oh, thank you...I understand.
Updated by aycabta (aycabta .) about 7 years ago
In Ruby 2.5, Ripper::Lexer::State is introduced:
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/60945/entry/ext/ripper/lib/ripper/lexer.rb#L49
It is for lex_state of parse.y, and has #& and #| for bit operations with lex_state_bits:
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/60945/entry/parse.y#L78
RDoc uses it:
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/60945/entry/lib/rdoc/parser/ripper_state_lex.rb#L321
If Integer#allbit? is implemented at 2.5, it's good for Ripper::Lexer::State and I'll use it for RDoc on 2.5.
Updated by naruse (Yui NARUSE) about 7 years ago
- Status changed from Assigned to Closed
Applied in changeset trunk|r61147.
Integer#allbits?, Integer#anybits?, Integer#nobits? [Feature #12753]
Updated by marcandre (Marc-Andre Lafortune) about 7 years ago
When writing specs, I discovered that coercion was failing for allbits.
I modified all three methods to apply coercion with to_int
if needed.