`local` just in case: good idea or code smell?

I often write local to ensure a variable does not accidently reuse another definition such as in the example below. Is that a good idea, or is there something more sophisticated I should be doing to test local scoping?

function f(input)
  ...
  p = plot(...)
  for i in input.n
      local a = ...
      local b = ...
      local c = ...
      local x = ...
      local y = ...
      local z = ...
      plot!(p, x, y, z)
  end
  ...
  return MyType(..., p, ...)
end
2 Likes

This is a little abstract, but for the case you seemed to have sketched out, why not just write a new function to call in the loop?

for i in input.n
    do_my_thing!(p, i)
end

You can declare all your locals a, b, c, ... in do_my_thing! and have no worries about polluting your outer function scope then.

1 Like

I guess that’s let:

  for i in input.n
      let a = ...,
          b = ...,
          c = ...,
          x = ...,
          y = ...,
          z = ...
          plot!(p, x, y, z)
       end
  end
1 Like

That feels to me like a weird thing to break out into its own function. I can’t call it plot_my_data because the setup for the plot is outside the loop. I would have to call it like add_data_to_p_plot! and move its definition outside the main function, away from the external related lines.

I guess the main reason probably comes down to function naming. I could move everything starting from p=plot(...) to its own function, but it would have to be named plot_some_aspect_of_my_data, since f in my actual code is already basically named plot_my_data.

The other scenario in which I use this pattern is if I need to calculate another index based on i like local j = 3(i-1)+1. In this case, I need that name j locally for several subsequent calls using outer variables, so I don’t think it makes sense as a separate function.

In any case, making up a new function name any time I need a for loop sounds difficult.

Cannot remember that I ever used local … but would probably consider the fact that the function has grown so long that I need to restrict variable bindings to a smaller subpart of it as the code smell – rule of thumb: don’t need to scroll to see whole function.

2 Likes

To a certain extent, I guess this is a matter of style, and for me personally, one of the big reasons I switched from matlab to julia was that small-function overhead was so huge in matlab (at least at the time, not sure what it’s like now), which gave me a lot of the problems you describe, but with julia I just make a bunch of little functions.

Perhaps a related problem is that there are so many local variables in scope you don’t feel confident you’re not overwriting something important, perhaps these could be organized into something a bit more structured? Say that your x, y, and z represent coordinates. You could then write

for i in input.n
    coords = calculate_coordinate_set_i(i)
    plot!(p, coords.x, coords.y, coords.z)
end

If other variables across your outer function are similarly contained in structs, NamedTuples, or what-have-you with descriptive names, it seems you could use small variable names like j for indices without it overwriting anything important.

Ultimately though, if this is just you plotting things, and you found a system that works for you, I’d say you’re all good.

2 Likes

Still working on breaking my procedural Matlab habits I think lol

1 Like

Perhaps bunching the local declerations together is easier on the eyes:

function f(input)
  ...
  p = plot(...)
  for i in input.n
      local a,b,c,x,y,z
      a = ...
      b = ...
      c = ...
      x = ...
      y = ...
      z = ...
      plot!(p, x, y, z)
  end
  ...
  return MyType(..., p, ...)
end
2 Likes

Perhaps bunching the local declerations together is easier on the eyes:

I would recommend against this. I used to do this in Lua a lot, but it’s easy for the declarations and the assignments to get out of sync, making refactoring harder.

let is basically the same, without having to write the variable names twice.

5 Likes