Pergunta

I need a class that can represent probabilities. It can be represented like a float between 0 and 1, and anything below 0.5 should evaluate to false. (or it can be between 1 and -1, anything negative is false)

p = A.probability() 
puts p # will output 0.3
if(p)
  puts 'success'
else
  puts 'failure'
end
# will outputs 'failure'

From this post it seems to suggest it is possible: every object has a boolean value... Most objects in Ruby will have a boolean value of true. Only two objects have a boolean value of false. Just that I need to set this boolean value somehow. So is this possible?

Foi útil?

Solução

I wanted to do something similar, but unfortunately this is not possible in Ruby.

The only two objects that have a boolean value of false are false itself and nil. A few weeks ago I had a an internet chat (IRC) discussion with Brixen, one of the main developers of rubinius, and he explained it pretty well. My understanding is that when Ruby decides whether an object is true or not, it does NOT call any methods on (i.e. send any messages to) the object, it simply looks at the pointer it has to the object to see whether the pointer itself is equal to false or nil. Since it doesn't call any methods on the object, there is no way for you to change the behavior.

The best you can do is something like this:

p = A.probability() 
puts p # => 0.3
if p.to_bool
  puts 'success'
else
  puts 'failure'
end

Outras dicas

There is no "cast to boolean" operator because, as David notes, falsiness is hard wired for false and nil and anything that isn't "falsy" is true. However, there is a logical negation operator so you can do it if you don't mind an explicit cast to boolean:

class P
    attr_accessor :p
    def !@
        p < 0.5
    end
end

And then:

>> p = P.new
>> p.p = 0.75
=> puts 'Pancakes!' if(!!p)
Pancakes!
>> p.p = 0.25
>> puts 'Pancakes!' if(!!p)
# No pancakes for you

All the double bangs might be a bit ugly but, on the upside, it might make people notice that something a little non-standard is going on.

First of all, you do not need a Float subclass. Those interested in subclassing Numeric types can see Katzuda's answer.

The simple way to achieve what you want to achieve is to simply use a method:

class P
  def initialize p; @p = p
    raise "outta range" unless 0 <= @p and @p <= 1 end
  def success?; SUCC <= @p end
  def fail?; not success? end
end

p = P.new 0.3
p.success? # => false
p.fail? # => true

q = P.new 0.7
q.success? # => true
q.fail? # => false

Remember, for these kind of circumstances, Ruby has methods.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top