Duktape borrows a lot from Lua conceptually. Below are a few notes on what's different in Duktape compared to Lua. This may be useful if you're already familiar with Lua.
All array and stack indices are zero-based, not one-based as in Lua. So,
bottom of stack is 0, second element from bottom is 1, and top element is -1.
Because 0 is no longer available to denote an invalid/non-existent element,
the constant DUK_INVALID_INDEX
is used instead in Duktape.
String indices are also zero-based, and slices are indicated with an inclusive start index and an exclusive end index (i.e. [start,end[). In Lua, slices are indicated with inclusive indices (i.e. [start,end]).
In Lua functions and threads are a separate type from objects. In Duktape the object type is used for plain objects, ECMAScript and native functions, and threads (coroutines). As a result, all of these have a mutable and extensible set of properties.
The concept closest to Lua userdata
is the Duktape buffer
type, with the following differences:
Lua lightuserdata
and Duktape pointer
are essentially
the same.
If you need to associate properties with a Duktape buffer, you can use a buffer object instead (or create your own object and store the plain buffer as its property). You can then add a finalizer to the object to free any resources related to the buffer. This works reasonably well as long as nothing else holds a reference to the buffer. If this were the case, the buffer could get used after the object had already been finalized. To safeguard against this, the native C structure should have a flag indicating whether the data structure is open or closed. This is good practice anyway for robust native code.
Duktape has a combined reference counting and non-incremental mark-and-sweep
garbage collector (mark-and-sweep is needed only for reference cycles). Collection
pauses can be avoided by disabling voluntary mark-and-sweep passes
(disable DUK_USE_VOLUNTARY_GC
). Lua has an incremental collector with
no pauses, but has no reference counting.
Duktape has an emergency garbage collector. Lua 5.2 has an emergency garbage collector while Lua 5.1 does not (there is an emergency GC patch though).
duk_safe_call()
is a protected C function call which
operates in the existing value stack frame. The function call is
not visible on the call stack all.
lua_cpcall()
creates a new stack frame.
Starting from Duktape 1.3 Duktape has a bytecode dump/load mechanism
similar to Lua lua_dump()
. See
Bytecode dump/load.
There is no equivalent of Lua metatables in ECMAScript E5/E5.1, but ECMAScript ES2015 Proxy objects provide similar functionality. To allow property virtualization better than available in E5/E5.1, Duktape implements an ES2015 Proxy subset.
lua_next()
replaces the previous key and value with a new pair,
while duk_next()
does not; the caller needs to explicitly pop the
key and/or value.
There is no equivalent to Lua raw table access functions like
lua_rawget
. One can use the following ECMAScript built-ins
for a similar effect (though not with respect to performance):
Object.getOwnPropertyDescriptor ( O, P ),
Object.defineProperty ( O, P, Attributes ).
There are no primitives for coroutine control in the Duktape API
(Lua API has e.g. lua_resume
). Coroutines can only be controlled
using the functions exposed by the Duktape
built-in. Further,
Duktape has quite many coroutine yield restrictions now; for instance,
coroutines cannot yield from inside constructor calls or getter/setter calls.
Lua supports multiple return values, Duktape (or ECMAScript) currently doesn't. This may change with ECMAScript ES2015, which has a syntax for multiple value returns. The Duktape/C API reserves return values above 1 so that they may be later used for multiple return values.
Lua supports weak references. Duktape currently doesn't.
Lua has no built-in Unicode support (strings are byte strings), while Duktape has support for 16-bit Unicode as part of ECMAScript compliance.
Lua has a streaming compilation API which is good when code is read from the disk or perhaps decompressed on-the-fly. Duktape currently does not support streaming compilation because it needs multiple passes over the source code.