The Crystal Programming Language Forum

[Solved] Returned Float64 is received as union in calling function?

Hi,

I have the following situation, the function find_rate gets a value of JSON::Any and converts it in a Float64 (a typeof of this variable confirms this), being returned, it becomes a union of type (Bool | Float64) and can not be used for calculation.
When tryring to make it a Float64 with appending .to_f64, I get the following error:
Error: undefined method 'to_f64' for Bool (compile-time type is (Bool | Float64))
Is this normal procedure?
How to solve this?

Here is the stripped down code:

require "http/client"
require "json"

# check for valid currency and return rate
def find_rate(items, cur)
   rate : Float64 = 0.0
   if cur == "EUR"
      return 1.0_f64
   end
   if items["rates"][cur]?
      puts "Currency #{cur}: #{items["rates"][cur]}"
   else
      puts "Currency #{cur} not found"
      return false
   end
   rate1 = items["rates"][cur]
   puts "typeof(rate1): #{typeof(rate1)} in function"
   rate = rate1.to_s.to_f64
   puts "typeof(rate): #{typeof(rate)} in function"
   return rate
end

response = HTTP::Client.get "https://api.exchangeratesapi.io/latest"
items = JSON.parse(response.body)

cur_in = "EUR"
cur_out = "USD"
amount_in = 10.0_f64
#rate_out = find_rate(items, cur_out).to_f64
rate_out = find_rate(items, cur_out)
#rate_out = 1.0977_f64
puts "rate: #{rate_out} #{typeof(rate_out)} after function call"
#amount_out = amount_in * rate_out
#print "%.2f #{cur_in} = %.2f #{cur_out}\n" % [amount_in, amount_out]

The reasoning is your method can either returns false or rate, which would make the return type be a union of Bool | Float64.

One solution would be to raise an exception instead of false. Another would be add some conditional logic to make sure the response is the correct type before doing additional logic on it.

something like

if rate_out.is_a? Float64
  # Do your logic there
end
1 Like

@Blacksmoke16 thank you, that makes sense, I hadn’t looked at it that way.