Everything is an object
Every value in neo is an object. Numbers, booleans,
running processes, methods, errors, and the editor
itself are all objects responding to the same mechanism.
Objects communicate through objects
Objects communicate by sending messages. Messages and running
calls are themselves objects, participating in the same world
as their senders and receivers. Just as a chemical signal
between cells belongs to the same physical world as the cells,
communication in neo belongs to the same object graph as the
objects communicating.
This is an ontological commitment. How messages are dispatched
and calls are executed is an implementation question; their
place in the object world is part of the theory.
Code is data
A neo program is not text that compiles into something else.
It is a graph of objects in the same image as everything else.
A method is an object. A running call is an object.
Program structure, communication, and execution state all
inhabit the same object ontology.
Homoiconicity follows from representing programs as objects
in that world. Treating messages and running calls as objects
extends this uniformity to communication and execution. It is
a broader commitment than homoiconicity alone requires.
This is homoiconicity in the strongest sense. Code isn't
merely inspectable as data, it is data, completely,
without exception. You can reach into a running program,
find a method object, change one of its slots, and the
change is live in the next call. There is no edit-compile-run cycle,
only the image.
The object graph is n-dimensional
Every object inhabits a space. Dimensionality belongs to
the object itself, not to an external coordinate system
imposed from outside. A 2D panel, a 3D simulation body,
a 10-dimensional embedding, and a scalar with no spatial
meaning coexist in the same image under a uniform spatial protocol.
Objects that need no spatial properties pay nothing for the ones that do.
Spaces are first-class objects. Rendering is a morphism
from an object's native space onto the viewer's space.
The scene graph is not a separate data structure;
it is the natural relation between objects that share a geometric space.
Spatial indexing, physics, and constraints follow the same pattern,
one mechanism instead of four.
Prototype-based, no classes
There are no class definitions. Objects inherit from
objects directly. To make a new kind of thing, clone
an existing thing and change what differs. The clone
is immediately live.
This is how the physical world works. You start from
an example and vary it. The blueprint is a fiction.
In neo, the prototype is the first example, real,
inspectable, and modifiable, and every other instance
is a variation of it.
Security from the reference graph
To act on an object you must hold a reference to it.
References are unforgeable. There is no global namespace,
no ambient authority, and no root access that bypasses the object graph.
A process that starts with no references can do nothing,
not because anything checks, but because there is nothing it can reach.
Reflection is a capability: an object you must hold,
not a power every developer has by default.
This resolves the long-standing tension in live systems
where openness and security are treated as opposites.
In neo they are the same property; the reference graph enforces both.
Self-reproduction
A system is self-reproducing when it can describe itself
completely and reconstruct itself from that description.
neo achieves this at three levels.
The image serialises to text. That text, when evaluated,
reconstructs the exact image that produced it, including the serialiser.
The image is its own source code.
The prototype chain bottoms out at a fixed point: `Object`,
whose prototype is itself. From this fixed point the entire
object hierarchy is generated by cloning. The system contains
the description of the thing that generates it.
The running image holds a representation of the kernel
itself as objects. The image can modify those objects,
emit a new kernel, and restart into it while preserving the image.
The substrate is not fixed; it can be modified from within the system it hosts.
This is what von Neumann described in 1948 as a universal
constructor: a machine containing a complete description
of itself, capable of reproducing that description, and
capable of modifying the description before reproducing.
neo is a software realisation of that structure.
The prior tradition
Self contributed prototype delegation, uniform slots,
and the inline cache. Smalltalk contributed the live
image and message passing as the only operation.
Lisp contributed homoiconicity. None of them completed the synthesis.
Self had no homoiconicity. Smalltalk had classes, compiler primitives,
and a UI model that was not genuinely object-oriented.
Lisp had no objects at the ontological level; functions
are the primitive, not objects.
neo takes what each got right and refuses what each
got wrong. The per-object dimensional model is neo's
original contribution; no prior system gave dimensionality
to the object itself.
The prior tradition is the floor, not the ceiling.
o-expression: the reference syntax
neo has no canonical syntax. Surface representations
are external readers, objects that consume text and
produce graph fragments. Any reader that produces
the correct object graph is a valid neo reader.
The system ships with o-expression as its reference
syntax. o-expression is named by contrast with s-expression.
Where s-expressions are lists, sequences of symbols and nested lists,
o-expressions are objects containing objects. Every `(...)` is one object.
The `o` names that.
Every `(...)` is exactly one object. The first
token is the object's name. The remaining contents
are its child objects. Nesting is containment.
Three characters, nothing else:
> an object containing two children
(+ (21) (21))
> a nested object
(counter
(count (0))
(increment
(body (+ (count (self)) (1)))))
> control flow: if is an object with three children
(if
(> (x) (0))
(print (x))
(print (0)))
> a simulation body in 3D space
(body
(space (Euclidean3D))
(position (vec3 (x (0)) (y (0)) (z (0))))
(mass (1.0)))
> duplication
(counter (signal (copy)))