# \[Pre-RFC\] integer and float literals for custom types

**URL:** <https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998>\
**Category:** compiler\
**Created:** [September 4, 2020, 1:42am UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998 "2020-09-04T01:42:46Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ChaiTRex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chaitrex/32/6699_2.png) [@ChaiTRex](https://internals.rust-lang.org/u/ChaiTRex)\
**Post date:** [September 4, 2020, 1:42am UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/1 "2020-09-04T01:42:46Z")

</div>

I have a proposal for implementing integer and float literals for custom types that I would like feedback for.

* * *

The few proposals I've seen for extending integer and float literals to programmer-defined types have the complication of compile-time-only big integer types and such. This is a much simpler proposal as far as the compiler goes.

The compiler transforms the literal from something like `-28_384BigInteger` into `IntegerLiteral { base: Base::Decimal, negative: true, digits: vec![2, 8, 3, 8, 4] }`, which is then fed into `BigInteger`'s `FromIntegerLiteral` implementation to produce a `Result<BigInteger, IntegerLiteralError>`.

Through this, parsing is taken care of by the compiler, avoiding the need for every implementation to reimplement it from scratch. Then the compiler can give its normal error messages if needed.

Is there some way of ensuring that existing implementations can run at compile time other than waiting for traits to be able to force implementing methods to be `const fn`s?

* * *

```rust
pub enum Base {
    Binary,
    Octal,
    Decimal,
    Hexadecimal,
}

pub struct IntegerLiteral {
    pub base: Base,
    pub negative: bool,
    pub digits: Vec<u8>,
}

pub struct FloatLiteral {
    pub base: Base,
    pub negative: bool,
    pub digits_before_point: Vec<u8>,
    pub digits_after_point: Vec<u8>,
    pub exponent_is_negative: bool,
    pub exponent_digits: Vec<u8>,    
}

pub enum IntegerLiteralError {
    TooHigh,
    TooLow,
    /* ... */
}

pub enum FloatLiteralError {
    TooHigh,
    TooLow,
    /* ... */
}

pub trait FromIntegerLiteral {
    fn from_integer_literal(literal: IntegerLiteral) -> Result<Self, IntegerLiteralError>;
}

pub trait FromFloatLiteral {
    fn from_float_literal(literal: FloatLiteral) -> Result<Self, FloatLiteralError>;
}

```

`FloatLiteral` also has a `base` field in case Rust [follows the example of Java](https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.2) in allowing literals in another base. The `base` field doesn't apply to the exponent digits, which are always in decimal.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [September 4, 2020, 1:57am UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/2 "2020-09-04T01:57:32Z")

</div>

This has been discussed here a number of times (search for "custom literals"). I think it would be nice, but it's also true that you can get 90% of the way there with macros and const fns (the latter getting more and more useful by the day). I think it would be useful if someone motivated put together a summary of past discussion (in particular in light of more recent const fn capabilities) and small survey of existing macro/library solutions.

> Is there some way of ensuring that existing implementations can run at compile time other than waiting for traits to be able to force implementing methods to be `const fn` s?

Probably just "wait for const fns" would be the easier/more principled path.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [September 5, 2020, 10:13am UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/3 "2020-09-05T10:13:48Z")

</div>

I would love that. Here are previous discussions:

> [@Pre-RFC: Custom Literals via Traits](https://internals.rust-lang.org/t/pre-rfc-custom-literals-via-traits/8050):
>
> This is a formal collection of my counter proposal from [https://internals.rust-lang.org/t/pre-rfc-custom-suffixes-for-integer-and-float-literals/](https://internals.rust-lang.org/t/pre-rfc-custom-suffixes-for-integer-and-float-literals/). Summary This RFC proposes syntax sugar for custom literals, implemented as std::ops traits. A custom literal is a suffix added to a numeric, string, or character literal to produce a user-defined type. For example: Complex numbers: 1 + 2i Time literals: 42ms + 120ns Typechecked units: 12m / 55s Compile-time checks of simple embedded languges: "…

> [@Pre-RFC: Custom suffixes for integer and float literals](https://internals.rust-lang.org/t/pre-rfc-custom-suffixes-for-integer-and-float-literals/8029):
>
> This proposal originates from “[time units](https://github.com/rust-lang/rust/pull/52556)” PR. Motivation To make creation of values with associated unit of measure more natural and ergonomic. Currently we have to write: let dt1: Duration = Duration::new(1, 200\*1\_000\_000); let dt2: Duration = Duration::from\_micros(10); let dt3: Duration = Duration::from\_micros(10) + Duration::from\_nanos(200); // Units are from simple\_units crate let distance1: Meter = Meter(1.0); let distance2: Meter = Meter(5e-9); let accel1: MeterPerSecond2 = MeterPerSec…

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [September 5, 2020, 12:59pm UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/4 "2020-09-05T12:59:42Z")

</div>

IMO the most comprehensive crate on [crates.io](http://crates.io) for units of measure seems to be [UoM](https://crates.io/crates/uom). Any proposal for custom literals should take into account the many types of units covered by that crate. Also, if it provides a syntax for 2-component complex numbers, that syntax should be extensible to 4-component [quaternions](https://en.wikipedia.org/wiki/Quaternion) (more as a test for the completeness of the approach than for practical reasons).

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [September 8, 2020, 3:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/5 "2020-09-08T15:11:55Z")

</div>

I recall someone bringing up allowing the production `$path ! $literal` at some point as sugar for `$path!($literal)`. I think the context was in string interpolation, where people wanted to be able to write `f!"foo is {foo}"` or similar. I think that this extends in a fairly natural way to custom literals in general: `big_int!42`, which means the problem of how to represent a "general" literal can be punted to a procedural macro, rather than stapled to `std`.

Unfortunately it's not compatible with the existing `42u32` syntax, but that syntax is already a lexer-level concern iirc. It's also nice because you can write `foo::bar!42` if you so chose. Path resolution seems to consistently be a problem with these proposals. It also has the benefit that you can write `foo::bar!(42)` if you really want to

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [September 9, 2020, 12:14pm UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/6 "2020-09-09T12:14:42Z")

</div>

Regarding the syntax: something I haven't seen in any of the linked discussions on the topic (but might have missed) is to use type ascription for this purpose - assuming it can be used on sub-expressions - rather than pre-/suffixes.

AFAICT this would not require any additional syntax other than type ascription, and would still look rather nice to me:

```rust
const length_explicit = 17 : units::si::Meter; // can use fully specified paths

use units::si::{m, s}; // assuming 'm', 's' are public aliases for Meter, Second
const distance = 17 : m;
const speed = distance / 1.0 : s;

const found = "foo(bar)?":regex.matches(data);

const c = (1, 4) : Complex;  
const q = (1.0, 2.5, 0.0, -3.7) : Quaternion

```

Ofc this would need some support/rules how ascriptions apply to constants of other (underlying) types, and does not address the issues regarding unit handling, and underlying storage types.

For the latter, one nice option may be module level generics:

```rust
use units::si::<u64>::{m, s}; 
const length = 128 : m; // base storage type is u64

```

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [September 9, 2020, 3:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/7 "2020-09-09T15:29:46Z")

</div>

Do keep in mind that the way I would accomplish this today with with an `impl From<i64> for BigInteger` that then let's you write `28_384.into()`, but that of course doesn't work for anything outside the range. At that point you could use a str, but it isn't as nice.

Be aware that the lever might have unexpected limitations that would make your extension not always behave the way you expect.

---

<div class="post-metadata">

**Author:** ![Aloso](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aloso/32/5039_2.png) [@Aloso](https://internals.rust-lang.org/u/Aloso)\
**Post date:** [September 10, 2020, 2:23am UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/8 "2020-09-10T02:23:51Z")

</div>

I verified that [macros can parse literals of any length](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3edd75ece6bf16642676b49492d0e44a).

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [December 9, 2020, 2:23am UTC](https://internals.rust-lang.org/t/pre-rfc-integer-and-float-literals-for-custom-types/12998/9 "2020-12-09T02:23:51Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
