Lichen

Annotated docs/wiki/Representations

868:d2c64260113c
2019-01-24 Paul Boddie Fixed loop termination by using a dedicated exception instead of StopIteration.
paul@810 1
= Representing Program Objects =
paul@810 2
paul@861 3
Certain representations have been chosen for program objects that attempt to
paul@861 4
support efficient access to those objects during the execution of a program.
paul@810 5
paul@810 6
<<TableOfContents(2,2)>>
paul@810 7
paul@810 8
== Attributes ==
paul@810 9
paul@861 10
The principal means of referring to an object in a program is by using an
paul@861 11
'''attribute''', having this name because it is the representation of an
paul@861 12
attribute in classes, instances and modules. Each attribute can hold a
paul@861 13
reference to an object, known as the '''value''', or other kinds of data:
paul@810 14
paul@810 15
{{{#!graphviz
paul@810 16
//format=svg
paul@810 17
//transform=notugly
paul@810 18
digraph attributes {
paul@810 19
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Attributes"];
paul@810 20
  edge [fontsize="13.0",fontname="Helvetica",tooltip="Attributes"];
paul@810 21
  rankdir=TB;
paul@810 22
paul@810 23
  attrA [label="attribute | { value |<value> reference to object }",shape=record];
paul@810 24
  obj1 [label="<main> object | { attr1 | value } | { attr2 | value } | ...",shape=record];
paul@810 25
paul@810 26
  attrB [label="attribute | { intvalue |<intvalue> 12345 }",shape=record];
paul@810 27
paul@810 28
  attrA:value -> obj1:main;
paul@810 29
}
paul@810 30
}}}
paul@810 31
paul@861 32
Although a value indicates a specific object of interest for an attribute, if
paul@861 33
the object is callable then additional '''context''' information may be
paul@861 34
required to call the object. Such context information is not stored in an
paul@861 35
attribute record but is instead obtained from the object itself, if
paul@861 36
appropriate.
paul@810 37
paul@810 38
=== Integer Representation ===
paul@810 39
paul@861 40
The `intvalue` member of the attribute structure is employed instead of the
paul@861 41
`value` member to store integer values. Since `value` normally holds a
paul@861 42
pointer, and since pointers are often aligned to certain address boundaries on
paul@861 43
many modern platforms (usually four-byte boundaries on 32-bit platforms,
paul@861 44
eight-byte boundaries on 64-bit platforms, two-byte boundaries on platforms
paul@861 45
with 16-bit addressing), the lowest significant bit (bit 0) will typically be
paul@861 46
zero for a valid pointer. Consequently, by setting bit 0 to 1, other data can
paul@861 47
be stored in the remaining bits and be distinguished from pointer information.
paul@861 48
Obviously, operations on attributes first need to test whether the `value`
paul@861 49
member or the `intvalue` member is in use by testing bit 0.
paul@810 50
paul@861 51
Thus, integers are transformed and stored directly within attributes, and they
paul@861 52
are therefore passed around by value. When an attribute of an integer needs to
paul@861 53
be accessed, the operation usually providing the `value` member, thus
paul@861 54
obtaining an instance under normal circumstances, instead provides the address
paul@861 55
of a common integer instance. This instance may then provide instance
paul@861 56
attributes, whose values will be the same for all integers, or class
paul@861 57
attributes through a reference to the integer (`int`) class.
paul@810 58
paul@861 59
Each method provided by `int`, when called, will be given the original
paul@861 60
attribute for which the method was obtained as its context. In such methods,
paul@861 61
operations on the context via `self` will either involve the propagation of
paul@861 62
the attribute to other functions or methods or attribute accesses on `self`,
paul@861 63
yielding common instance attributes or class attributes as already described.
paul@861 64
Only native functions will attempt to interpret the attribute in a different
paul@861 65
way, decoding the representation, performing arithmetic or logical operations,
paul@861 66
and encoding the result in a new attribute.
paul@810 67
paul@810 68
== Contexts and Wrappers ==
paul@810 69
paul@861 70
The context of an object is of significance if that object is callable. For
paul@861 71
example, an instance may permit access to a method via an attribute. Since the
paul@861 72
method will be callable, and since the method is accessed via the instance,
paul@861 73
the context of that method will be the instance. In order to retain both
paul@861 74
context and value information, a '''wrapper''' may be created.
paul@810 75
paul@810 76
{{{#!graphviz
paul@810 77
//format=svg
paul@810 78
//transform=notugly
paul@810 79
digraph wrappers {
paul@810 80
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Wrappers"];
paul@810 81
  edge [fontsize="13.0",fontname="Helvetica",tooltip="Wrappers"];
paul@810 82
  rankdir=TB;
paul@810 83
paul@810 84
  inst [label="<main> instance | { attr1 |<attr1> reference to method } | { attr2 | value } | ...",shape=record];
paul@810 85
  method [label="<main> method | ...",shape=record];
paul@810 86
  wrapper [label="<main> wrapper | { __context__ |<context> reference to instance } | { __value__ |<value> reference to method } | ...",shape=record];
paul@810 87
paul@810 88
  inst:attr1 -> method:main;
paul@810 89
  wrapper:context -> inst:main;
paul@810 90
  wrapper:value -> method:main;
paul@810 91
}
paul@810 92
}}}
paul@810 93
paul@861 94
The context is not always the accessor of the object - in this case, the
paul@861 95
instance - because the object may already be a wrapper with its own context.
paul@810 96
paul@810 97
== Objects ==
paul@810 98
paul@861 99
Classes, instances and modules are objects, and all of these kinds of objects
paul@861 100
provide metadata describing the type of each object, together with a
paul@861 101
collection of attributes forming the contents of such objects.
paul@810 102
paul@810 103
{{{#!graphviz
paul@810 104
//format=svg
paul@810 105
//transform=notugly
paul@810 106
digraph objects {
paul@810 107
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Objects"];
paul@810 108
  edge [fontsize="13.0",fontname="Helvetica",tooltip="Objects"];
paul@810 109
  rankdir=TB;
paul@810 110
paul@810 111
  instC [label="<main> instance of C | { 0 | reference to\ninstance table } | { __class__ |<cls> reference\nto C } | { a | value } | { b | value } | ...",shape=record];
paul@810 112
  clsC [label="<main> class C | { class identifier | reference to\nclass table } | { __class__ |<cls> reference\nto type } | { __fn__ | instantiator\nreference } | { __args__ | reference to\nparameter table } | { f | <f> reference\nto f } | { g | value } | ...",shape=record];
paul@810 113
  methodF [label="<main> function f | { 0 | reference to\ninstance table } | { __class__ |<cls> reference\nto function } | { __fn__ | method\nreference } | { __args__ | reference to\nparameter table } | ...",shape=record];
paul@810 114
  function [label="<main> class function | { class identifier | reference to\nclass table } | { __class__ |<cls> reference\nto type } | ...",shape=record];
paul@810 115
  type [label="<main> class type | { class identifier | reference to\nclass table } | { __class__ |<cls> reference\nto type } | ...",shape=record];
paul@810 116
paul@810 117
  instC:cls -> clsC:main;
paul@810 118
  clsC:cls -> type:main;
paul@810 119
  clsC:f -> methodF:main;
paul@810 120
  methodF:cls -> function:main;
paul@810 121
}
paul@810 122
}}}
paul@810 123
paul@861 124
Classes are represented by structures whose members reference class attributes
paul@861 125
and class metadata (the class table), as well as incorporating invocation
paul@861 126
metadata (the `__args__` and `__fn__` special attributes).
paul@810 127
paul@861 128
Instances are represented by structures whose members reference instance
paul@861 129
attributes (including `__class__` which indicates the class instantiated by a
paul@861 130
given instance) and instance metadata (the instance table), as well as
paul@861 131
incorporating invocation metadata (the `__args__` and `__fn__` special
paul@861 132
attributes).
paul@810 133
paul@861 134
Functions are instances of a general function type that does not permit
paul@861 135
additional, general instance attributes. However, function instance structures
paul@861 136
may have extra members corresponding to default parameter values. Access to
paul@861 137
such extra members is performed using the minimum and maximum values provided
paul@861 138
via `__args__` and with knowledge of the number of declared instance
paul@861 139
attributes indicated by the instance table for the function type.
paul@810 140
paul@861 141
Modules are represented by structures whose members reference module
paul@861 142
attributes and module metadata (the module table).
paul@810 143
paul@810 144
== Special Members ==
paul@810 145
paul@861 146
All object representations support the following special members describing
paul@861 147
the invocation properties of each object:
paul@810 148
paul@810 149
{{{#!table
paul@861 150
`__args__` || the minimum number of arguments supported in an invocation and a
paul@861 151
           .. reference to the parameter table for the object
paul@810 152
==
paul@861 153
`__fn__` || a reference to a native function containing the actual code run
paul@861 154
         .. when calling the object
paul@810 155
}}}
paul@810 156
paul@861 157
Classes are invoked in order to create instances of each class
paul@861 158
('''instantiation'''). Instances may support invocation by providing a
paul@861 159
`__call__` method. Functions are supported by instances of a general function
paul@861 160
class. Modules are generally not callable and will not actually provide these
paul@861 161
special members in practice.
paul@810 162
paul@810 163
All object representations support information about their type:
paul@810 164
paul@810 165
{{{#!table
paul@810 166
`__class__`
paul@861 167
|| the class of the object: instances refer to their classes, classes refer to
paul@861 168
.. the `type` class, functions are instances that refer to the `function`
paul@861 169
.. class, modules refer to the `module` class
paul@810 170
}}}
paul@810 171
paul@810 172
Certain kinds of object support other descriptive attributes:
paul@810 173
paul@810 174
{{{#!table
paul@810 175
`__name__` || the name of a class or a function
paul@810 176
==
paul@810 177
`__parent__` || the parent scope of a class or a function
paul@810 178
}}}
paul@810 179
paul@861 180
Objects supported by native, system-level functionality require a means of
paul@861 181
retaining information in special attributes:
paul@810 182
paul@810 183
{{{#!table
paul@810 184
`__data__` || private data manipulated at the native level
paul@810 185
}}}
paul@810 186
paul@861 187
Strings support special annotation attributes that permit their use in
paul@861 188
dynamically resolving attributes:
paul@810 189
paul@810 190
{{{#!table
paul@861 191
`__key__` || the code and position of the attribute whose name is represented
paul@861 192
          .. by the string
paul@810 193
}}}
paul@810 194
paul@861 195
Such "key" attributes provide information that can be used to inspect an
paul@861 196
object table and to test for the presence of an attribute. With such
paul@861 197
information, the `getattr` and `hasattr` functions can be supported.
paul@810 198
paul@810 199
== Attribute Tables ==
paul@810 200
paul@861 201
In order to provide information about the attributes supported by each object,
paul@861 202
the structure of each object will reference a table containing entries
paul@861 203
describing these supported attributes. The size of this table is declared
paul@861 204
within the table structure, and for each position in the table an entry
paul@861 205
corresponding to the same position within an actual object structure describes
paul@861 206
the nature of the attribute at that position.
paul@810 207
paul@810 208
== Parameter Tables ==
paul@810 209
paul@861 210
In order to support argument validation and keyword arguments in invocations,
paul@861 211
a structure is referenced by `__args__` that indicates...
paul@810 212
paul@810 213
 * The minimum number of parameters supported by a callable
paul@810 214
 * The maximum number of parameters supported by a callable
paul@810 215
 * The size of the table describing the parameters
paul@861 216
 * A table of entries with each entry indicating the nature of a parameter (in
paul@861 217
   effect, which name it uses, albeit as a generated code instead of a string)
paul@861 218
   and the position of the parameter in any argument list prepared for an
paul@861 219
   invocation
paul@810 220
paul@861 221
Parameter tables only need to be consulted at run-time if the nature of a
paul@861 222
callable is undetermined. By supporting a uniform interface, the arguments
paul@861 223
used in an invocation can be tested against the description provided by
paul@861 224
`__args__` and the table.