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.63k stars 2.15k forks source link

Compiler allows assigning negative values to `u32` #10737

Closed flysand7 closed 3 years ago

flysand7 commented 3 years ago

V version: V 0.2.2 44e78a6 OS: windows, Microsoft Windows 10 Home Single Language v19042 64-bit

What did you do?

mut x := u32(0)
x = -1
println(x)

What did you expect to see?

Compiler error, I tried to assign a negative value to a type that doesn't represent a superset of negative values.

What did you see instead?

A correctly compiling code:

$ v run main.v
4294967295
levelfourtwenty commented 3 years ago

I have noticed the same issue with the u16 and u64 types.

The code for the u16 type:

mut x := u16(0)
x = -1
println(x)

What I got:

$ v run . 
65535

Code for the u64 type:

mut x := u64(0)
x = -1
println(x)

What I got:

18446744073709551615

In both cases I had expected to get a compiler error yet the code compiled.

dumblob commented 3 years ago

Well, this might be a bit bigger topic than it seems. @medvednikov expressed his wish to have number literals untyped and coerce them automatically to what's expected at that very place. This saves boilerplate code.

The question is, whether coercing in this case is wanted or not.

flysand7 commented 3 years ago

@dumblob untyped literals have nothing to do with not being a statically-typed language and print errors like this to the screen. Having a negative value assigned to u32 is not an expected thing in general.

Odin is Go-inspired language with untyped types built into the compiler, that allows treating numeric values in the way that makes them "just work".

$ cat main.odin
package main;
import "core:fmt";

main :: proc() {
  a : u32 = -1;
}
$ odin run .
main.odin(5:13) Cannot convert '-1' to 'u32' from 'untyped integer'

Also please do not close issues prematurely. I know that V devs are trying to close as many issues as possible, but doing it that way is cheating and will not make V a better language.

dumblob commented 3 years ago

I'd guess V currently treats untyped literals more or less the same as casting - if casting is allowed (e.g. promotions work) in the given case, then also assignment works. But I'm not sure this is the reason.

If it's really like that, then it's IMHO problematic if not outright wrong. Because casting is "enforcement of the programmer's will" but autoconversion from an untyped literal must not enforce anything and instead fail in compile time.

FYI Odin disallows casting/promotion from -1 to u32 (a : u32 = cast(u32)-1) - I've just tried that. V from the current master though allows this cast (and produces the same number as you demonstrated above).

Also please do not close issues prematurely. I know that V devs are trying to close as many issues as possible, but doing it that way is cheating and will not make V a better language.

Let me apologize for the whole V community. I'm certain this is not a common approach (see e.g. issues I've authored - some are 1.5 years old, still unsolved, some of them very unpopular, but nobody closed them). Please ping @medvednikov if you think anything was closed prematurely.

JalonSolov commented 3 years ago

Direct assignment as an implicit cast is an bad idea. However, an explicit cast should still be allowed. One of the oldest tricks in programming is to set a unsigned variable to -1 to get the maximum value.

So...

BAD (implicit casting)

mut u := u32(0)
u = -1

GOOD (explicit casting)

u := u32(-1)
flysand7 commented 3 years ago

One of the oldest tricks in programming to get the maximum value--bitwise not of unsigned sized zero ~u32(0). I'm not going to support either of the positions about whether u32(-1) should be allowed, but the language is fine if it doesn't support that.