• There are people who say Julia is idiot-proof.

  • As a veritable idiot, I had to put the statement to test.


  • Take a very innocous array of integers. You might use one of them to store a simple table.
my_table = rand(1:100, 5, 5)

>>>
5×5 Array{Int64,2}:
 76  41  23   5  74
 87  61  36   9  95
  6  61  90  14  74
 52  44   1  94  21
 24  83  53  19  41
  • Now let me write a simple function that sets the ith row to 1. Easy Peasy.
function set_row(table, row)
    table[row, :] .= 1
end
  • Let’s benchmark this function to see if I am leaking any memory.
@btime set_row(my_table, 1)
>>> 21.821 ns (1 allocation: 48 bytes)
  • Wait. Why is it assigning 48 bytes to this function? That’s weird.
  • By the way, what happens if you decide to set all rows to 1?
function set_all_rows(table)
    for row=1:5                     # all rows
        table[row, :] .= 1
    end
end

@btime set_all_rows(my_table)
>>> 19.852 ns (0 allocations: 0 bytes)
  • Okay I think I understand what is going on here. If I don’t have a function parameter like row, I don’t allocate memory.
  • Is that really what’s going on here? Let me try to write a function that only sets the second row to be 1.
function set_second_row(table)
    table[2, :] .= 1  # only the second row
end

@btime set_second_row(my_table)
>>> 21.525 ns (1 allocation: 48 bytes)
  • WTF? 48 bytes allocated. If I try to set the whole array to one, I don’t allocate any memory. But if I try to set one row to one, then I somehow need to make new space for this one row.

Swapping Rows

  • Let’s try swapping rows.
function swap_rows(table, i, j)
    table[i,:], table[j,:] = table[j,:], table[i,:]
end

my_table = rand(1:100, 5, 5)

# 5×5 Array{Int64,2}:
#  58  86  80  80  55
#  52   7   1  67  54
#  67  24  62  42  20
#  62  69  22  75  83
#  25  76  16  99  31

swap_rows(my_table, 2, 4) # SWAP row 2 and 4

my_table
# 5×5 Array{Int64,2}:
#  58  86  80  80  55
#  62  69  22  75  83
#  67  24  62  42  20
#  52   7   1  67  54
#  25  76  16  99  31
  • Okay it looks like the rows have been swapped.
  • What about memory allocation though?
@btime swap_rows(my_table, 2, 4)
 118.901 ns (3 allocations: 288 bytes)
  • Okay this is crazy.
  • Maybe I need to write the code in the dumbest way possible, swapping elements one at a time.
function swap_rows_dumb(table, i, j)
    for k=1:5
        temp = table[i, k]
        table[i,k] = table[j,k]
        table[j,k] = temp
    end
end

@btime swap_rows_dumb(my_table, 2, 4)
  17.350 ns (0 allocations: 0 bytes)
  • Okay, finally. Zero memory allocation.

  • This makes me question why I am even trying to make it work with Julia.
  • If I cannot do simple row operations without blowing up memory, why am I not coding directly in C?