Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arguments to require'd function get lost/disappear in Lua?

Tags:

lua

While I don't really know Lua, this is a rather unexpected and bizarre behavior.

Let's say I have my_module.lua:

local function dump(o) -- SO:9168058
  if type(o) == 'table' then
    local s = '{ '
    for k,v in pairs(o) do
       if type(k) ~= 'number' then k = '"'..k..'"' end
       s = s .. '['..k..'] = ' .. dump(v) .. ','
    end
    return s .. '} '
  else
    return tostring(o)
  end
end


local mymodule = {}

function mymodule.myfunction(indict)
  print(dump(indict))
end

return mymodule

Ok, now I run this:

lua5.3 -e "mm=require('my_module'); mm:myfunction({aa=12})"

This should not be complicated - I "import" the module, and call a function in it with an argument that is an object (the table/associative array/dictionary {aa=12}). Then I simply try to print this argument from within the function. However, I get this:

$ lua5.3 -e "mm=require('my_module'); mm:myfunction({aa=12})"
{ ["myfunction"] = function: 0x5619aeddf770,} 

So, the response to print(dump(indict)) inside myfunction, where indict is an argument passed to myfunction, Lua prints .... "myfunction" ????!

I cannot even wrap my head around this - how can this possibly happen ?

And how can I pass an object as an argument to a function, such that when I print the argument from within the function, the object which is the argument is printed - and not the function itself ??!

Btw, the same happens even if I just pass a number instead of an object, say:

lua5.3 -e "mm=require('my_module'); mm:myfunction(42)"

EDIT: did a bit of debugging - so with this:

function mymodule.myfunction(indict)
  print(indict)
  print(dump(indict))
end

... I get this printout when using a numeric argument:

$ lua5.3 -e "mm=require('my_module'); mm:myfunction(42)"
table: 0x55f15a7a07a0
{ ["myfunction"] = function: 0x55f15a7a07e0,} 

... so it simply doesn't see this number anywhere, but the function sees itself as the first argument.

This reminded me, how in a Python class, you have to write methods as functions with "self" as first argument, so I tried this:

function mymodule.myfunction(self, indict)
  print("self", self, "indict", indict)
  print(dump(indict))
end

... which prints:

$ lua5.3 -e "mm=require('my_module'); mm:myfunction(42)"
self    table: 0x560510b5a7d0   indict  42
42

... or in case of passing an obect:

$ lua5.3 -e "mm=require('my_module'); mm:myfunction({aa=12})"
self    table: 0x55d51c9d5800   indict  table: 0x55d51c9d5880
{ ["aa"] = 12,} 

... well, that's more like it ...

Can anyone explain where does this come from - why do I need to add a "self" argument in this case?

like image 608
sdaau Avatar asked Jan 30 '26 23:01

sdaau


1 Answers

In lua, the call a:b(x) passes a reference to the object a as the first (self) parameter to the function b.

Since your module definition is:

function mymodule.myfunction(indict)

and the call statement is mm:myfunction, the object/table mm is passed as the first parameter (which here is indict).

Either change the function definition to

function mymodule:myfunction(indict)

if you want to keep call like mm:myfunction, or call the function as mm.myfunction.


The behaviour is discussed in detail in the PiL book on OOP concepts.

The effect of the colon is to add an extra hidden parameter in a method definition and to add an extra argument in a method call. The colon is only a syntactic facility, although a convenient one; there is nothing really new here.

like image 55
hjpotter92 Avatar answered Feb 03 '26 01:02

hjpotter92



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!