On this page:
describe
thing
send
thing?
is-a?
thing=?
Self
extends
inherit

3.10 Things

Things are Heresy’s definable data structures. Unlike the objects of most object-oriented languages, which often exist to hold and carry mutable state and actions with which to change that state, Things are immutable. A Thing, once sprung to life, cannot itself be altered, but can be called with the correct syntax to return a new Thing with different internal values for its internal data fields.

Things are essentially functions, lambdas specifically, with predefined syntax arguments. They are first class values, and can be passed freely just as any other data, but can also be passed arguments to either return the values of their fields, return a new Thing, or to employ any functions contained within the thing.

syntax

(describe Name)

(describe Name (field value) ...)
(describe Name extends super-thing (field value) ...)
(describe Name extends super-thing inherit (id ...) (field value) ...)
Defines a new type of Thing, given Name. By convention, Things are generally named in uppercase, though this is not required by the syntax. Each field is an internal name and external symbol, which is mapped to the given value. Anonymous functions (fn) can be assigned as values to Thing fields, and those functions can access the fields of the Thing by name.

If the extends option is provided, the new Thing extends super-thing, inheriting it’s fields and methods (unless they are overridden). If the inherit option is provided with it, then the ids are available as bindings within the method expressions.

syntax

(thing)

(thing (field value) ...)
(thing extends super-thing (field value) ...)
(thing extends super-thing inherit (id ...) (field value) ...)
Just like fn produces an anonymous function, thing produces an anonymous Thing.

If there is a Thing defined as Name:

(Name)

(Name symbol)
(Name 'fields)
(Name pattern)
Once a Thing has been described or bound to a name by other means, that Name is bound locally as a function, and can thus be called with special syntax to return its contents or to return a new copied Thing. In more detail, these syntaxes are as follows:

(Name)

Returns an association list containing the contents of the Thing, ie. a list in the form of: '((field value) ...)

(Name 'fields)

Returns a list of symbols for the fields contained within the Thing. Note that the symbol 'fields takes precedent over the field names within, in order to prevent overwriting this syntax.

(Name symbol)

Returns the value of the field associated with symbol, the quoted form of the field name described when the Thing type was first declared. Will return an error if no such named field is found. If the value associated with symbol is a function, this expression can be used as the operating function of a further expression like so:

Examples:
> (describe Lord-Cthulhu (eat (fn (x) (print (& "Devours " x)))))
> ((Lord-Cthulhu 'eat) "Dave")

Devours Dave

(Name pattern)

 
pattern = `(sub-pat ...)
     
sub-pat = *
  | value
Returns a copy of the Thing, with new values according to the pattern passed to the original Thing. pattern must be a quoted list of either '*s or values, in order according to the fields of the Thing as originally defined (so the first sub-pat matches the first field, the second to the second field, and so on). A '* in a field indicates that the value is copied in-tact, while a value becomes the new value of the field in that position. For example:

Examples:
> (describe Santa
            (size 'fat)
            (sleigh 'ready)
            (sack 'full))
> (def Santa-after-Christmas (Santa `(* * empty)))
> (Santa-after-Christmas)

'((size fat) (sleigh ready) (sack empty))

procedure

(send Thing symbol arg ...)  any

  Thing : thing?
  symbol : symbol?
  arg : any
An alternate syntax for accessing functions within Things, send calls the function named by (Thing symbol) with the given arguments and returns the result.

procedure

(thing? v)  boolean?

  v : any?
Returns True if v "looks like" a Thing, or False if it doesn’t. thing? employs a duck-typing method, checking the object for the expected properties of a Thing, so it is possible, albeit unlikely, to fool it. Specifically it checks first if v is a fn?, then checks the returns for the default internal methods of all Things, and its internal hash value.

procedure

(is-a? Type Thing)  boolean?

  Type : thing?
  Thing : thing?
Returns True if Thing is an instance of Type. This will return True if Thing is the same kind as Type, or if Thing is derived from Type, as by extends. This is done by comparing the internal '_ident field of Type to both the '_ident and '_parents fields of Thing.

procedure

(thing=? thing1 thing2)  boolean

  thing1 : thing?
  thing2 : thing?
Returns True if thing1 and thing2’s fields are equal? to each other, according to the internal hash values generated from their fields, after first checking that both things are the same type according to is-a?.

syntax

(Self ....)

Self is the self-referring identifier for a Thing, allowing for functions within Things to call the Thing itself. Note that if it is only the values of the other fields, this is not necessary, as fields are defined as local names within the context of the Thing, and thus can be referred to simply by name.

syntax

extends

can only be used within a describe or thing form.

syntax

inherit

can only be used within a describe or thing form.