# Parametric bits

**URL:** <https://discourse.julialang.org/t/parametric-bits/26117>\
**Category:** Internals & Design\
**Created:** [July 7, 2019, 2:47pm UTC](https://discourse.julialang.org/t/parametric-bits/26117 "2019-07-07T14:47:41Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [July 7, 2019, 2:47pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/1 "2019-07-07T14:47:41Z")

</div>

Float{64} would make a lot more sense than Float64, no? Julia exports at least 13 float/integer types, and with parametric types it could cut down to three (signed, unsigned, and float). Maybe something to consider for 2.0?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 7, 2019, 3:14pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/2 "2019-07-07T15:14:40Z")

</div>

What do you need this for? For eg (hypothetical code)

```julia
function foo(x::Float{T}) where {T}
    print("I have $T bits!")
end

```

you can define a trait, or use `size(Float64) * 8`.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [July 7, 2019, 4:19pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/3 "2019-07-07T16:19:13Z")

</div>

This would imply that `Float{13}` is just as valid and usable a type as `Float{64}`, which it’s not.

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [July 8, 2019, 3:04am UTC](https://discourse.julialang.org/t/parametric-bits/26117/4 "2019-07-08T03:04:35Z")

</div>

Hmm maybe Float{6} then, where 64 = 2^6?

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 8, 2019, 3:36am UTC](https://discourse.julialang.org/t/parametric-bits/26117/5 "2019-07-08T03:36:24Z")

</div>

Why does `Float{64}` make more sense than `Float64`? Having a number in the name is not a reason to replace that number by a type parameter.

All the exported types requires completely different handling from each other (they are all different hardware types). Parametric type is for dealing with types that are the same with each other apart from the type parameters and this is not the case between the number types you suggests. Making them parametric type does not help writing any code and simply confuses the user about their properties/relations.

Also, reducing the export is not a goal on it’s own, or basically all type in Base would have been spelled as `IntegerType{:Int64}` etc.

---

<div class="post-metadata">

**Author:** ![MikeInnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikeinnes/32/3656_2.png) [@MikeInnes](https://discourse.julialang.org/u/MikeInnes)\
**Post date:** [July 8, 2019, 11:39am UTC](https://discourse.julialang.org/t/parametric-bits/26117/6 "2019-07-08T11:39:53Z")

</div>

Doing this would make total sense if there was a general mapping from `N` bits to a floating point layout, and there’d be no issue mapping `Float{64}` to hardware operations where possible. Unfortunately I don’t think any such mapping exists that would include `Float64` and `Float32` as special cases, and it may not be possible to do this in a sensible way, in which case it’s better to view them as completely distinct types.

Julia can’t do anything here, but that’s largely just historical contingency rather than it being an inherently unreasonable idea.

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [July 8, 2019, 12:38pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/7 "2019-07-08T12:38:25Z")

</div>

> [@yuyichao](#):
>
> reducing the export is not a goal on it’s own

Having a well-factored API is an explicitly stated goal, and the official reason why we can’t have underscores

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 8, 2019, 1:17pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/8 "2019-07-08T13:17:28Z")

</div>

> [@bramtayl](#):
>
> Having a well-factored API

That is not reducing exports at all. Reducing exports when not needed is the mean to achieve a well-factored API, together with having easy to remember, widely accepted and concise names etc. It is definitely not the goal itself and doing what you are suggesting does not make a better API. As I said, you can arbitrarily reduce the export size using type parameters. In fact, you can remove almost all function export from Base and replace them with

```julia
julia> struct BaseFunc{S}
       end

julia> (::Type{BaseFunc{S}})(args...; kwargs...) where S = getfield(Base, S)(args...; kwargs...)

```

and that probably cut down the export from base by an order of magnitude. Such changes are simply changing the spelling, just like `Float64` and `Float{64}`.

Basically, putting the information into the type parameter does not on itself bring any benefit and cutting down the export from 13 to 3 is not an argument for anything. You must instead look at the properties of the types you are trying to consolidate and see what a different it’ll make for the user/implimentation. AFAICT, most (all?) code either care about the property of the abstract type (`Unsigned`, `Signed`, `AbstractFloat`) which includes other types as well, or they care about the exact concrete type since, as I said, these are different hardware types. Adding the type parameter doesn’t help for either of these and merely hide the fundamental difference between the types and mislead people to over-generalize.

Also, underscore is something completely unrelated to this.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [July 8, 2019, 3:32pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/9 "2019-07-08T15:32:18Z")

</div>

By comparison, it would make some sense to have parameterized `UInt` and `Int` types since there is a completely standard representation and behavior for unsigned and signed two’s complement integers. However, while that’s the theory, in practice, using integer sizes that are not what the hardware supports directly is not recommended. It will be slow and will most likely hit LLVM bugs. Exporting types that suggest that using integer types with arbitrary bit sizes seems like doing our users a disservice.

Note that in a somewhat related area we have `ComplexF32` and `ComplexF64` as convenience abbreviations for `Complex{Float32}` and `Complex{Float64}`, even though the `Complex` type is truly generic. That’s because these are the most common and hardware supported complex types. So even if `UInt64` were defined as `UInt{64}`, we’d probably want a convenience alias for it anyway, since it’s by far the most common integer type that you want.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [July 8, 2019, 3:44pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/10 "2019-07-08T15:44:24Z")

</div>

I would have liked for the precision of `BigFloat` to be a type parameter, rather than a mutable global state.

But I’m guessing there’s something in the internals of GMP that would make this hard to implement?

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [July 8, 2019, 4:24pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/11 "2019-07-08T16:24:00Z")

</div>

Yes, implementation aside bigfloat of different sizes are similar enough for this. Unless the runtime or the user can take advantage of it though, it should just be data (field or global) other than in the type.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [July 8, 2019, 6:59pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/12 "2019-07-08T18:59:59Z")

</div>

But the choice between “size as type parameter” and “size as dynamic global setting” is a false dichotomy. There is also the option of passing it as an argument the the `BigFloat` constructor and having operations on big floats do promotion based on the precisions of their arguments (i.e. the result has the max precision of its arguments). We can already construct `BigFloat` values of a given precision with the `precision` keyword argument, the only problem that remains at this point is that the precision of operations on BigFloats is taken from the global setting, not from the precisions of the arguments:

```julia
julia> big_pi = BigFloat(pi, precision=1024)
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724586997

julia> big_e = BigFloat(ℯ, precision=2048)
2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901157383418793070215408914993488416750924476146066808226480016847741185374234544243710753907774499206955170276183860626133138458300075204493382656029760673711320070932870912744374704723069697720931014169283681902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312773617821542499922957635148220826989519366803318252886939849646510582093923982948879332036250944311730123819706841609

julia> big_pi*big_e
8.539734222673567065463550869546574495034888535765114961879601130179228611157304

julia> precision(ans)
256

```

Some previous discussion here:  
[https://github.com/JuliaLang/julia/issues/10040](https://github.com/JuliaLang/julia/issues/10040)

---

<div class="post-metadata">

**Author:** ![simonbyrne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonbyrne/32/19_2.png) [@simonbyrne](https://discourse.julialang.org/u/simonbyrne)\
**Post date:** [July 8, 2019, 7:57pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/13 "2019-07-08T19:57:11Z")

</div>

The main hassle with having precision as a type parameter is that it will then invoke compilation for every new precision value. This can cause problems for cases where you do actually want precision to be set dynamically, e.g. I’ve written code for computing continued fractions by iteratively recomputing expressions in higher precision.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [July 8, 2019, 8:13pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/14 "2019-07-08T20:13:40Z")

</div>

It’s also unnecessary to solve the main problem people have with the current BigFloat behavior—all we need to do is propagate precision from arguments to results during operations. The main hope from putting the precision in the type would be that the compiler could store BigFloats in registers for small enough precisions, but I’m not sure how realistic that actually is and how much better that would be than just being in L1 cache.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [July 8, 2019, 8:47pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/15 "2019-07-08T20:47:37Z")

</div>

> [@StefanKarpinski](#):
>
> Exporting types that suggest that using integer types with arbitrary bit sizes seems like doing our users a disservice.

Imo exposing `primitive type` to users is already too much: `primitive type foo 24 end` will produce bugs everywhere, due to different parts of the compiler disagreeing on whether this is 3 or 4 byte (3 byte payload + 1 byte padding for alignment).

I think we could do without syntax / keywords for that and expose it in expressions only, just like `:new` (constructing instances of objects without calling inner constructors; this is impossible by writing julia source, but very possible by emitting julia expressions, e.g. via macros or generated functions. It is inconvenient for good reason: That way you can generate an object `struct bar x end` where `x` is nullpointer, and segfault on `bad_bar.x` instead of getting `UndefRefError`).

---

<div class="post-metadata">

**Author:** ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)\
**Post date:** [July 9, 2019, 6:52pm UTC](https://discourse.julialang.org/t/parametric-bits/26117/16 "2019-07-09T18:52:56Z")

</div>

You can simulate this with

```julia
import Base: +

struct FloatBits{Bits, FloatType}
    raw::FloatType
end

struct IntegerBits{Bits, IntegerType}
    raw::IntegerType
end

struct UnsignedIntegerBits{Bits, UnsignedIntegerType}
    raw::UnsignedIntegerType
end

FloatBits{Bits}(raw) where {Bits} = 
    error("$Bits bit floats unsupported")
FloatBits{16}(raw) = FloatBits{16, Float16}(Float16(raw))
FloatBits{32}(raw) = FloatBits{32, Float32}(Float32(raw))
FloatBits{64}(raw) = FloatBits{64, Float64}(Float64(raw))

IntegerBits{Bits}(raw) where {Bits} = 
    error("$Bits bit integers unsupported")
IntegerBits{8}(raw) = IntegerBits{8, Int8}(Int8(raw))
IntegerBits{16}(raw) = IntegerBits{16, Int16}(Int16(raw))
IntegerBits{32}(raw) = IntegerBits{32, Int32}(Int32(raw))
IntegerBits{64}(raw) = IntegerBits{64, Int64}(Int64(raw))
IntegerBits{128}(raw) = IntegerBits{128, Int128}(Int128(raw))

UnsignedIntegerBits{Bits}(raw) where {Bits} = 
    error("$Bits bit unsigned integers unsupported")
UnsignedIntegerBits{8}(raw) = UnsignedIntegerBits{8, UInt8}(UInt8(raw))
UnsignedIntegerBits{16}(raw) = UnsignedIntegerBits{16, UInt16}(UInt16(raw))
UnsignedIntegerBits{32}(raw) = UnsignedIntegerBits{32, UInt32}(UInt32(raw))
UnsignedIntegerBits{64}(raw) = UnsignedIntegerBits{64, UInt64}(UInt64(raw))
UnsignedIntegerBits{128}(raw) = UnsignedIntegerBits{128, UInt128}(UInt128(raw))

+(x::IntegerBits{Bits}, y::IntegerBits{Bits}) where Bits = 
    IntegerBits{Bits}(x.raw + y.raw)

IntegerBits{8}(127) + IntegerBits{8}(127)

```
