1. 17

  2. 2

    This is just an assumption, but isn’t it that the out param is used for slices because they are not Sized?

    The compiler can treat -> i32 and out: &mut i32 as the same thing if it already has a reference in which to store the result, as shown in the assembly, and can treat -> i32 as a special case where it can also create a new owned variable. With [u8] the memory needs to already be allocated as it is not Sized.

    1. 5

      That’s a correlation, but not a cause. If it were as cheap to construct a 4KB buffer as it is to construct a 4 byte integer, you’d probably see a whole lot fewer out params in use. But buffers are expensive to allocate, which results in:

      • users having opinions about how big their buffers need to be
      • type systems being able to abstract over different buffer sizes
      • recycled buffers passed in as out params
    2. 1

      Sounds like the same reason that out parameters and mutation are idiomatic in Lisp, i.e. for “accumulators”.

      I make use of that pattern all over Oil, e.g. with recursive evaluation functions all appending to the same Python list.

      I started with return values, but the accumulator is a lot more elegant IMO (and efficient due to not creating lots of lists)

      1. 3

        I think this is touched on in the article but not quite spelled out, but my take on the reason to use an out parameter has a lot to do with allocation. If your function would otherwise need to allocate heap memory in order to produce a result, an out parameter can make it so the responsibility of allocation (and memory ownership) is delegated to the caller. That means the caller is allowed to reuse the same memory or use any other custom allocation strategy.