Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Need help with code that generates lots of errors:
function()
local restedxp = GetXPExhaustion()
local totalXP = UnitXPMax("player")
local percent = 0
if restedxp > 0 then percent = floor((restedxp / totalXP) * 100) end
local ret = string.format("%s%%", percent)
return ret
end
Error: attempt to compare number to nil
Comparing a number vs nil doesn't make sense. Hence the error.
In your case you only have one comparison in the provided code which is any expression with a relational operator.
The usual thing you do is to find out which of the two values is nil and fix the reason or if you can't avoid that value being nil make sure you only do the comparison if it is not.
In your case this is pretty simple. You go to the line number which is given in the error message. You find the only conditional expression restedxp > 0 and as 0 is obviously a number it must be restedxp that is nil
You find out where restedxp is assigned the last value befor the comparison which is
local restedxp = GetXPExhaustion()
So GetXPEhaustion() returns nil!
If you have access to that function you may be able to fix it or at least find out if you can do anything so it won't return nil!
If you can't you either assign a default value to restedxp, for example 0.
local restedxp = GetXPExhaustion() or 0
Or you avoid to compare the values with a conditional statement.
if type(restedxp) == "number" and restedxp > 0 then
percent = restedXp // totalXP * 100
end
Or if you know restedxp is either a number or nil
if restedxp and restedxp > 0 then
percent = restedXp // totalXP * 100
end
The same makes sense for totalXP of course. Just also make sure it isn't 0 befor you divide.
Your string formatting is incorrect btw.
percent is a number so you should use %d instead of %s as %s refers to a string. It will work as Lua will convert your number to a string but it's not very clean.
https://www.lua.org/manual/5.3/manual.html#pdf-string.format
Option s expects a string; if its argument is not a string, it is
converted to one following the same rules of tostring. If the option
has any modifier (flags, width, length), the string argument should
not contain embedded zeros.
Related
This question already has an answer here:
Lua: attempt to perform arithmetic on a string value
(1 answer)
Closed 5 years ago.
Here is my error message:
Panel: [name:DItemSlot][class:Panel][138,69,64,64]
[ERROR] addons/pointshop2/lua/ps2/client/notifications/cl_knotificationpanelmanager.lua:91: attempt to perform arithmetic on field 'duration' (a string value)
1. unknown - addons/pointshop2/lua/ps2/client/notifications/cl_knotificationpanelmanager.lua:91
And here is my code:
if not self.panelSlidingIn and #self.notificationsWaiting > 0 then
self.panelSlidingIn = table.remove( self.notificationsWaiting, 1 ) --
Dequeue
self.panelSlidingIn:SetParent( self )
self.panelSlidingIn:SetVisible( true )
self.panelSlidingIn.slideOutStart = CurTime( ) +
self.panelSlidingIn.duration + self.slideInDuration
self.slidingStarted = CurTime( )
table.insert( self.notifications, self.panelSlidingIn )
surface.PlaySound( self.panelSlidingIn.sound or
"kreport/misc_menu_4.wav" )
end
I don't know what is happening, and I can't seem to fix it either.
When you use + operator on string Lua tries to convert them to numbers. If it couldn't it gives you such errors. If you want to concatinate strings use operator .. instead. If you want to make arithmetics, make sure strings have convertable values.
Similar question: here.
I found this code on another thread.
def is_number? string
true if Float(string) rescue false
end
Instead of using a method to return true or false, I'd like to do this "is_numeric" test in one line, in an if statement. Can someone explain if this is possible? I'm getting errors at the moment both when the string variable is null and when it contains non-numeric characters.
if Float(string)
* do something
else
* do something else
end
if Float() is pointless code, since Float() will either return a truthy value or raise an error (based on my limited look at the source code - as of writing, you can follow the code path from line #2942). I'd suggest you're asking the wrong question/looking at the problem wrong (it'd be helpful to know what you're actually trying to achieve).
To do something with Float() on one line and avoid breaking code, use rescue as a statement modifier, as has been done in the is_number? method posted.
Float(string) rescue 0.0 # trying to emulate String#to_f!
Ensuring the phone number is 10 digits, numbers only, is quite simple.
PHONE_NUM_LENGTH = 10
string.length == PHONE_NUM_LENGTH && string.count('0-9') == PHONE_NUM_LENGTH
will return the true/false value representing this check. This is more efficient than a Regex.
The first part,
string.length == PHONE_NUM_LENGTH
checks whether the string is 10 characters long. The second,
string.count('0-9') == PHONE_NUM_LENGTH
checks whether it has exactly 10 numeric characters.
The, well, special specification of Lua's length operator made me wonder whether Lua would be "allowed" to return a negative value in a situation like
#{[-5]=1,[-1]=3}
It says:
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil;
n=-5 and n=-1 would meet this criterion in my example, right?
moreover, if t[1] is nil, n can be zero.
Right, it can be zero, but it's not guaranteed, right?
For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value.
This isn't the case here, so it doesn't apply.
If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
This is the case here, so again, n=-5 and n=-1 would be valid return values, right?
Can I be entirely certain that Lua always returns 0 for the example table, or any other table containing only negative indices? If (hypothetically) I'd be writing a Lua interpreter and would return either of those values, would I be conforming with the specifications?
Edit
Obviously, the way Lua is implemented, it does not return negative values. I felt the length operator is somewhat underdocumented and I see that Lua 5.2's documentation has changed. It now says:
Unless a __len metamethod is given, the length of a table t is only defined if the table is a sequence, that is, the set of its positive numeric keys is equal to {1..n} for some integer n. In that case, n is its length. Note that a table like
{10, 20, nil, 40}
is not a sequence, because it has the key 4 but does not have the key 3.
So, it now talks about positive numeric keys, that's much clearer. I'm left wiser but not totally happy with the documentation. When it says the "length is only defined if the table is a sequence", it should also state that even if the table is not a sequence a value is returned, but the behavior is undefined. Also, this table looks pretty much like a sequence:
a = setmetatable(
{0},
{
__index = function(t,k)
return k < 10 and k or nil
end
}
)
i = 1
while a[i] do
print(a[i])
i = i+1
end
--[[ prints:
0
2
3
4
5
6
7
8
9
]]
print(#a)
-- prints: 1
However, this is becoming nitpicking as it's pretty clear that it wouldn't make sense to take into account what mess __index might make. And Stackoverflow is certainly not the place to complain about documentation that could be more precise.
As you have noted, the specification of the length operator has changed between 5.1 and 5.2.
Can I be entirely certain that Lua always returns 0 for the example table, or any other table containing only negative indices?
You can for the current reference implementation, which ensures that for ilen defined
function ilen (xs)
local i=0
while xs[i+1] do i=i+1 end
return i
end
we always have #xs >= ilen(xs) - see the definition of luaH_getn in the ltable.c source. But the specification now deliberately does not promise this behaviour: a conformant implementation can return nil or raise an exception for attempts to find the length of tables that are not sequences.
From the text in reference link. The answer is NO.
I think your confusing the fact that if a NIL is found then the length of the table is deemed to be position the NIL was found -1.
Therefore if t(1) is NIL then 1 - 1 = 0 so the table length is 0.
If the length of a table was 5 then the next position or t(6) IS or WOULD BE NIL
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero.
Easy question here, probably, but searching did not find a similar question.
The # operator finds the length of a string, among other things, great. But with Lua being dynamically typed, thus no conversion operators, how does one type a number as a string in order to determine its length?
For example suppose I want to print the factorials from 1 to 9 in a formatted table.
i,F = 1,1
while i<10 do
print(i.."! == "..string.rep("0",10-#F)..F)
i=i+1
F=F*i
end
error: attempt to get length of global 'F' (a number value)
why not use tostring(F) to convert F to a string?
Alternatively,
length = math.floor(math.log10(number)+1)
Careful though, this will only work where n > 0!
There are probably a dozen ways to do this. The easy way is to use tostring as Dan mentions. You could also concatenate an empty string, e.g. F_str=""..F to get F_str as a string representation. But since you are trying to output a formatted string, use the string.format method to do all the hard work for you:
i,F = 1,1
while i<10 do
print(string.format("%01d! == %010d", i, F))
i=i+1
F=F*i
end
Isn't while tostring(F).len < 10 do useful?
I have variable that contains a number. While Lua allows variables to be set to nil, the variable then becomes toxic - destroying all code in its path.
If a variable contains a nil, I want it converted to a zero.
local score;
score = gameResults.finalScore;
I want to ensure that score contains a number, so I try:
local score;
score = tonumber(gameResults.finalScore);
but that doesn't work. So I try:
local function ToNumberEx(v)
if (v == nil) then
return 0
else
return tonumber(v)
end
local score;
score = ToNumberEx(gameResults.finalScore);
but that doesn't work. So I try:
local function ToNumberEx(v)
if (v == nil) then
return 0
else
return tonumber(v)
end
local score;
score = ToNumberEx(gameResults.finalScore);
if (score == nil) then
score = 0
end
That works, but defeats the purpose of having a function.
What is wrong with the function? I'm sure there is a perfectly reasonable and logical explanation - except to anyone who is familiar with programming languages.
score = tonumber(gameResults.finalScore) or 0
If the argument is already a number or
a string convertible to a number, then
tonumber returns this number;
otherwise, it returns nil.
Your code was good, except you didn't take into account what happens when gameResult.finalScore can't be converted to a number, if it was " " or "stuff" or a table than tonumber would return nil. None of your checks could detect that kind of situation.
If you really want to enforce that this variable gameResults.finalScore has this behavior (set to zero when receives any value different from a number), than you should take a look at Lua metatables.
You could create a metatable for gameResults, and "overwrite" the "index" and "newindex" methods of the metatable, checking the value for the finalScore field, and thus enforcing it's value to be on the desired ranges.
Not the best solution, but depending on your case, could be a good defensive practice against some other "evil developer" on the team. :-)
www.lua.org/pil/13.html (I'm not currently allowed to post more than 1 link) PiL 1 can help too, if you are still using Lua 5.0 or you want a more deep understanding of the metatables concept.