# _Muddling_ for Lispers and Schemers This is an overview of the key differences between Muddle and other lispy languages. Good Muddle is easy for humans to read, but it is also tasteful: it efficiently matches the operation of the program to the operation of the Muddle interpreter. Each semantic note is followed by a review of the performance implications. ## Objects Muddle code deals exclusively with Muddle _objects_. Objects are always passed by value. An object can be a _scalar_ (e.g. `FIX`), with its value stored directly inside it, or a _collection_ (e.g. `LIST`, `VECTOR`, `TEMPLATE`), holding a reference to external data. Copying a collection object yields a new object that refers to the same collection _body_, but the object itself can have metadata that isn't shared -- like a `VECTOR`'s current length (see below). ### Performance An object is bigger than a pointer, but smaller enough to copy around easily. Every object is tagged with a type, so dispatching on types never requires following references. Collection bodies are allocated in heaplike spaces and managed by a tracing GC; copying references has no special overhead, but there is a write barrier when modifying objects stored in collections. ## Calls A `FUNCTION` or `FSUBR` may not evaluate all of its arguments; as a result, the normal call process of evaluating arguments before passing them to the callee is not practical. Arguments are passed unevaluated, and may then be evaluated by the callee (usually implicitly, based on its argument declarations). The main programmer-visible consequences of this are: * there are no "special forms"; first-class `FUNCTION`s can operate on syntax at runtime (and even modify it) * arguments are evaluated in a deterministic sequence (left-to-right is the default, but the callee can do anything; adhering to the Principle of Least Astonishment is recommended) * stack traces show arguments evaluated in the callee's frame ### Performance The by-name calling strategy combined with the ability to redefine any global allow incredible flexibility for debugging, but neither feature is recommended to be used widely in production. Accordingly, while the functionality is always available to interpreted programs, performance of code that doesn't use such dynamism is the implementation priority; certain unusual operations, like replacing an applicable function with a `"CALL"` function, may carry a high runtime cost. ## Scope Scoping is dynamic by default. You can create nested bindings to keep variables relatively local, e.g. with `"AUX"` pseudo-arguments. You can also create a full lexical scope with `BLOCK`. ## `LIST` Unlike other lisps that implement their "lists" with binary trees, Muddle's `LIST`s are intrusive singly-linked lists: the value is not behind a pointer like a "car", and *every* object has a `REST` field. Lists can share tails, but no object can otherwise be an element of more than one list, or in a list and also anywhere else. Cyclic or self-containing lists are possible, and must be handled with care. ### Performance `LIST`s can be very efficient for true lists (including lists of objects that may be `LIST`s, like Muddle code itself). The GC handles them specially in order to store objects next to their `REST`s whenever possible. To get efficient allocations, help the GC predict what you want by building your list idiomatically: * LIFO order (fastest): consecutive `CONS`es to one list * FIFO order (slow): `PUTREST` 1-element lists * fixed-size: `` (including `MAPF ,LIST`), but if you expect to extend it right away, you should build it with `CONS` or `PUTREST` ## `VECTOR` Muddle's `VECTOR` is an array-structured container of objects. Like similar types in other languages, it supports efficient random access and expensive resizing to a larger allocation. More unusually, it has stack-like behavior: each `VECTOR` object maintains a current length that is less than or equal to the allocated length of its body. The length can be decreased with `REST` or increased (to at most the body's actual size) with `BACK` / `TOP`, which make objects accessible again, with their original values. Because all of its allocated objects are reachable with `TOP` (or potentially through a different `VECTOR` to the same body), its full allocation is always composed of initialized, live objects (although those objects can be `LOSE`s). ### Performance Choose a `VECTOR` if you want random access, or the stacklike features. `REST` is non-destructive; if you won't be using the objects again, overwriting them with `LOSE`s will allow the GC to free anything they refer to. ## User-defined data types A common idiom for user-defined data types in Muddle is to use a type with a `TYPEPRIM` of `VECTOR`, and use `ATOM`s that resolve to `FIX`es as accessors. ## Control flow [coroutines, continuations, ...] There is no TCE for normal calls, but `AGAIN` resembles a self-tailcall. ## Misc Reference semantics can be had by indirecting through a collection. If you need to accept a value by reference without knowing what kind of collection it's in, you want a `LOCATIVE`. # License Copyright (C) 2018 Keziah Wesley You can redistribute and/or modify this file under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this file. If not, see .