Lichen

docs/wiki/Restarted

932:c07b0dd14f85
11 months ago Paul Boddie Moved integer instantiation support to library functions.
     1 = Lichen Restarted =     2      3 Originally, lots of work was being put in to support various Python features     4 that are arguably superfluous. The realisation was had that a lot of effort     5 was being made for little practical benefit by trying to support things that     6 are, [[../Design|in the larger picture]], not that important. Consequently,     7 Lichen was refocused on a smaller set of more useful Python features.     8      9 This document is of historical interest only, with the [[../Design|design]]    10 and other documents attempting to communicate the results of this restarting    11 effort. Some obsolete information is therefore preserved below. For example,    12 attributes hold context information in the diagrams, but context information    13 is now held in wrappers or is maintained separately within programs.    14     15 Objectives:    16     17  * Individual module inspection    18  * No importing triggered during module inspection    19  * All unresolved external references are set to `<depends>`    20  * Hierarchical module namespaces are not exposed in programs    21  * Modules are independent: package hierarchies are not traversed when    22    importing    23  * Nested scopes will be dropped    24  * If expressions and comprehensions will be dropped    25  * `self` is a reserved name and is optional in method parameter lists    26  * Unbound methods must be bound using a special function taking an instance    27  * Functions assigned to classes do not become unbound methods    28     29 == Names ==    30     31 Names are locals, globals or built-ins. (Special names exist internally to    32 support certain operations.)    33     34 Locals inside functions are dynamic; locals outside functions are static, as    35 are module globals. Built-ins are defined statically in the `__builtins__`    36 package.    37     38 == Imports ==    39     40 Imports provide access to external references. The "leaf" module in a module    41 path is the module returned by the statement.    42     43 Indicate that module "compiler" is accessed via compiler...    44     45 {{{#!python numbers=disable    46 import compiler    47 }}}    48     49 Indicate that module "compiler" is accessed via comp...    50     51 {{{#!python numbers=disable    52 import compiler as comp    53 }}}    54     55 Indicate that module "compiler.ast" is accessed via ast; module    56 "compiler.transformer" is accessed via tr...    57     58 {{{#!python numbers=disable    59 import compiler.ast as ast, compiler.transformer as tr    60 }}}    61     62 Import compiler.ast, access Function...    63     64 {{{#!python numbers=disable    65 from compiler.ast import Function    66 }}}    67     68 Import compiler.ast, access Function as F...    69     70 {{{#!python numbers=disable    71 from compiler.ast import Function as F    72 }}}    73     74 This causes some semantic differences with Python, with the most significant    75 one being the following:    76     77 {{{{#!table    78 '''Python''' || '''Lichen'''    79 ==    80 <style="vertical-align:top">    81     82 Import compiler, import compiler.ast, set ast on compiler...    83 {{{#!python numbers=disable    84 import compiler.ast    85 }}}    86 ...returning compiler    87     88 ||    89 <style="vertical-align:top">    90     91 Import compiler.ast...    92 {{{#!python numbers=disable    93 import compiler.ast    94 }}}    95 ...returning compiler.ast as ast    96     97 }}}}    98     99 Some statements can be rewritten to achieve the same effect:   100    101 {{{{#!table   102 '''Python''' || '''Lichen'''   103 ==   104 <style="vertical-align:top">   105    106 Import compiler, access ast as submodule...   107 {{{#!python numbers=disable   108 from compiler import ast   109 }}}   110    111 ||   112 <style="vertical-align:top">   113    114 Import compiler.ast...   115 {{{#!python numbers=disable   116 import compiler.ast   117 }}}   118 ...returning compiler.ast as ast   119    120 }}}}   121    122 Other kinds of import are not directly possible with Lichen. For example:   123    124 Import all names from compiler.ast...   125 {{{#!python numbers=disable   126 from compiler.ast import *   127 }}}   128    129 Some notes:   130    131  * Names not defined in a module and not declared in import statements are   132    unresolved   133  * Modules are identified during inspection but are not loaded   134  * Instead, modules are added to a list and are imported later   135  * Names imported from modules are set to `<depends>` (since the contents of   136    modules will not generally be known)   137  * Names are resolved in a later activity   138    139 == Self ==   140    141 In Python:   142    143  * The `self` name provides access to the instance associated with a method   144  * The instance is supplied by a "context", initialised when a method is   145    obtained from an instance (or through other attribute accesses)   146  * Upon invocation, any instance context must be assigned to the `self`   147    parameter, provided the callable is a method   148  * Meanwhile, any non-instance context is not assigned to the `self`   149    parameter, which should be provided explicitly for class-accessed methods   150  * Plain functions never expose `self` or have `self` initialised, even if   151    they have been assigned to an instance   152    153 Apart from tests for the nature of the context and the callable, the argument   154 list is effectively variable.   155    156 With `self` as a ubiquitous, hidden parameter:   157    158  * The `self` name still provides access to the instance associated with a   159    method   160  * The instance is still supplied by a "context", initialised when a method is   161    obtained from an instance (or through other attribute accesses)   162  * Upon invocation, `self` is included in the argument list regardless of the   163    nature of the callable   164  * Class-accessed methods would have their class as context, following from   165    the above, but `self` may not refer to a class: it must be an instance   166  * To combine class-accessed methods with instance contexts, a special   167    function is employed   168    169 The argument list for each callable thus remains static, at a cost of   170 allocating an extra argument that may not be used. (Various calling   171 conventions for certain processor architectures employ potentially unused   172 registers, anyway.) Note that a callable may support defaults, however, and   173 thus any argument list may need extending to include default values for   174 parameters without corresponding arguments.   175    176 {{{{#!table   177 '''Python''' || '''Without self'''   178 ==   179 <style="vertical-align:top">   180    181 {{{#!python numbers=disable   182 inst.method(x, y, z)   183 # -> inst.method(inst, x, y, z)   184    185 def method(self, a, b, c):   186     # self = inst; a = x; b = y; c = z   187 }}}   188    189 ||   190 <style="vertical-align:top">   191    192 {{{#!python numbers=disable   193 inst.method(x, y, z)   194 # -> inst.method(inst, x, y, z)   195    196 def method(a, b, c):   197     # self = inst; a = x; b = y; c = z   198 }}}   199    200 ==   201 <style="vertical-align:top">   202    203 {{{#!python numbers=disable   204 cls.method(self, x, y, z)   205    206 def method(self, a, b, c):   207     # parameters = arguments   208 }}}   209    210 ||   211 <style="vertical-align:top">   212    213 {{{#!python numbers=disable   214 f = get_using(cls.method, self)   215 # context of f = self; value of f = cls.method   216 f(x, y, z)   217 # -> f(context of f, x, y, z)   218    219 def method(a, b, c):   220     # self = context of f = self; a = x; b = y; c = z   221 }}}   222    223 }}}}   224    225 To avoid usage of `self` in undefined ways, only methods are able to use   226 `self` and are not allowed to redefine it. Consequently, when invoking a   227 callable, the context is set (where the callable is unknown until run-time; it   228 is not set if compile-time knowledge indicates that it is not needed), and in   229 situations where `self` is not permitted, the context is therefore safely   230 ignored. Meanwhile, methods are always supplied with a context compatible with   231 `self`.   232    233 || '''Callable''' || '''self''' || '''Remarks''' ||   234 || Class || context || context discarded and replaced by allocated instance ||   235 || Function || null || `self` not permitted, context ignored ||   236 || Function (stored on class) || class as context || `self` not permitted, context ignored ||   237 || Function (stored on instance) || instance as context || `self` not permitted, context ignored ||   238 || Instance || instance as context || `self` set to instance ||   239 || Method (via class) || class as context || method not called (see "unbound methods") ||   240 || Method (via instance) || instance as context || `self` set to instance ||   241    242 Note that the treatment of functions stored on classes differs from Python. In   243 Python, such functions would become unbound methods (see below) and would   244 employ their first parameter as an effective `self` parameter (regardless of   245 name).   246    247 == Unbound Methods ==   248    249 Since methods acquired directly from classes ("unbound methods" in Python) are   250 meant to be combined with an instance as context (using the `get_using`   251 function), they must be uncallable until combined with the appropriate   252 context, yet the same methods when acquired via instances ("bound methods" in   253 Python) must be immediately callable.   254    255 To support the two different states of methods, the principal structure of a   256 class has attributes referencing uncallable versions of its methods.   257 Meanwhile, such uncallable methods reference callable versions and when   258 instances are employed to access the class attributes, it is these callable   259 versions that are retrieved. For example:   260    261 {{{#!graphviz   262 //format=svg   263 //transform=notugly   264 digraph structures {   265   node [shape=box,fontsize="13.0",fontname="sans-serif",tooltip="Instance and class structures"];   266   edge [fontsize="13.0",fontname="sans-serif",tooltip="Instance and class structures"];   267   rankdir=TB;   268    269   instanceC [label="<main> instance of C |{ context of a | value of a }|{context of b | value of b }",shape=record];   270   classC [label="<main> class C |{ context of m | <m> value of m }|{ context of n | <n> value of n}",shape=record];   271   callables [label="<m> m\ncallable |<n> n\ncallable",shape=record];   272   uncallables [label="<m> m\nuncallable |<n> n\nuncallable",shape=record];   273    274   instanceC:main -> classC:main;   275   classC:m -> uncallables:m [label="C.m",style=dashed];   276   classC:n -> uncallables:n [label="C.n",style=dashed];   277   uncallables:m -> callables:m [label="get_using(C.m, instance)",style=dashed];   278   uncallables:n -> callables:n [label="get_using(C.n, instance)",style=dashed];   279 }   280 }}}   281    282 The precise structure usage is as follows:   283    284 {{{#!graphviz   285 //format=svg   286 //transform=notugly   287 digraph methods {   288   node [shape=box,fontsize="13.0",fontname="sans-serif",tooltip="Method structures"];   289   edge [fontsize="13.0",fontname="sans-serif",tooltip="Method structures"];   290   rankdir=TB;   291    292   classC [label="<main> class C | { context of m | <mvalue> uncallable for m } | ...",shape=record];   293   uncallableattr [label="attr | { <context> C | <value> uncallable for m }",shape=record];   294   callableattr [label="attr | { <context> instance | <value> callable for m }",shape=record];   295   uncallable [label="<main> uncallable for m |{ __fn__ | <b> bound method reference | <fn> unbound method routine }|{ __args__ | minimum #parameters | <ptable> parameter table reference }",shape=record];   296   callable [label="<main> callable for m |{ __fn__ | 0 | <fn> bound method routine }|{ __args__ | minimum #parameters | <ptable> parameter table reference }",shape=record];   297   ptable [label="<main> parameter table for m | ...",shape=record];   298    299   classC:mvalue -> uncallableattr [label="C.m",style=dashed];   300   classC:mvalue -> uncallable:main;   301   uncallableattr:value -> uncallable:main;   302   uncallableattr -> callableattr [label="get_using(C.m, instance)",style=dashed];   303   uncallable:b -> callable:main;   304   callableattr:value -> callable:main;   305   uncallable:ptable -> ptable:main;   306   callable:ptable -> ptable:main;   307 }   308 }}}   309    310 Callable methods provide a reference to a callable routine in its special   311 callable member, just as functions and classes do. Uncallable methods populate   312 the callable member with a reference to an error routine. Thus, any attempt to   313 call an uncallable method would cause the error routine to be invoked. In   314 addition, uncallable methods reference the corresponding callable methods so   315 that the callable methods can be found and referenced.   316    317 || '''Accessor''' || '''Provider''' || '''Attribute''' || '''Context''' || '''Summary''' ||   318 ||<|4> Instance ||<|4> Instance || Function || ''not used'' ||<|6> Preserve context ||   319 || Bound method || Original instance ||   320 || Unbound method || Providing class ||   321 || Other || Same as value ||   322 ||<|4> Instance ||<|4> Class || Function || ''not used'' ||   323 || Bound method || Original instance ||   324 || Unbound method || Accessing instance, if compatible || Test and replace context ||   325 || Other || Same as value ||<|5> Preserve context ||   326 ||<|4> Class ||<|4> Class || Function || ''not used'' ||   327 || Bound method || Original instance ||   328 || Unbound method || Providing class ||   329 || Other || Same as value ||   330    331 When obtaining an unbound method from an instance attribute, the context of   332 the method attribute is provided. Indeed, the context is always preserved when   333 accessing instance attributes.   334    335 When obtaining an unbound method from a class attribute via an instance, the   336 context of the method attribute is tested against the accessing instance. If   337 compatible, an attribute is copied containing the instance as context and a   338 callable method reference as value.   339    340 When obtaining an unbound method from a class attribute, the context of the   341 method attribute is provided. Indeed, the context is always preserved when   342 accessing class attributes directly.   343    344 When combining an unbound method obtained from a class with an instance using   345 `get_using`, the context of the method attribute is tested against the   346 supplied instance. If compatible, an attribute is copied containing the   347 instance as context and a callable method reference as value.   348    349 === Functions as Unbound Methods ===   350    351 Functions not defined within classes could be treated as unbound methods if   352 they were to employ `self` (thus indicating that they are intended as   353 methods). Such functions would then be recorded as uncallable in the module   354 namespace, needing to be explicitly bound to a class using a special function.   355 However, there appears to be limited utility in defining functions in this   356 way, instead of defining them directly as methods, or instead of merely using   357 such generic functions from existing methods.