Properties of types and values
This chapter defines cross-cutting value behavior: equality, boolean contexts, string conversion, and the (deliberately minimal) set of implicit conversions.
No implicit conversion
The language performs no implicit conversion between unrelated types at run time. Operations that require a particular type assert it and raise a run-time type error on mismatch (Error conditions). In particular:
- A string is never silently parsed as an integer. Use
intfor an explicit parse. - A string is never silently split into words. Use
wordsfor an explicit conversion to a word iterable. - Arithmetic (
+ - * / %) and ordered comparison (gt lt ge le) requireintoperands.
The single exception is conversion to string, which always succeeds (see String conversion) and is what makes interpolation and concatenation work on any value.
Equality
eq and ne (and ismember) compare as follows:
| Type | Compares equal when … |
|---|---|
| null | both are null |
| bool | same value |
| int | same value |
| string | same byte content |
| entity reference | denotes the same entity |
| prototype | same vnum |
| room | same room |
| iterable | never (even to itself) |
| block / list | identity only |
[eq 1 1] # true
[eq '1' 1] # false — string vs int
[eq true 1] # false — bool vs int
[eq $a $b] # creatures: equal iff same creature
Boolean contexts
Every boolean context requires a value of type bool. There is no
truthiness coercion at runtime: passing any non-bool value raises a
type error and halts the script.
The boolean contexts are:
if/elifconditionsand,or,not- the handler guards
requireandunless - the predicate result of
select,every,some(and any predicate-driven higher-order builtin)
String conversion
Any value may convert to a string. This conversion is invoked by interpolation and whenever a string is required.
| Type | Rendering |
|---|---|
| null | "" (empty) |
| bool | "true" / "false" |
| int | decimal digits |
| string | itself |
| creature | #mob:N# (NPC) or #player:N# (PC) |
| mob_proto | #mob:N# |
| object | #obj:N# |
| obj_proto | #obj:N# |
| room | #room:N# (N is the room number) |
| iterable | elements space-joined (brace-quoting elements that contain spaces or braces); deferred iterables (from select and slice) render as <iterable> |
| block | <block> |
| list | <list> (elements are not rendered) |
Binding and sharing
When a value is read from a variable or passed as an argument, the relationship between the original and the new binding depends on type:
- Scalars and entity references. Each binding is independent: mutating one variable does not affect another that held the same value. An entity reference in a different variable still denotes the same game entity — the entity itself is not duplicated.
- Iterables. Each binding traverses independently — advancing one does not affect another.
- Blocks and lists. Multiple bindings of the same block or list all refer to the same block or list: they compare equal by identity, and mutations to the block's enclosing bindings are visible through all of them.
A block may access its enclosing bindings for as long as the block exists (Declarations and scope).