lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



On 1-Sep-05, at 8:18 AM, Lisa Parratt wrote:

Boyko Bantchev wrote:
... assuming `simple' values are meant.  Because tables, e.g.,
_are_ passed by reference.

They might look like they're being passed by reference, but they're not. All arguments in Lua are passed by value. They are not passed by copy, so when you pass a table (by value) you are passed the same table, which means you can mutate it (arg[key] = 42) or compare its object identity with another table, etc. Immutable objects (such as numbers and strings) are not copied either, since there are no mutators, so the copy is unnecessary.


Not really - you can't wholesale change the calling functions idea of which table is being referred to by a symbol, which you could if it were being passed truly by reference, only the members of said table.

It's a bit of a special case, and a bit of a mish-mash.

I think reasonable people could argue with the word "mish-mash". It's "not like C" :)

R.

PD. The simplest way to create a "reference" type in Lua is by creating a one-element table.
  a = {value = "some value"}

Deref:  a.value
Mutate: a.value = newvalue

Constructor to save a couple of keystrokes:
  function Box(val) return {value = val} end

Here's an overly complicated implementation illustrating various other options, depending on your needs/desires/sense of aesthetics.

do
  local meta = {}
  -- protect
  meta.__metatable = false

  -- box() dereferences the box
  function meta:__call() return self[1] end

  -- so does box.value
  function meta:__index(key)
    if key == "value" then return self[1]
       else return meta[key]
    end
  end
  -- which is read/write
  function meta:__newindex(key, val)
    if key == "value" then self[1] = val
      -- allow them to set attributes on a box
      else rawset(self, key, val)
    end
  end
  -- That slows down dereferencing a lot, so if you don't need that
  -- style, use this instead:
  --   meta.__index = meta

  -- so does box:get()
  -- function meta:get() return self[1] end
  meta.get = meta.__call  -- :)

  -- change the value with box:set(val)
  function meta:set(val) self[1] = val end

  -- change the value and get the old value
  -- with box:flip(val). (Some people like this
  -- semantic
  function meta:flip(val)
    local old = self[1]
    self[1] = val
    return old
  end

  ------ Actually create the object. You might prefer to call this Ref
  function Box(initial_value)
    return setmetatable({initial_value}, meta)
  end
end

-- Test run
> salutation = Box("Hello")
> audience = Box("world")
> function greet() print(salutation()..", "..audience()) end
> greet()
Hello, world
> salutation.value = "Good morning"
> audience:set "Luaphiles"
> greet()
Good morning, Luaphiles
> =salutation.value
Good morning
> =salutation()
Good morning
> =salutation:get()
Good morning
> old = salutation:flip("Good afternoon")
> greet()
Good afternoon, Luaphiles
> old = salutation:flip(old)
> greet()
Good morning, Luaphiles
>