Log In  


Apologies if this is a duplicate, I'm new to the forums and couldn't find anything similar when searching.

I was making some centred variants of graphics functions and found that omitting the colour parameter would result in the pen colour being set to black

I've broken it down so you can use the following snippet to observe the issue (pico-8 0.2.3)

function pen_col()
 return peek(0x5f25)&0xf
end

cls(1)
color() -- reset pen colour

print("default colour",0,0)
assert(pen_col()==6)

print("nil produces black",0,6,nil)
assert(pen_col()==0)

print("draw state is now black",0,12)
assert(pen_col()==0)

color() -- reset pen colour
_c=nil
print("colour parameter containing nil is black",0,18,_c)
assert(pen_col()==0)

color() -- reset pen colour
print("back to default colour",0,24)
assert(pen_col()==6)

In my usage this means that if I wrap for example print, I'll want to forward the colour value, but allow for it to be omitted, in order to work around the bug I have to read the current pen colour from the draw state to prevent draw state defaulting to black.

I'd consider this a bug since passing nil colour should behave the same as omitting the colour parameter from the built in draw functions.



there are lots of edge cases like this with nil; for example, rnd() returns a value between 0 and 1 but rnd(nil) always returns 0.

It's confusing and I sometimes wish it wasn't like this, but I'd be surprised if it changed; I think it would be pretty hard to change this without breaking old carts. (it also might be more of a lua quirk than a pico-8 quirk? not sure)


That's unfortunate, I did some more and it doesn't appear to be lua quirk, or at least not a quirk in lua code

The following functions as expected for example

function pen_col()
 return peek(0x5f25)&0xf
end

function crect(_x,_y,_w,_h,_c)
 local _halfw,_halfh=_w*0.5,_h*0.5
 rect(_x-_halfw,_y-_halfh,_x+_halfw-1,_y+_halfh-1,_c or pen_col())
end

cls(1)
color()

crect(20,10,5,5)
assert(pen_col()==6)

crect(10,10,5,5,nil)
assert(pen_col()==6)

I don't know much about how pico-8 is made but I would assume that it's a c/c++ program using a lua API and the transition of nil parameters versus empty parameters over the API boundary is the actual culprit of the quirk here. Whether that quirk is caused by the lua API itself of the implementation would be another matter.


1

The way Lua works is that nil is a literal value, so if you pass it to a function, it's not the same thing as passing nothing.

The reason why this is confusing is that both nil and nothing will result in named arguments becoming nil inside the function.

Internally, however, the interpreter knows the difference, and this knowledge is exposed somewhat via the pack() function, which can pack the varargs to a function (the special "..." tuple) into an array table with an additional .n value to say how many values were passed:

> t=pack(1,2,3)
> print(t[4])
[nil]
> print(t.n)
3

> t=pack(1,2,3,nil)
> print(t[4])
[nil]
> print(t.n)
4

And I'm pretty certain zep deliberately converts a nil to 0 in most drawing functions because it allows people to write code that doesn't need to check for nil or indeed allows people to literally default unassigned colors to 0 if they actually want to do that. More useful in code golf and tweetcarts than in most games, but it also comes up in games sometimes.

The downside is that it also allows bad code to run when it should really assert or die so the author knows they dereferenced the wrong table or used the wrong variable or whatever. However, anyone writing Lua code is already painfully aware of this hazard because it can already happen in hundreds of other ways in Lua.

In general, I would expect API functions to treat an unexpected nil in a numeric arg as if it were 0. Also usually true for missing args, though with functions like print() or line() the number of args is actually important.



[Please log in to post a comment]