Destructuring In Other Places

Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:

MoonScript:

tuples = {
  {"hello", "world"}
  {"egg", "head"}
}

for {left, right} in *tuples
  print left, right

Lua:

local tuples = {
  {
    "hello",
    "world"
  },
  {
    "egg",
    "head"
  }
}
for _index_0 = 1, #tuples do
  local _des_0 = tuples[_index_0]
  local left, right
  left, right = _des_0[1], _des_0[2]
  print(left, right)
end

We know each element in the array table is a two item tuple, so we can unpack it directly in the names clause of the for statement using a destructure. Function Stubs

It is common to pass a function from an object around as a value, for example, passing an instance method into a function as a callback. If the function expects the object it is operating on as the first argument then you must somehow bundle that object with the function so it can be called properly.

The function stub syntax is a shorthand for creating a new closure function that bundles both the object and function. This new function calls the wrapped function in the correct context of the object.

Its syntax is the same as calling an instance method with the \ operator but with no argument list provided.

MoonScript:

my_object = {
  value: 1000
  write: => print "the value:", @value
}

run_callback = (func) ->
  print "running callback..."
  func!

-- this will not work:
-- the function has to no reference to my_object
run_callback my_object.write

-- function stub syntax
-- lets us bundle the object into a new function
run_callback my_object\write

Lua:

local my_object = {
  value = 1000,
  write = function(self)
    return print("the value:", self.value)
  end
}
local run_callback
run_callback = function(func)
  print("running callback...")
  return func()
end
run_callback(my_object.write)
run_callback((function()
  local _base_0 = my_object
  local _fn_0 = _base_0.write
  return function(...)
    return _fn_0(_base_0, ...)
  end
end)())

The Using Clause; Controlling Destructive Assignment

While lexical scoping can be a great help in reducing the complexity of the code we write, things can get unwieldy as the code size increases. Consider the following snippet:

i = 100

-- many lines of code...

my_func = ->
  i = 10
  while i > 0
    print i
    i -= 1

my_func!

print i -- will print 0

Lua:

local i = 100
local my_func
my_func = function()
  i = 10
  while i > 0 do
    print(i)
    i = i - 1
  end
end
my_func()
print(i)

In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn’t clear what names have already been declared.

It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident.

The using keyword lets us do that. using nil makes sure that no closed variables are overwritten in assignment. The using clause is placed after the argument list in a function, or in place of it if there are no arguments.

MoonScript:

i = 100

my_func = (using nil) ->
  i = "hello" -- a new local variable is created here

my_func!
print i -- prints 100, i is unaffected

Lua:

local i = 100
local my_func
my_func = function()
  local i = "hello"
end
my_func()
print(i)

Multiple names can be separated by commas. Closure values can still be accessed, they just cant be modified:

tmp = 1213
i, k = 100, 50

my_func = (add using k,i) ->
  tmp = tmp + add -- a new local tmp is created
  i += tmp
  k += tmp

my_func(22)
print i,k -- these have been updated

Lua:

local tmp = 1213
local i, k = 100, 50
local my_func
my_func = function(add)
  local tmp = tmp + add
  i = i + tmp
  k = k + tmp
end
my_func(22)
print(i, k)

results matching ""

    No results matching ""