Vixen

From Esolang
Jump to navigation Jump to search
This is still a work in progress. It may be changed in the future.
Vixen
Designed by User:Corbin
Appeared in 2025
Computational class Turing-complete
Reference implementation included in this article!
Influenced by Cello, COLA, Dylan, E, Erlang, execline, Monte, Nix, s6, Self, Smalltix, zope.interface

Vixen is a calling convention for Unix systems which idealizes directories as objects. It is similar to Smalltix[1] but reifies objects as clonable prototypes as in Self[2] or COLA languages like Pepsi[3].

The name "Vixen" is a pun on "VAXen" as the plural of wikipedia:VAX, with "-en" both meaning "more than one machine" and also short for "E" and "Nix", the two main innovations included since Smalltalk and Unix.

Objects

The Vixen connection is similar to Smalltix but does not have classes. There is only one sort of object, the directory. A directory's entries each represent a slot with the name of the entry providing the verb for that slot. If an entry is executable then it is a method. There is only one calling convention; to call method $METH on object $OBJ with arguments $@, execute:

$OBJ/$METH $OBJ $@

Delegation is achieved via symlinks. Inheritance is achieved by symlinking one directory to the "parent" entry of another; during message delivery, if there is no slot corresponding to the called selector but there is a "parent" entry then the message will be delivered to the parent method on behalf of the child object. That is, suppose that our previous example is extended with a symlink to a parent object $PAR, and further suppose that the selector is not present in $OBJ but it is present in $PAR. Then we execute:

$PAR/$METH $OBJ $@

Core

The core of Vixen is reproduced here using execline. Let $V be some directory. To animate it, we need a method for calling methods on objects. It needs to discern whether a slot denotes a method by checking whether it is executable. The following method $V/call: will work:

#!/usr/bin/env -S execlineb -s2
importas -iS V
backtick -I -E method { ${V}/lookup: $1 $2 }
ifte {
    ifte { $method $1 $@ } { cat $method }
    eltest -x $method
} { exit 1 }
eltest $? -eq 0

This method must delegate the actual lookup of the method on the recipient. This lookup method needs to be recursive so that it can walk the parents. The following method $V/lookup: will work:

#!/usr/bin/env -S execlineb -s2
ifte { echo "${1}/${2}" } {
    ifte { $0 "${1}/parent" $2 } { exit 1 }
    eltest -e "${1}/parent"
}
eltest -e "${1}/${2}"

The interested reader should start their journey by adding printing for objects, messages, and errors.

Cloning

As in Self, the fundamental unit of object creation is invocation of clone: methods; once cloned, an object can be customized by standard Unix techniques. To address the concerns of Kell[4] and Jakubovic about allocation, let $Alloc be a directory which we idealize as an object and will pass to clone: as a parameter. First, assuming that we have already written a method $Alloc/allocate which allocates a new object, we initialize that object by creating a "parent" symlink within it. The following method $V/clone: will work:

#!/usr/bin/env -S execlineb -s2
importas -iS V
backtick -E obj { ${V}/call: $2 allocate }
backtick -E target { realpath $1 }
foreground { ln -s $target "${obj}/parent" }
echo $obj

Let $Alloc/base name a reasonable temporary directory, perhaps $TMPDIR, which will be the base directory where allocated objects are located. The following method $Alloc/allocate will work:

#!/usr/bin/env -S execlineb -S1
importas -iS V
backtick -E basePath { ${V}/lookup: $1 base }
backtick -E base { cat $basePath }
mktemp -d -p $base obj.XXXXX

Asynchrony

As in E, a message can either be delivered in the foreground or the background. The execline background command is sufficient to implement the functionality, although we will want to reify the background process as its own object. First, the following method $V/send: will work:

#!/usr/bin/env -S execlineb -s0
importas -iS V
importas -iS Process
background { ${V}/call: $@ }
importas -iu pid !
${V}/call: $Process fromPID: $pid

This method relies on an auxiliary $Process object which represents a Unix process by PID. The simplest object which will work is a clone of $V which has a slot $Process/allocator referring to an allocator like $Alloc from the previous section. On top of such an object, the following method $Process/fromPID: will work:

#!/usr/bin/env -S execlineb -s2
importas -iS V
backtick -E allocator { ${V}/call: ${1} allocator }
backtick -E obj { ${V}/call: $1 clone: $allocator }
foreground { echo $obj }
redirfd -w -n 1 ${obj}/pid
echo $2

Complexity class

Vixen orchestrates Turing-complete components and as such is also Turing-complete. In particular, it is immediate from folklore of pointer-chasing and symlinks that:

Theorem (Undecidability of Halting for Vixen). It is undecidable whether a Unix system interpreted as a Vixen object graph will respond to a given message.

Similarly, we cannot know whether a component will ever perform an arbitrary effect at an arbitrary point.

Theorem (Undecidability of Printing for Vixen). It is undecidable whether delivering a single message to a Vixen object graph will produce any output.

References

  1. J. Jakubovic, 2025. The Unix executable as a Smalltalk method. Onward! 2025. https://programmingmadecomplicated.wordpress.com/wp-content/uploads/2025/10/onward25-jakubovic.pdf
  2. D. Ungar & R. B. Smith, 1987. Self: the power of simplicity. OOPSLA 87, 1987. Lisp and Symbolic Computation, 4, 3, 1991. https://bibliography.selflanguage.org/_static/self-power.pdf
  3. I. Piumarta, 2006. Pepsi: not quite the real thing. https://www.piumarta.com/software/cola/idst-20070918/doc/pepsi.html.in
  4. S. Kell, 2015. Towards a dynamic object model within Unix processes. Onward! 2015. https://dl.acm.org/doi/10.1145/2814228.2814238