Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: wrong argument type with Ruby &~ operator

I try to compare flags in my Ruby application.

I have this code :

if self.flag &~ flag == self.flag
        return false

But it won't run. I've narrowed the problem to this :

irb(main):020:0> my_user.flag
=> 1
irb(main):021:0> flag
=> 128
irb(main):022:0> my_user.flag.class
=> Fixnum
irb(main):023:0> flag.class
=> Fixnum
irb(main):024:0> my_user.flag &~ flag
TypeError: wrong argument type Fixnum (expected Proc)

That is really disturbing since it works like this :

irb(main):025:0> 1 &~ 128
=> 1
like image 848
Mat Avatar asked Sep 27 '22 00:09

Mat


1 Answers

The difference between 1 &~ 128 and my_user.flag &~ flag is that the second expression involves a dot-method call. That changes the way the subsequent tokens are interpreted.

Try this:

# works
my_user.flag() &~ flag

# also works
(my_user.flag) &~ flag

# best
my_user.flag & ~flag

You'll find that it works. This is because adding () or moving ~ changes the order of operations to be more in line with what you expected.

The original method call you're using is actually interpreted by Ruby as:

# bad
my_user.flag(&(~flag))

This order of operations first flips the bits in flag by applying the ~ operator, then attempts to call to_proc on the resulting Fixnum because of the application of the & (cast-as-block) operator, and then finally attempts (had that not thrown a TypeError) to pass it as a block argument to the User#flag method.

like image 171
user513951 Avatar answered Nov 04 '22 20:11

user513951