On Tuesday, August 30, 2016 3:57:36 PM CDT Yichao Yu wrote:
> And even then, this completely looses the advantage of using tuple
> (inferrable size and element types) so you shouldn't do this in general
> unless you are going to do a lot of work with the tiny tuple afterwards.

Right. If you want to grow a tuple, you should use "lispy recursion" so the 
compiler can reason about the size, which is part of the type of the tuple. 
(`for` loops are completely off the table for this kind of programming.) 
Here's an example that builds a tuple of N `true`s (i.e., functionally 
equivalent to `ntuple(d->true, N)`):

    buildtrues{N}(::Type{Val{N}}) = _buildtrues((), Val{N}) # initialization

    _buildtrues{N}(out::NTuple{N}, ::Type{Val{N}}) = out   # termination

    @inline _buildtrues{N}(out, ::Type{Val{N}}) =
        _buildtrues((out..., true), Val{N})           # the "inner loop"

Key features include the `@inline` and the fact that `N` is available to the 
type system. For a particular inferrable`N<15`, the compiler will just figure 
out the end result and return that; the "apparent" recursion runs at compile 
time, not runtime.

Note that if your condition isn't evaluatable at compile time, and especially 
if it changes from one "iteration" to the next, then you're frankly much 
better off using Arrays rather than tuples. Don't attempt to fake compile-time 
evaluation using `Val` unless the condition is already embedded in the type 
system (e.g., coming from an `::Array{T,N}`) or it's the same `Val` being used 
bazillions of times. See http://docs.julialang.org/en/latest/manual/
performance-tips/#types-with-values-as-parameters and the section after that.

This is not just a theoretical concern: while tuples have enormous advantages 
in certain settings, trying to fake this with tuples/Val and getting it wrong 
could easily result in a 30-100 fold performance *penalty* compared to using 
Arrays.

Best,
--Tim

Reply via email to