RiX Types And Traits Guide
RiX separates concrete runtime facts from sticky semantic interpretation.
Runtime metadata is ephemeral:
._typenames the current concrete runtime shape, such asInteger,Rational,RationalInterval,array, ortensor.._protois the built-in/runtime method layer.
Semantic metadata is sticky:
.__nameis an optional semantic name..__typeis the requested semantic type, such as:Rational,:RationalInterval, or:Tensor..__traitsis the materialized set of semantic traits..__protocontains semantic method layers.
.__proto is a map with:
.__proto[:traits].__proto[:type]
Method lookup checks direct meta first, then trait proto methods, then type proto methods, then runtime ._proto.
Trait Registry
Traits are immutable semantic capability entries. A trait may define implied traits, verification, proto methods, and descriptive metadata.
Trait implication is resolved when traits are applied. All implied traits are materialized into .__traits, so inquiry stays simple:
x = {^ /::Rational/ 7}
x ? :number
x ? :ring
x ? :field
x ? :rational
x ? :trait checks .__traits directly. It does not dynamically walk implication chains.
Trait proto methods are layered in application order. Later traits overwrite earlier trait methods.
Type Registry
Types are immutable protocol bundles. A type can define conversion, normalization, validation, default traits, type proto, export/import hooks, and system operator variants.
Built-in registered types include:
:Integer:Rational:RationalInterval:String:Array:Tuple:Map:Tensor:Set:Function:Multifunction:Null:Hole
Lowercase aliases such as :rational, :interval, and :tensor remain supported for compatibility. New code should prefer registered semantic names such as :Rational.
Conversion
The same target-driven conversion path is used by:
x ~: :Rational
x ~!: :Rational
{^ /::Rational/ x}
Soft conversion returns _ on conversion failure. Strict conversion and semantic headers throw.
The pipeline:
- Find the target type entry.
- Determine the semantic source type from
.__typeand runtime source type from._typeor the concrete value. - Try
convertFromfor the runtime/source type. - Try the type’s generic converter.
- Normalize and validate.
- Set sticky
.__type. - Materialize default and explicit traits, including implications.
- Build
.__proto[:type]and.__proto[:traits]. - Refresh runtime metadata.
Sticky semantic type is reapplied during ~= and ~~= updates, so a value like {^ /::Rational/ 7} remains a Rational when updated with a new exact value.
Export And Import
Type export uses tagged maps:
r = 7 ~: :Rational
e = .TypeExport(r)
r2 = .TypeImport(e)
r == r2
Export maps contain:
typedatacacheversion
Ordinary cell metadata such as .lock, .key, .frozen, and .immutable is not part of ordinary type export.
Operator Installation
Selected internal system operators are system multifunctions. They try installed type variants first and keep the native implementation as the final /NativeFallback/ variant.
First-wave operators include:
ADD,SUB,MUL,DIVINTDIV,MODPOW,POWPRODNEGEQ,LT,GT,LTE,GTEABS,SQRTSIN,COS,TAN,ASIN,ACOS,ATAN,ATAN2LOG,LN,LOG10,EXP
Built-in type installation currently installs Rational arithmetic/comparison variants before native fallback. Type install order is dispatch order; fallback remains last.
^ lowers to POW. ** lowers to POWPROD. Both currently share native behavior, but they are distinct system functions and operator aliases:
@^ ## .POW
@** ## .POWPROD
Defining New Types And Traits
The runtime core is implemented in JavaScript, but extension registration is available from RiX startup code through system helpers:
.TraitRegister({=
name = :exampleTrait,
implies = [:number],
proto = {=
Describe = (self) -> "example trait"
}
})
.TypeRegister({=
name = :Example,
nativeType = :map,
defaultTraits = [:exampleTrait],
convertFrom = {=
integer = (x) -> {= kind = :example, value = x }
},
validate = (x) -> x[:kind] == :example,
proto = {=
Value = (self) -> self[:value]
},
installs = {= }
})
.TypeInstall(:Example)
Hosts can still use the JS-side helpers in src/runtime/type-system.js for core bootstrapping:
registerTrait(spec)registerType(spec)installRegisteredTypes(registry, typeNames)
Registration stores immutable specs. Installation injects operator variants into system multifunctions.
Integer, Rational, and RationalInterval are built-in exact numeric types. Oracle-style real number implementations are deliberately not built in. They are user-land types so multiple real-number representations can coexist and be compared.
The example startup source in src/startup/oracle-example.rix registers:
:refinable:approximate:oracle:Oracle
The JavaScript loader in src/startup/oracle-example.js only reads and evaluates that RiX startup source. Hosts can load it when creating the registry:
import { createDefaultRegistry } from "./src/evaluator.js";
import { loadOracleExampleStartup } from "./src/startup/oracle-example.js";
const registry = createDefaultRegistry({
startupLoaders: [loadOracleExampleStartup],
});After that startup load, RiX code can use the example type:
o = 7 ~: :Oracle
e = .TypeExport(o)
o2 = .TypeImport(e)
o2.Mid()
The Float example demonstrates a different extension pattern. It lives outside the evaluator core in rix/examples/floats/, so it can become a standalone package or submodule. Its interface is a RiX startup file named floats.js.rix, while the heavy arithmetic and JavaScript Math calls live in the neighboring floats.js.
The generic bridge is:
.ImportJS("floats.js")
.JSCall("floats.js", :Sin, x)
.ImportJS loads a local JavaScript module relative to the active .js.rix startup file. .JSCall calls one named export from that module. Float-specific helpers such as FloatLte are not system capabilities; they are plain JavaScript exports used only by the Float package.
f = 1 ~: :Float
g = 2 ~: :Float
h = f + g * g
s = .SIN(f)
e = .EXP(f)
Float installs overloads for arithmetic, comparison, and common real-valued math functions. Those functions are system multifunctions with /NativeFallback/ variants, so later user-land real-number types can install their own SIN, LOG, EXP, and related variants without replacing the Float implementation.