# Show(io, i::Int) allocates

**URL:** https://discourse.julialang.org/t/show-io-i-int-allocates/59259
**Category:** Internals & Design
**Tags:** performance
**Created:** [April 14, 2021, 9:38am UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259 "2021-04-14T09:38:52Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![green.nsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/green.nsk/32/24014_2.png) [@green.nsk](https://discourse.julialang.org/u/green.nsk)
#### Post date: [April 14, 2021, 9:38am UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/1 "2021-04-14T09:38:52Z")

</div>

This was unexpected, but `show(io::IO, i::Int)` does allocate.  
It’s clearly happening because printing an integer first converts it to a string and then writes a string to `io`: [julia/show.jl at v1.6.0 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/v1.6.0/base/show.jl#L969)

```julia
@btime print(io, 1)
# > 100.949 ns (2 allocations: 96 bytes)

```

Is there any rationale for doing it this way and not another way? Print number to IOBuffer and then convert that to a string seems a more straightforward way to implement it.

Performance of IO-based version should theoretically be superior, but it depends on what and how you measure, as usual 🙂

My main question I guess is whether anyone ran into similar issues, and if you think there’s a room for improving standard integer serialization.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [April 14, 2021, 9:44am UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/2 "2021-04-14T09:44:34Z")

</div>

> [@green.nsk](#):
>
> Is there any rationale for doing it this way and not another way?

Maybe you can give a short example of the other way. Remember that `"123"` and writing `1`, `2` and `3` has totally different representation:

```julia
julia> codeunits("123")
3-element Base.CodeUnits{UInt8, String}:
 0x31
 0x32
 0x33

```

---

<div class="post-metadata">

### Author: ![green.nsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/green.nsk/32/24014_2.png) [@green.nsk](https://discourse.julialang.org/u/green.nsk)
#### Post date: [April 14, 2021, 10:01am UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/3 "2021-04-14T10:01:38Z")

</div>

I had something like this in mind (based on current `dec()` implementation ([julia/intfuncs.jl at v1.6.0 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/v1.6.0/base/intfuncs.jl#L678))

```julia
function dec(x::Unsigned, pad::Int, neg::Bool)
    n = neg + ndigits(x, pad=pad)
    io = IOBuffer(fill(UInt8(0), n); write = true, maxsize = n)
    dec_io(io, x, pad, neg)
    String(take!(io))
end

dec_io(io, x, pad, neg) = print(io, '1', '2', '3') # for x = 123

```

then you could reuse `dec_io()` for implementing `show(io, i::Int)` as well as more complex stuff (for example date serialization which is the actual problem I’m looking at)

P.S. This specific implementation will not be faster than current implementation at all, more for illustration purposes

---

<div class="post-metadata">

### Author: ![green.nsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/green.nsk/32/24014_2.png) [@green.nsk](https://discourse.julialang.org/u/green.nsk)
#### Post date: [April 14, 2021, 10:10am UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/4 "2021-04-14T10:10:50Z")

</div>

I am not entirely sure why would `print(io, "123")` ever produce anything different than `print(io, '1', '2', '3')`. Maybe I’m just clueless.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 14, 2021, 12:08pm UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/5 "2021-04-14T12:08:21Z")

</div>

> [@green.nsk](#):
>
> ```julia
> dec_io(io, x, pad, neg) = print(io, '1', '2', '3') # for x = 123
> 
> ```
> 
> then you could reuse `dec_io()` for implementing `show(io, i::Int)` as well as more complex stuff (for example date serialization which is the actual problem I’m looking at)

If you look at the current implementation of `dec`, it computes the digits from right to left, so you’d need a completely different algorithm to output the digits left-to-right into an `io` stream.

(One option would be to pre-allocate a per-thread buffer, which we used to do for printf and grisu but no longer do for some reason.)

---

<div class="post-metadata">

### Author: ![green.nsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/green.nsk/32/24014_2.png) [@green.nsk](https://discourse.julialang.org/u/green.nsk)
#### Post date: [April 14, 2021, 12:42pm UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/7 "2021-04-14T12:42:25Z")

</div>

Sure, the algorithm will be different. You don’t need to allocate any buffers, just compute digits in reverse order.

My point is that converting int to a string is inefficient because it requires memory allocation. You could print the integer without allocating any memory.

In my perftests it was pretty hard to beat current implementation of `show(io, int)` when perftested in isolation, but when part of more complex `show(io, date)`, allocation-free version does much better.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 14, 2021, 12:58pm UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/8 "2021-04-14T12:58:24Z")

</div>

> [@green.nsk](#):
>
> Sure, the algorithm will be different. You don’t need to allocate any buffers, just compute digits in reverse order.

The nice thing about computing digits from right to left is that it is pretty easy to come up with an algorithm that works for any precision simply by a sequence of `divrem(n, 10)` operations (actually Julia uses `divrem(n, 100)` to get 2 digits at a time), whereas from right-to-left it seems trickier to do efficiently.

Note also that we similarly need a buffer for float-to-string conversion, since the [Ryu algorithm](https://dl.acm.org/doi/10.1145/3192366.3192369) that we employ does not compute digits from left to right.

It seems like the simplest solution would be to pre-allocate a buffer array (per thread). Then the `show` method could output bytes directly from the buffer rather than constructing a `String`.

---

<div class="post-metadata">

### Author: ![green.nsk](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/green.nsk/32/24014_2.png) [@green.nsk](https://discourse.julialang.org/u/green.nsk)
#### Post date: [April 14, 2021, 3:50pm UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/9 "2021-04-14T15:50:19Z")

</div>

Sure, that’s more versatile and I am guessing smaller change too I’m also happy.

Should I create an issue in Julia GitHub for this?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 14, 2021, 4:19pm UTC](https://discourse.julialang.org/t/show-io-i-int-allocates/59259/10 "2021-04-14T16:19:24Z")

</div>

> [@green.nsk](#):
>
> Should I create an issue in Julia GitHub for this?

Sure, but maybe first try to put together a benchmark demonstrating the benefit of a pre-allocated buffer (you could just hack an alternative `show` by copy-and-pasting the Base code, and not worrying about thread safety).
