Vous êtes sur la page 1sur 7

5/1/13

Lua Gotchas

Lua Gotchas
1 Calling methods 2 Values which are false 3 Undeclared variables 3.1 .. are global by default 3.2 Variables must be declared before use. 4 All numbers are floating point 5 When does automatic conversion to string occur? 6 Tables are both arrays and dictionaries 6.1 Arrays start at one 6.2 Table keys 6.3 Undefined field access is a feature 6.4 Arrays with holes are bad news 6.5 Element order with pairs() is arbitrary 7 When to use parentheses with functions? 8 Expressions with multiple values 8.1 Functions can return multiple values 8.2 A Superficial similarity with Python 8.3 Multiple Assignments in Declarations 9 Values and references 10 Using metatables 10.1 __index is a fallback 10.2 __index can be a table 10.3 __eq cannot be used to compare arbitrary values 'Gotchas' are Lua features which are often confusing at first, if you are used to other languages. Here is a short list compiled from the Lua mailing list, particularly by Timothy Hunter.

1 Calling methods
If you are used to other languages, then o b j . m e t h o d ( )looks like a method call, but really it is just looking up 'method' in the context of o b jand then calling that function. To make a proper method call, use o b j : m e t h o d ( )which is 'syntactical sugar' for o b j . m e t h o d ( o b j )- that is, the colon passes the object as the first argument as s e l f . Common methods encountered in basic Lua programming are the string methods, like s : f i n d ( " h e l l o " )being short for s t r i n g . f i n d ( s , " h e l l o " ) .

2 Values which are false


C-like languages regard 0as equivalent to f a l s e , but this is not true for Lua. Only an explicit f a l s eor n i lare equivalent to f a l s e . When in doubt, make the condition explicit, e.g. i fv a l= =n i lt h e n . . .e n dunless the value is actually b o o l e a n .

3 Undeclared variables
www.luafaq.org/gotchas.html#T7 1/7

5/1/13

Lua Gotchas

3.1 .. are global by default


Like all dynamic languages, you don't have to declare variables. However, the scope of what gets implicitly declared is not the same. For instance, an undeclared variable is local to the function in Python, and you need the keyword g l o b a lto tell the interpreter to look outside. In Lua, the situation is exactly opposite; unless declared using l o c a l , Lua will look up a name in the current environment, which is usually _ G . Also, the value of an undeclared variable is n i l , because there is no special u n d e f i n e dvalue. Since n i lmay be an acceptable value for a variable, typing errors can bite deep. In larger programs, this can lead to madness, so people often use a technique which traps undefined global access - see strict model.

3.2 Variables must be declared before use.


This might seem an obvious point, but in JavaScript function declarations are 'hoisted' so that they can be declared in any order. This also works in Python:
d e ff o o ( ) : d e fb a r( ) : z o g ( ) d e fz o g ( ) : p r i n t" Z o g ! " b a r ( )

but the equivalent Lua does not because z o ghas not yet been declared:
f u n c t i o nf o o ( ) l o c a lf u n c t i o nb a r ( )z o g ( )e n d l o c a lf u n c t i o nz o g ( )p r i n t" Z o g ! "e n d b a r ( ) e n d

4 All numbers are floating point


The good news is that any integer up to 2^52 can be represented exactly by a 64-bit double-precision value. But don't expect equality to work always for floating-point values! (This is more a general programming gotcha, since you must become used to finite precision.) Lua can be compiled only to use integer arithmetic on embedded platforms that lack hardware floatingpoint support.

5 When does automatic conversion to string occur?


1 0 + " 2 0 "does work

in Lua, but 1 0 = = " 1 0 "is not true. In an arithmetic expression, Lua will attempt to convert strings to numbers, otherwise you will get a 'attempt to perform arithmetic on a string value'. Fortunately, string concatenation is a separate operator, so JavaScript-style weirdness does not happen so often: " 1 0 " . . " 2 0 "is unambiguously "1020".

6 Tables are both arrays and dictionaries


www.luafaq.org/gotchas.html#T7 2/7

5/1/13

Lua Gotchas

Lua tables are the ultimate one-stop-shop of data structures. It can be confusing that a table can behave like both kinds of containers at once, such as { 1 , 2 , 3 , e n a b l e = t r u e } . So you will see reference to the array-part and the 'hash' part of a table.

6.1 Arrays start at one


This gets people because starting at zero is more common, and the habit is hard to break. The problem is that t [ 0 ] = 1is not considered a problem, but then the length of the array will be off-by-one. The value is in the table, but is in the 'hash' or 'dictionary' part. The length operator #only applies from 1 to the last non- n i lelement.

6.2 Table keys


The 'key' in t . k e yis a constant 'key', not the variable named 'key'. This is because t . k e yis the same as t [ " k e y " ] . If you want to index by a variable, say t [ k e y ] . This 'quoting' also happens in table constructors, e.g. t = { k e y = 1 }sets the value of t . k e y . But, this can only work for valid Lua names that aren't keywords or contain special characters. So you must say t = { [ " f o r " ] = 1 , . . . } 'a n d t["for"]`. JavaScript programmers will be comfortable with Lua tables, but remember there is no distinction between 'undefined' and 'null'.

6.3 Undefined field access is a feature


In many languages, trying to access a non-existent key in a list or dictionary causes an exception; in Lua the result is simply n i l . This is unambiguous because n i lcannot be usefully put into tables.

6.4 Arrays with holes are bad news


Try not to put n i lin arrays. It will work if you know what you're doing, but the length operator #will be confused and standard table functions like t a b l e . s o r t ( )will complain bitterly. Sparse arrays have their uses, if you remember not to depend on # :
>t={ } >t [ 1 ]=1 >t [ 4 ]=4 >t [ 1 0 ]=1 0 >=# t >N B ! 1 >f o rk , vi np a i r s ( t )d op r i n t ( k , v )e n d 1 1 4 4 1 0 1 0

6.5 Element order with pairs() is arbitrary


Yes, you can use p a i r s ( )with an 'array', but don't expect to get the keys in ascending order. That is the first reason for i p a i r s ( )which makes that guarantee. The second reason for i p a i r s ( )is that it only goes over the 'array' part of a table.

7 When to use parentheses with functions?


www.luafaq.org/gotchas.html#T7 3/7

5/1/13

Lua Gotchas

Lua is different in that strings require parentheses if you want to call string methods, such as ( ' % s = % d ' ) : f o r m a t ( ' h e l l o ' , 4 2 ) . But there are important cases when you can leave out parentheses, such as p r i n t' h e l l o 'and m y f u n c{ 1 , 2 , 3 ;e n a b l e = t r u e } . If the single argument of a function is a string or a table constructor, then they can be safely left out. (The old-style Python p r i n t' h e l l o 'has another meaning, since p r i n tis a statement.)

8 Expressions with multiple values


Expressions can have multiple values, so you can swap two values with one line like so:
x , y=y , x

A powerful and unusual feature, but there are several things to be aware of.

8.1 Functions can return multiple values


A Lua function call can return multiple values. A number of the string functions work like this,for instance, s t r i n g . f i n dwill return the start index and end index of the match, plus any captures.
>s=" h e l l od o l l y " >p r i n t ( s : f i n d ( " ( d o l l y ) " ) ) 7 1 1 d o l l y

(Note that the parentheses in the string pattern have special meaning, like in standard regular expressions.) It is easy to write a function that returns multiple values:
f u n c t i o ns u m p r o d ( x , y )r e t u r nx + y ,x * ye n d

(The comma is never an operator in Lua; it is only a delimiter.) Furthermore, these multiple return values are treated specially in function calls and table constructors. The expression { s u m p r o d ( 1 0 , 2 0 ) }is the table { 3 0 , 2 0 0 }and p r i n t ( s u m p r o d ( 1 0 , 2 0 ) )has the same effect as p r i n t ( 3 0 , 2 0 0 ) . The function u n p a c kgoes the other way:
>p r i n t ( u n p a c k { 1 , 2 , 3 } ) 1 2 3

This is a powerful and efficient feature but it can bite you. For instance, consider this function that turns a string into hexadecimal bytes:
f u n c t i o ne s c a p e ( s ) r e t u r ns : g s u b ( ' . ' , f u n c t i o n ( s )r e t u r n( ' % 2 X ' ) : f o r m a t ( s : b y t e ( 1 ) )e n d ) e n d

But there is a gotcha:


>=e s c a p e ( '' )
www.luafaq.org/gotchas.html#T7 4/7

5/1/13

Lua Gotchas

2 0

s t r i n g . g s u breturns the result of the substitution plus the number of substitutions made -

so this function can mess up code that is expecting exactly one return code. The best solution is to enclose the expression in parentheses:
f u n c t i o ne s c a p e ( s ) r e t u r n( s : g s u b ( ' . ' , f u n c t i o n ( s )r e t u r n( ' % 2 X ' ) : f o r m a t ( s : b y t e ( 1 ) )e n d ) ) e n d

(Or you could assign the result of g s u bto a local variable and return that.) The rule for expanding multiple results only works for the last argument, so be careful with expressions like { f ( ) , g ( ) }- if f ( )returned multiple values, then only the first one would be used. (There has been a proposal for an operator that would 'unpack' multiple values in any position.)

8.2 A Superficial similarity with Python


Note that the following statement works in both Lua and Python, but in very different ways:
x , y=f u n ( )

In Lua, the function f u nreturns two values, in Python it returns one t u p l evalue, which it then helpfully unpacks in this context. This is one of the many little things that makes Lua the 'speed queen' of dynamic languages, since there is no extra hidden overhead with this assignment. A Python programmer may expect this to also implicitly unpack a table:
x , y={ 1 , 2 }

But there is no such magic in Lua, and you must explicitly use u n p a c k . It's a gotcha because it is not an error; xbecomes the table value, and ybecomes n i l .

8.3 Multiple Assignments in Declarations


In most languages, several variables can be declared and assigned at the same time:
v a rx=1 ,y=2

In Lua the equivalent is


l o c a lx , y=1 , 2

and you will get an 'unexpected symbol near '='' error if you try the first syntax.

9 Values and references


If x = 1 0and y = 1 0then we know that x = = y , but the same is not true for tables and other objects:
l o c a lt 1 , t 2={ } , { } p r i n t ( t 1= =t 2 ) = = >f a l s e

www.luafaq.org/gotchas.html#T7

5/7

5/1/13

Lua Gotchas

t 1and t 2are distinct

values; tables are never compared 'element by element'. It is straightforward to do this in Lua; for example see how d e e p c o m p a r eis defined in Penlight In the same way t 1=t 2does not make a copy of t 2 . The variable t 1will become another reference to the value of t 2 . Assigning to t 1 [ 1 ]will change t 2 [ 1 ] , because they simply point to the same object. Now, how does string equality work? Unlike Java, s 1 = = s 2will work on equal strings, character by character. This is because there is only ever one instance of any particular string stored in memory, so comparison is very quick (this is called interning), for an extra cost of string creation. This can work because strings are 'immutable', there is no way in Lua to modify the contents of a string directly. The same lessons taught to Java programmers apply here: building up a large string by concatenation creates a lot of temporary strings that can stress the garbage collector. The Lua way is to put the strings into a table and then use t a b l e . c o n c a t . If you are a C programmer, this may seem massively inefficient, but the answer is that Lua strings are not the right data structure for modification. Representing a string as a table of string fragments (sometimes called a 'rope') is much more efficient.

10 Using metatables
Lua has powerful meta-programming abilities through mechanism of metatables . Different table values can be given common behaviour by giving them the same metatable, and so you can think of it as a generalisation of the 'class' concept in other dynamic languages.

10.1 __index is a fallback


The metatable can have metamethods like _ _ i n d e x . This is called when table indexing fails, and in this example forces a table index to return a default zero value if out-of-bounds.
t={ 1 , 2 , 3 } s e t m e t a t a b l e ( t , { _ _ i n d e x=f u n c t i o n ( t , k )r e t u r n0e n d } ) p r i n t ( t [ 1 ] , t [ 5 ] ) >1 0

Cute, and incredibly powerful. In Lua 4.0 the equivalent concept was called a 'fallback' and that word describes the behaviour very well. A common misunderstanding is that _ _ i n d e xoverrides all table accesses, but this is not so. In a similar way, _ _ n e w i n d e xonly kicks in if the key does not exist in the table. (If you do need to do something for each table key access, then proxy tables are the suggested solution. This technique involves deliberately keeping the table empty, and keeping the implementation data separate. Then _ _ i n d e xwill always fire and you can return whatever you like - this can be used to implement true properties with getters and setters.)

10.2 __index can be a table


A common way to implement classes looks like this:
www.luafaq.org/gotchas.html#T7 6/7

5/1/13

Lua Gotchas

C={ } C . _ _ i n d e x=C f u n c t i o nC : m 1 ( )r e t u r ns e l f : m 2 ( )e n d -n o t et h ei m p l i c i ts e l fw i t h:s h o r t c u t f u n c t i o nC : m 2 ( )r e t u r ns e l f . v a l u ee n d

To construct a new instance of C , you make a new table and set its metatable to C .
f u n c t i o nC . n e w ( v a l u e ) l o c a lo b j=s e t m e t a t a b l e ( { } , C ) o b j . v a l u e=v a l u e r e t u r no b j e n d

The key to this trick is C . _ _ i n d e x=C ; people often think that merely putting functions in the metatable will allow objects to access them, but all unknown field accesses have to go through _ _ i n d e x , and this assignment lets objects find their functions in the metatable.

10.3 __eq cannot be used to compare arbitrary values


Looking at the manual shows you a full list of the available metamethods. For instance, you can override the usual equality operation and make it do something else, for instance do a true element-byelement comparison for lists. There is a gotcha with _ _ e q ; unlike the arithmetical metamethods, it insists that both arguments have the same metatable.

www.luafaq.org/gotchas.html#T7

7/7

Vous aimerez peut-être aussi