Lichen

docs/wiki/Structure

932:c07b0dd14f85
11 months ago Paul Boddie Moved integer instantiation support to library functions.
     1 = Program Structure =     2      3 A program consists of a number of '''modules''' with each module providing its     4 own namespace. Modules can be organised within '''packages''' which define a     5 hierarchical relationship between them. However, the relationship between     6 modules is not automatically exposed within the program: it is more     7 appropriate to consider modules as independent entities that have a particular     8 naming scheme.     9     10 Within each module a hierarchy of namespaces is provided by '''classes''',    11 with each class potentially containing other classes, and so on. Also    12 appearing within modules and classes are '''functions''', with those appearing    13 within classes being regarded as '''methods'''.    14     15 Function namespaces are considered separately from module and class namespaces    16 and are not considered part of the general namespace hierarchy, instead merely    17 appearing as objects at the edges of that hierarchy. Functions may also be    18 defined within functions, and such inner functions will be referenced within    19 their parent functions, but no hierarchical relationship will exist between    20 their namespaces.    21     22 Thus, a program provides a static namespace hierarchy consisting of modules    23 containing classes (containing other classes, and so on) plus functions.    24 Objects residing within namespaces are accessed via '''attributes''' of those    25 namespaces.    26     27 {{{{#!table    28 {{{#!graphviz    29 //format=svg    30 //transform=notugly    31 digraph program {    32   node [shape=box,fontsize="13.0",fontname="sans-serif",tooltip="Program structure"];    33   edge [tooltip="Program structure"];    34   rankdir=LR;    35     36   program [label="program",shape=folder,style=filled,fillcolor=cyan];    37     38   subgraph {    39     rank=same;    40     moduleM [label="module M",style=filled,fillcolor=gold];    41     moduleN [label="module N\n(package)",style=filled,fillcolor=gold];    42   }    43     44   subgraph {    45     rank=same;    46     classA [label="class A"];    47     moduleNP [label="module N.P",style=filled,fillcolor=gold];    48   }    49     50   subgraph {    51     rank=same;    52     functionF [label="function f",shape=ellipse];    53     functionG [label="function g",shape=ellipse];    54     classB [label="class B"];    55     classC [label="class C"];    56   }    57     58   subgraph {    59     rank=same;    60     functionJ [label="function j",shape=ellipse];    61     functionH [label="function h",shape=ellipse];    62     functionK [label="function k",shape=ellipse];    63   }    64     65   program -> moduleM;    66   program -> moduleN;    67     68   moduleM -> classA;    69   moduleN -> moduleNP;    70   moduleNP -> classC;    71     72   classA -> functionF;    73   classA -> functionG;    74   classA -> classB;    75   classB -> functionH;    76   classC -> functionK;    77     78   functionG -> functionJ [style=dashed];    79 }    80 }}}    81 ||    82 {{{#!python numbers=disable    83 # module M    84     85 class A:    86     def f(...): pass    87     88     def g(...):    89         def j(...): pass    90     91     class B:    92         def h(...): pass    93     94 # module N    95     96 ...    97     98 # module N.P    99    100 class C:   101     def k(...): pass   102 }}}   103 }}}}   104    105 == Referencing the Structure ==   106    107 Each part of the structure is catalogued using an '''object path''',   108 indicating its location in the structure hierarchy, and a reference indicating   109 its nature and origin. For example:   110    111 || '''Object Path''' || '''Reference''' || '''Explanation''' ||   112 || `M.A` || `<class>:M.A` || The definition of class `A` in module `M` ||   113 || `O.A` || `<class>:M.A` || A reference to `M.A`, a class ||   114 || `N.P.C.k` || `<function>:N.P.C.k` || The definition of method `k` in class `C` of module `N.P` ||   115 || `O.k` || `<function>:N.P.C.k` || A reference to `N.P.C.k`, a function ||   116 || `O.values` || `<instance>:__builtins__.list.list` || An object identified as an instance of class `__builtins__.list.list` ||   117 || `__main__.M` || `<module>:M` || A reference to module `M` ||   118 || `__main__.counter` || `<var>` || An undetermined object called `counter` in the `__main__` module ||   119    120 The reference therefore expresses the '''kind''' of object (class, function,   121 instance, module or undetermined variable), possibly accompanied by an object   122 type, and also possibly accompanied by an alias indicating where the reference   123 was obtained.   124    125 == Classes ==   126    127 Classes are regarded as statically-defined objects, meaning that they are only   128 evaluated once and must not be defined within conditional sections or within   129 functions. Base classes must be expressed using readily-identifiable class   130 names, since any potential ambiguity or uncertainty with the identity of base   131 classes could result in a class inheritance hierarchy that is effectively   132 dynamic.   133    134 When '''instantiated''', classes provide '''instances''' that provide the   135 attributes of each class's namespace plus any '''inherited''' attributes from   136 base classes that would not be provided by the class itself. In addition,   137 instances provide their own instance attributes.   138    139 == Functions ==   140    141 Functions are regarded as statically-defined objects, but they may be defined   142 either with names within other named functions or as '''lambdas''' (functions   143 without names) within named functions or other lambdas. Thus, unlike classes,   144 functions may be defined once but replicated many times, each time with   145 different accompanying state information. Such state information needs to be   146 provided via default parameters: it is not detected and propagated   147 automatically. Closures are not supported: any state from enclosing scopes   148 must be supplied at the point of definition of a function; it is not acquired   149 from outer functions by name.   150    151 {{{#!python numbers=disable   152 def outer(a):   153     b = 2   154     def inner(c, a=a, b=b):   155         # a initialised using default from outer scope   156         # b also initialised using default from outer scope   157         return a, b, c   158     b = 4   159    160 outer(1)(3) # returns (1, 2, 3) not (1, 4, 3)   161 }}}   162    163 === Lambdas ===   164    165 Lambdas are given special names for the purposes of identification within the   166 program structure, being named relative to the scope in which they are   167 defined. For example, the first lambda appearing within module `N` would have   168 an object path of `N.$l0`, and a subsequent lambda within the same scope would   169 have an object path of `N.$l1`. Lambdas may appear within classes and   170 functions, including lambdas themselves. For example:   171    172 {{{#!python numbers=disable   173 def f(x):   174     return lambda y, x=x: lambda z, x=x, y=y: (x, y, z)   175 }}}   176    177 Here, within a module `M`, the outer lambda would have the object path   178 `M.f.$l0` whereas the inner lambda would have the object path `M.f.$l0.$l0`.