titzer / virgil

A fast and lightweight native programming language
1.24k stars 48 forks source link

Float to integer cast fails #83

Closed srackham closed 2 years ago

srackham commented 2 years ago

Virgil tests suggest casts are possible:

https://github.com/titzer/virgil/blob/1baf86603c313b978af2048435ab7305915221be/test/feature/float.v3#L96-L102

But this fails to execute:

$ v3c-x86-64-linux --version                     
Aeneas III-7.1526: no input files

$ cat hello.v3
def main() {
  def f: float = 3.142f;
  def i: i32 = i32.!(f);
}

$ v3c-x86-64-linux hello.v3                 

$ ./hello
!TypeCheckException
        in main() [hello.v3 @ 3:21]
titzer commented 2 years ago

That's the intended semantics. A type cast means "is this value representable in the target type?" You can use int.truncf, which is probably the operator you are looking for. (There are also the explicit round operators in float: round, ceil, and floor).

It takes a little getting used to, but just think "casts are dangerous, what I usually want is a conversion or a match".

srackham commented 2 years ago

Thanks for that. CS 101, the difference batween a conversion and a cast. I should have slept on it, it came to me at 3am, mea culpa!

titzer commented 2 years ago

No worries. Virgil's casts w.r.t. float and integer types are actually a bit surprising because value range checking.

I've been meaning to write up the numerical model of Virgil to explain the rationale for the design choices because it's somewhat surprising that casts don't round (i.e. convert) numbers like most other languages. But briefly, casts never destroy information, so (successful) casts from one type F to type T and then back to F always preserve the original value. Similarly, type queries always return true iff the value is representable in the target type, with the exception of null for reference types; casts of null succeed but queries of null return false.

srackham commented 2 years ago

casts never destroy information, so (successful) casts from one type F to type T and then back to F always preserve the original value. Similarly, type queries always return true iff the value is representable in the target type

Great explanation, thanks.

titzer commented 2 years ago

Closing this, as it's WAI.