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.