Type algorithms

This section describes how type-related Ecmascript algorithms like comparisons and coercions are extended to Duktape custom types. Duktape specific type algorithms (ToBuffer() and ToPointer()) are also discussed.

Notation

The following shorthand is used to indicate how values are compared:

ValueDescription
tcompares to true
fcompares to false
ssimple compare: boolean-to-boolean, string-to-string (string contents compared), buffer-to-buffer (buffer contents compared), buffer-to-string (buffer and string contents compared)
nnumber compare: NaN values compare false, zeroes compare true regardless of sign (e.g. +0 == -0)
Nnumber compare in SameValue: NaN values compare true, zeroes compare with sign (e.g. SameValue(+0,-0) is false)
pheap pointer compare
Llightfunc compare: to be considered equal, Duktape/C function pointers and internal control flags (including the "magic" value) must match
1string/buffer vs. number: coerce string with ToNumber() and retry comparison; a buffer is first coerced to string and then to number (e.g. buffer with "2.5" coerces eventually to number 2.5)
2boolean vs. any: coerce boolean with ToNumber() and retry comparison
3object vs. string/number/buffer: coerce object with ToPrimitive() and retry comparison

Equality (non-strict)

Non-strict equality comparison is specified in The Abstract Equality Comparison Algorithm for standard types. Custom type behavior is as follows:

The standard behavior as well as behavior for Duktape custom types is summarized in the table below:

undnulboonumstrobjbufptrlfn
undt t f f f f f f f
nul t f f f f f f f
boo s 2 2 2 2 f f
num n 1 3 1 f f
str s 3 s f f
obj p 3 f f
buf s f f
ptr s f
lfn L

Strict equality

Strict equality is much more straightforward and preferable whenever possible for simplicity and performance. It is described in The Strict Equality Comparison Algorithm for standard types. Custom type behavior is as follows:

The standard behavior as well as behavior for Duktape custom types is summarized in the table below:

undnulboonumstrobjbufptrlfn
undt f f f f f f f f
nul t f f f f f f f
boo s f f f f f f
num n f f f f f
str s f f f f
obj p f f f
buf p f f
ptr s f
lfn L

SameValue

The SameValue algorithm is not easy to invoke from user code. It is used by e.g. Object.defineProperty() when checking whether a property value is about to change. SameValue is even stricter than a strict equality comparison, and most notably differs in how numbers are compared. It is specified in The SameValue algorithm for standard types. Custom type behavior is as follows:

The standard behavior as well as behavior for Duktape custom types is summarized in the table below:

undnulboonumstrobjbufptrlfn
undt f f f f f f f f
nul t f f f f f f f
boo s f f f f f f
num N f f f f f
str s f f f f
obj p f f f
buf p f f
ptr s f
lfn L

Type conversion and testing

The custom types behave as follows for Ecmascript coercions described Type Conversion and Testing (except SameValue which was already covered above):

bufferpointerlightfunc
DefaultValueTypeErrorTypeError"light_<PTR>_<FLAGS>" (toString/valueOf)
ToPrimitiveidentityidentity "light_<PTR>_<FLAGS>" (toString/valueOf)
ToBooleanfalse for zero-size buffer, true otherwisefalse for NULL pointer, true otherwisetrue
ToNumberlike ToNumber() for a string0 for NULL pointer, 1 otherwiseNaN
ToIntegersame as ToNumbersame as ToNumber0
ToInt32same as ToNumbersame as ToNumber0
ToUint32same as ToNumbersame as ToNumber0
ToUint16same as ToNumbersame as ToNumber0
ToStringstring with bytes from buffer datasprintf() with %p format (platform specific)"light_<PTR>_<FLAGS>"
ToObjectBuffer objectPointer objectFunction object
CheckObjectCoercibleallow (no error)allow (no error)allow (no error)
IsCallablefalsefalsetrue
SameValue(covered above)(covered above)(covered above)

When a buffer is string coerced, the bytes from the buffer are used directly as string data. The bytes will then be interpreted as CESU-8 (or extended UTF-8) from Ecmascript point of view.

When a lightfunc is coerced with ToPrimitive() it behaves like an ordinary function: it gets coerced with Function.prototype.toString() with the result (normally) being the same as ToString() coercion.

When a lightfunc is object coerced, a new Function object is created and the virtual properties (name and length and the internal "magic" value are copied over to the Function object.

Custom coercions (ToBuffer, ToPointer)

ToBuffer() coercion is used when a value is forced into a buffer type e.g. with the duk_to_buffer() API call. The coercion is as follows:

ToPointer() coercion is used e.g. by the duk_to_pointer() call. The coercion is as follows:

The following table summarizes how different types are handled:

ToBufferToPointer
undefinedbuffer with "undefined"NULL
nullbuffer with "null"NULL
booleanbuffer with "true" or "false"NULL
numberbuffer with string coerced numberNULL
stringbuffer with copy of string dataptr to heap hdr
objectbuffer with ToString(value)ptr to heap hdr
bufferidentityptr to heap hdr
pointersprintf() with %p format (platform specific)identity
lightfuncbuffer with ToString(value)NULL
There is currently no ToLightFunc() coercion. Lightfuncs can only be created using the Duktape C API.

Addition

The Ecmascript addition operator is specified in The Addition operator (+). Addition behaves specially if either argument is a string: the other argument is coerced to a string and the strings are then concatenated. This behavior is extended to custom types as follows:

Property access

If a plain buffer or pointer is used as a property access base value, properties are looked up from the (initial) built-in prototype object (Duktape.Buffer.prototype or Duktape.Pointer.prototype). This mimics the behavior of standard types.

For example:

duk> buf = Duktape.dec('hex', '414243');  // plain buffer
= ABC
duk> buf.toString;
= function toString() {/* native */}
duk> typeof buf.toString();
= string

Lightfuncs have a few non-configurable and non-writable virtual properties (name and length) and inherit their remaining properties from Function.prototype, which allows ordinary inherited Function methods to be called:

var bound = myLightFunc.bind('dummy', 123);