title: Fortran-like arrays such as FArray(Float64, -1:1,-7:7,-128:512) in Julia
body: <p>Generally having 1-based array for Julia is a good decision, but sometimes it is desirable to have Fortran-like array with indices that span some subranges of ℤ:</p>
  
  <pre><code>julia&gt; x = FArray(Float64, -1:1,-7:7,-128:512)
  </code></pre>
  
  <p>where it would be useful:</p>
  
  <p>in the codes accompanying the book Numerical Solution of Hyperbolic Partial Differential Equations by prof. John A. Trangenstein these negative indices are used intensively for ghost cells for boundary conditions.
  The same is true for Clawpack (stands for “Conservation Laws Package”) by prof. Randall J. LeVeque <a href="http://depts.washington.edu/clawpack/" rel="noreferrer">http://depts.washington.edu/clawpack/</a> and there are many other codes where such indices would be natural.
  So such auxiliary class would be useful for speedy translation of such codes.</p>
  
  <p>I just started to implement such an auxiliary type but as I'm quite new to Julia your help would be greatly appreciated.</p>
  
  <p>I started with:</p>
  
  <pre><code>type FArray
      ranges
      array::Array
      function FArray(T, r::Range1{Int}...)
          dims = map((x) -&gt; length(x), r)
          array = Array(T, dims)
          new(r, array)
      end
  end
  </code></pre>
  
  <p>Output:</p>
  
  <pre><code>julia&gt; include ("FortranArray.jl")
  julia&gt; x = FArray(Float64, -1:1,-7:7,-128:512)
  FArray((-1:1,-7:7,-128:512),3x15x641 Array{Float64,3}:
  [:, :, 1] =
  6.90321e-310  2.6821e-316   1.96042e-316  0.0  0.0  0.0  9.84474e-317  …  1.83233e-316  2.63285e-316  0.0           9.61618e-317  0.0        
  6.90321e-310  6.32404e-322  2.63285e-316  0.0  0.0  0.0  2.63292e-316     2.67975e-316
  ...
  [:, :, 2] =
  ...
  </code></pre>
  
  <p>As I'm completely new to Julia any recommendations especially that lead to more efficient would be greatly appreciated.</p>
  
  <p>[Edit]</p>
  
  <p>The topic has been discussed here:</p>
  
  <p><a href="https://groups.google.com/forum/#!topic/julia-dev/NOF6MA6tb9Y" rel="noreferrer">https://groups.google.com/forum/#!topic/julia-dev/NOF6MA6tb9Y</a></p>
  
  <p>During the discussion two ways to have Julia arrays with arbitrary base were elaborated:
  SubArray-based, sample usage is with a helper function:</p>
  
  <pre><code>function farray(T, r::Range1{Int64}...)
      dims = map((x) -&gt; length(x), r)
      array = Array(T, dims)
      sub_indices = map((x) -&gt; -minimum(x) + 2 : maximum(x), r)
      sub(array, sub_indices)
  end
  
  julia&gt; y[-1,-7,-128] = 777
  777
  
  julia&gt; y[-1,-7,-128] + 33
  810.0
  
  julia&gt; y[-2,-7,-128]
  ERROR: BoundsError()
   in getindex at subarray.jl:200
  
  julia&gt; y[2,-7,-128]
  2.3977385e-316
  </code></pre>
  
  <p>Please note, that bounds are not checked fully more details are here:
  <a href="https://github.com/JuliaLang/julia/issues/4044" rel="noreferrer">https://github.com/JuliaLang/julia/issues/4044</a></p>
  
  <p>At the moment SubArray has performance issues but eventually its performance might be improved, see also:</p>
  
  <p><a href="https://github.com/JuliaLang/julia/issues/5117" rel="noreferrer">https://github.com/JuliaLang/julia/issues/5117</a></p>
  
  <p><a href="https://github.com/JuliaLang/julia/issues/3496" rel="noreferrer">https://github.com/JuliaLang/julia/issues/3496</a></p>
  
  <p>Another approach that has better performance at the moment, besides checks both bounds:</p>
  
  <pre><code>type FArray{T&lt;:Number, N, A&lt;:AbstractArray} &lt;: AbstractArray
  
      ranges
      offsets::NTuple{N,Int}
      array::A
  
      function FArray(r::Range1{Int}...)
          dims = map((x) -&gt; length(x), r)
          array = Array(T, dims)
          offs = map((x) -&gt; 1 - minimum(x), r)
          new(r, offs, array)
      end
  end
  
  FArray(T, r::Range1{Int}...) = FArray{T, length(r,), Array{T, length(r,)}}(r...)
  
  getindex{T&lt;:Number}(FA::FArray{T}, i1::Int) = FA.array[i1+FA.offsets[1]]
  getindex{T&lt;:Number}(FA::FArray{T}, i1::Int, i2::Int) = FA.array[i1+FA.offsets[1], i2+FA.offsets[2]]
  getindex{T&lt;:Number}(FA::FArray{T}, i1::Int, i2::Int, i3::Int) = FA.array[i1+FA.offsets[1], i2+FA.offsets[2], i3+FA.offsets[3]]
  
  setindex!{T}(FA::FArray{T}, x, i1::Int) = arrayset(FA.array, convert(T,x), i1+FA.offsets[1])
  setindex!{T}(FA::FArray{T}, x, i1::Int, i2::Int) = arrayset(FA.array, convert(T,x), i1+FA.offsets[1], i2+FA.offsets[2])
  setindex!{T}(FA::FArray{T}, x, i1::Int, i2::Int, i3::Int) = arrayset(FA.array, convert(T,x), i1+FA.offsets[1], i2+FA.offsets[2], i3+FA.offsets[3])
  </code></pre>
  
  <p>getindex and setindex! methods for FArray were inspired by base/array.jl code.</p>
  
  <p>Use cases:</p>
  
  <pre><code>julia&gt; y = FArray(Float64, -1:1,-7:7,-128:512);
  
  julia&gt; y[-1,-7,-128] = 777
  777
  
  julia&gt; y[-1,-7,-128] + 33
  810.0
  
  julia&gt; y[-1,2,3]
  0.0
  
  julia&gt; y[-2,-7,-128]
  ERROR: BoundsError()
   in getindex at FortranArray.jl:27
  
  julia&gt; y[2,-7,-128]
  ERROR: BoundsError()
   in getindex at FortranArray.jl:27
  </code></pre>