modularml / mojo

The Mojo Programming Language
https://docs.modular.com/mojo/manual/
Other
22.96k stars 2.59k forks source link

[Feature Request] Simple float conversion #3157

Open RichardCoppin opened 3 months ago

RichardCoppin commented 3 months ago

Review Mojo's priorities

What is your request?

Currently float() behaves weirdly in VSCode IDE. It seems to be identified as a keyword by the LSP (I assume), but then when you try to use it, we get the error use of unknown declaration 'float': image

We also do not have a way to denote a class which can be converted to a floating point value.

Could we not just have something similar to the integer class:


trait Floatable:
    """ `Floatable` trait describes a type that can be converted into an floating point representation.

    An struct will need to implement the `__float__(self) -> FLoat64` method to be considered 'Floatable'
    """

    fn __float__(self) -> Float64:
        """Get the float representation of the struct.

        Returns:
            A Float64 value.
        """
        ...

fn float(value: Int) -> Float64:
    return Float64(value)

fn float(value: Float64) -> Float64:
    return value

fn float[T: Floatable](value: T) -> Float64:
    return value.__float__()

What is your motivation for this change?

Floating point values seem to be a bit of a sharp edge in Mojo at the moment.

The float token is also exhibiting contradictory behavior. VSCode identifies it as a keyword, but the compiler does not have a definition of it.

When constructing your own struct, which should be convertible into float, there is no simple way of casting to floating point:

struct Floatable_Struct():
    var value: Float64

    fn __init__(inout self, value: Float64):
        self.value = value

    fn __float__(self) -> Float64:
        return Float64(self.value)

To extract the floating point value of the struct, one would need to do something like:

fn main()
    var flt_st: Floatable_Struct = Floatable_Struct(0)
    print(Float64(flt_st.__float__())

Trying to do a mere conversion without the clunky dunder call, just results in an error: image

Yet with the above

struct Floatable_Struct(Floatable):
    var value: Float64

    fn __init__(inout self, value: Float64):
        self.value = value

    fn __float__(self) -> Float64:
        return Float64(self.value)

I can just call :

# from builtin import float, Floatable
fn main()
    var flt_st: Floatable_Struct = Floatable_Struct(6.283186)
    flt = float(flt_st)

or if the FloatXX methods were aware of the 'Floatable' trait it could just be:

    var flt64: Float64 = Float64(flt_st)
    var flt32: Float32 = Float32(flt_st)
    var flt16: Float16 = Float16(flt_st)

Any other details?

The dunder method def __float__(self)__ -> float is a defined __dunder__ method in Python.

So this would be inline with expected behavior.

I cannot say which would be the preferred bit-depth for return of the float() method. It could be that this should be compilation target specific.

bgreni commented 2 months ago

Unless there is an intentional reason why this hasn't already been implemented, I can get started on this.