Hi folks, I have a simple Lua question. I thought I'd ask here. Otherwise I could try StackOverflow, though I am sure it has been asked somewhere already.
function foobar()
end
print(foobar())
if foobar() ~= nil then
print("FOOBAR DOES NOT RETURN NIL")
end
The "FOOBAR DOES NOT RETURN NIL" is not printed. So am I to conclude that foobar is returning nil? This does not appear to be true. As is clear, foobar is returning nothing.
@FaheemMitha well, why are you checking the return of a function if your function clearly does not return anything? Your code simply does not make sense to me.
@FaheemMitha @Marcel might have a better understanding of this, but even the manual has some confusion on what a function with no return should "return in practice".
> foobar() == nil
true
@FaheemMitha my take is that the result of the last expression in the function is returned, which does not exist, and thus nil is returned.
@PauloCereda Perhaps so. I can't find any discussion of this, but searching for things related to "nil" and friends is hard. Maybe I'll ask a question on SO just for clarity.
The context is posix.stat, which returns nothing if there is no match.
actutally the manual says Results are returned using the return statement (see §3.3.4). If control reaches the end of a function without encountering a return statement, then the function returns with no results. so no return doesn't return nil but if teh function is used as an expression then such a thing is equal to nil, I wonder if that's documented..
(This is not an answer, just an opinion about the subject)
As for me, this artifical difference between nil and no value is inconsistent and rather annoying.
local function f1() return nil end
local function f0() end
local v1 = f1() -- OK, assigns nil
print(type(f1())) -- OK, prints 'nil...
@FaheemMitha the nil behaviour is documented lua.org/pil/5.1.html " If a function has no results, or not as many results as we need, Lua produces nils: " so foo() returns nothing but in foo()==nil a nil is "produced" so the construct returns true
@PauloCereda You might think, but especially in LuaTeX it sometimes does make a difference. E.g. the node library sometimes enforces the number of arguments, so if the last parameter is nil you can't replace it with a missing value. Other functions use e.g. the last argument instead of e.g. the third one, so again it makes a difference if the last argument is nil (and therefore counted) or doesn't exists.
But as long as the function call is not the last thing in an argument list or a return statement, there shouldn't be a difference.
@FaheemMitha print prints each argument it receives. So if it's nil, it prints nil, but if you don't pass any argument (since the function doesn't return anything) then it prints nothing. That directly follows from the official documentation. But in your case it sounds like you are actually wondering about format.
@FaheemMitha format has a variable number of arguments, so if you use a function in the last position which doesn't return anything than nothing is passed as argument. So your code is the same as foobar() print(string.format("RETURN VALUE OF FOOBAR IS %s")) . Lua warns about that since it expects format to receive the right number of arguments.
@FaheemMitha You can always put parens around your function to avoid that: print(string.format("RETURN VALUE OF FOOBAR IS %s", (foobar())))
@MarcelKrüger Well, it's confusing, because it looks like foo() returns nil. But it seems that that the nil return value is actually "constructed" in some fashion when assignments are made, or when its used in an expression.
(This is not an answer, just an opinion about the subject)
As for me, this artifical difference between nil and no value is inconsistent and rather annoying.
local function f1() return nil end
local function f0() end
local v1 = f1() -- OK, assigns nil
print(type(f1())) -- OK, prints 'nil...
No, actually not the same thing. Never mind.
Especially in the comparison case it's confusing, because there does not appear to be any assignment of the function value there.
@FaheemMitha There are IIRC two cases where Lua uses parens: After a function name to define the arguments or to pass them (which isn't the case here since there is nothing callable before them) or around an expression to form a new expression with the same value (used to change operator precedence). Therefore in this case the second case is used, which expects an expression inside. Therefore the empty list appears in an expression and gets converted to nil.
@MarcelKrüger Actually, if the function returns multiple values, it will just restrict to the first value if brackets are applied. So it has a second effect if used with a function.
@FaheemMitha That's not a second effect but exactly the same one. Whenever Lua needs n values and m are provided, it will discard the last values if m>n and will fill up with nil if n>m. In an expression (e.g. due to parens), one value is needed, so n=1. A function without return values provides 0 values, so m is zero.
@JosephWright et al. During the l3build change I noticed that the cp function applied to directories does not do the right thing on UNIX like systems. Fixing this while still using the cp command does not really seem possible using only POSIX functionality.
We could solve this by using a GNU extension which probably wouldn't work on BSD systems (and OSX) or with a BSD extension which isn't supporte by GNU (and therefore most Linuxes) or we could use rsync instead (but I don't know if that's installed everywhere).
@DavidCarlisle If a and b are directories and b exists, cp -r creates a directory b/a and copies stuff there while it copies directly into b is it does not exists. Since we often precreate the directories, this leads to very inconsistent behavior.
@DavidCarlisle Creating the target first is complicated if we explicitly want to copy into an existing directory (which might contain existing data). Also we can't delete a directory which isn't necessarily empty.
@MarcelKrüger thats true of files as well, not just cp -r if you go cp myfile /tmp/zzz then if zzz exists and is a directory you get /tmp/zzz/myfile otherwise you get /tmp/zzz being a copy of myfile
@MarcelKrüger yes but you can do a create if doesn't exist easily enough can't you?
@AlanMunn I tried that with luatex but you are reported as a missing character. I hope you are OK?
@DavidCarlisle Yes, but we want the other case. If we have a directory a and want to copy it's content into b, then we might know which case we are in but that only means that we know the files will end up in the wrong place.
@DavidCarlisle Well --no-target-directory would fix that too.
@DavidCarlisle That might work, but we'll have to check how this interacts with . and ... (It seems to depend on the shell if .* matches . and .., but especially copying .. might be problematic.) That makes me wonder if cp -r a/. b might do the right thing in all cases.
@Skillmon Not a big deal. I deleted that answer because it was wrong, not because it was downvoted—I wrote it on my phone away from a computer and realized it was wrong as I walked back home & deleted it as soon as I could.
@MarcelKrüger Perhaps you should be writing Lua documentation. And is a value needed in a comparison expression? It seems comparing to nothing would be legitimate.
@MarcelKrüger traditionally in Unix the trick was to use a tar -c -| tar xp - pipe to avoid problems. But my unix tricks skill is a bit old and with a lot of rust...
@JosephWright Anyway the direct-copy branch has some first code which uses it to copy directories as is. Basically used as tdsdirs = { sourcedir = 'tex' } to copy sourcedir into $TEXMF-WHATEVER/tex.
(I know that the name of the variable needs work...)