Crystal: Integer division magically converts into Float64

Created on 1 Oct 2019  路  5Comments  路  Source: crystal-lang/crystal

I've been fiddling around with the source, and it's been a blast!

However, since I updated to Crystal 0.32, I've noticed a change that I can't seem to understand how to fix it. I've isolated what version it started happening on. It does not happen on 0.30.1. It happens on versions _0.31.0_, _0.31.1_ and latest master (_0.32.0-dev_)

I've reduced my code the best I can to show an example:

class Client
  property min_dmg = 1
end

player = Client.new

# main_item = json::any Hash from items.json data (exported from mysql, so integer types matter)
# Just an example from main code (ignore)
# player.min_dmg += main_item["base_dmg"].to_i8 / 2

player.min_dmg += (10_i8) / 2

Error:

Error: instance variable '@min_dmg' of Client must be Int32, not Float64

When doing simple division on any Int32 ivar, it wants it to become a Float64. I was thinking about using a union (Int32 | Float64), but good heavens I have tons of ivars that are Int32 . Most of them rely on basic integer division. I don't know if this is intended, or a bug, but I figured I would make this issue to let the core developers know

question

Most helpful comment

Even simpler explanation: / used to mean two different operations, depending on the operands. Now it always means float division, whatever the operands. For floor division there is //.

All 5 comments

See the CHANGELOG:

  • (breaking-change) Make / the arithmetic division for all types. (#8120)

This means that:

  • / now always returns a float (int / int => float);
  • // was introduced as floor division (int // int => int).

I just read through https://github.com/crystal-lang/crystal/issues/2968

@ysbaddaden thanks for the information. It got me thinking though, doesn't this break the static nature of crystal? Why is an Int divided by an Int, converting its value into a Float64? Crystal is not a dynamic language? This means, I need to use unions for all my ivars in a class that has their types set explicitly to a Int32?

In the programming language C, (which I know you know very well), the result from the operation is still an int, but it's only a float if you divide that number by a float. This is the same for GDScript, Ruby, C, and GoLang. If I want my conversion to be a float, I would divide it by a float

I found this as well: https://stackoverflow.com/questions/16221776/why-dividing-two-integers-doesnt-get-a-float which makes sense. Especially since Crystal binds a lot of C functions

What am I missing here?

@girng To understand why / and // are good to have, I have an exericse. Write a function that computes the average of two numbers. The signature is this:

def average(x, y)
  # fill in the body
end

The function should work with every number type: integers, floats and also complex numbers.

Here are some examples:

require "complex"

average(10.5, 2.3) # => 6.4
average(10, 1) # => 5.5
average(Complex.new(1, 2), Complex.new(4, 5)) # => (2.5 + 3.5i)

Do it with a previous Crystal version, for example 0.29.0, where / does a floor division for integers. Then do it for 0.31.0 and see which one is simpler and easier to read/write.

Even simpler explanation: / used to mean two different operations, depending on the operands. Now it always means float division, whatever the operands. For floor division there is //.

Was this page helpful?
0 / 5 - 0 ratings