vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.79k stars 2.16k forks source link

int values incorrectly promoted to f32 #7692

Open mareek opened 3 years ago

mareek commented 3 years ago

V version: 0.2 OS: Windows 10 x64

What did you do? I assigned an int to a mutable f32 variable

mut my_float_32 := f32(3.2)
my_int := int(2147483583)
my_float_32 =  my_int // should fail to compile

What did you expect to see? I expected a compilation error as implied by the documentation

An int value for example can be automatically promoted to f64 or i64 but not to f32 or u32. (f32 would mean precision loss for large values and u32 would mean loss of the sign for negative values).

What did you see instead? The code compiled and ran without error but precision was lost

medvednikov commented 3 years ago

Good find!

mareek commented 3 years ago

I'm not sure if it's a compiler bug or problem with the documentation PR #5174 explicitly allowed this kind of promotion but forgot to update the part of the documention I mentionned earlier.

medvednikov commented 3 years ago

It's a compiler bug. @dumblob would you agree?

dumblob commented 3 years ago

Yes, it's a compiler bug. The behavior described in doc is a sane behavior.

Delta456 commented 3 years ago

Can we just revert that commit?

dumblob commented 3 years ago

Hm, looking at this after some time I'm sure we should not only disable promotion int->f32, but also int64->f64 (i.e. just revert PR https://github.com/vlang/v/pull/5174 ).

Having it relaxed as it's now is unsafe (i.e. violates the V's promise of safety) and doesn't compose (i.e. makes the judgement about promotions and casting overly complex) with future number types (bigint, bigdecimal, decimal, f128, ...).

medvednikov commented 3 years ago

I agree, these promotions should not be allowed, except for int literals

fn foo(x f32) {}
foo(1)
dumblob commented 3 years ago

I agree, these promotions should not be allowed, except for int literals

fn foo(x f32) {}
foo(1)

@medvednikov what's the difference between these two then?

Hey, careful, the API says it's f32 and you're passing a variable with value which can't be guaranteed to be passed losslessly.

Hey, careful, the API says it's f32 and you're passing a literal value of a type which can't be guaranteed to be passed losslessly.

I'd say there is no difference, but allowing any literal being passed doesn't support this understanding.

What we can do though is to analyze in compile time whether the particular literal can be losslessly casted to the receiver type. That should cover most use cases like the one shown without sacrificing the general default rule of explicit casting.

medvednikov commented 3 years ago

In V, like in Go, number literals are untyped, and are fit into the right type (as long as the value of the literal is not out of bounds). This makes things a lot less verbose.

JalonSolov commented 3 years ago

So if the literal is out of bounds for the type, V should give a warning. Otherwise, silently convert the value to the var type.

dumblob commented 3 years ago

@medvednikov @JalonSolov perfect, it's another way of saying the same as I wrote I think, so we're on the same boat :wink:.