micropython

docs/invocation.txt

257:9e7cd9146ed3
2009-09-04 Paul Boddie Added document descriptions.
     1 Invocations in classic Python:
     2 
     3   f(1, 2, 3)      # positional
     4   f(1, 2)         # positional with defaults
     5   f(1, 2, c=3)    # keywords
     6   f(1, c=3)       # keywords with defaults
     7   f(1, 2, 3, 4)   # extra positional arguments
     8   f(1, 2, 3, d=4) # extra keyword arguments
     9   f(1, 2, *args)  # positional bundles (possibly with defaults)
    10   f(1, 2, **kw)   # keyword bundles (possibly with defaults)
    11 
    12   Note that f is never fixed before run-time in Python.
    13 
    14 Comparison to invocations in C:
    15 
    16   f(1, 2, 3)      # positional, f known at compile-time
    17   f(1, 2, 3)      # positional, f is appropriate function pointer
    18                   # ie. (*f)(A, B, C)
    19 
    20 Least expensive cases (positional plus defaults):
    21 
    22   f(1, 2, 3)      # put arguments in frame
    23                   # if f is not known, add arguments vs. parameters check
    24   f(1, 2)         # to handle defaults, introduce default "filling" where
    25                   # not enough arguments are given
    26                   # if f is not known, this is obviously done at run-time
    27 
    28 More expensive cases (keywords plus defaults):
    29 
    30   f(1, 2, c=3)    # prepare frame using parameter details
    31                   # (provided c is a known parameter)
    32                   # if f is not known, this is obviously done at run-time
    33   f(1, c=3)       # as with the previous case, with default "filling" done
    34                   # where not enough arguments are given
    35                   # if f is not known, this is obviously done at run-time
    36                   # but with all defaults copied in before keywords are
    37                   # assigned (since their positions and thus the positions
    38                   # of missing parameters cannot be known)
    39 
    40 Awkward cases (extra arguments):
    41 
    42   f(1, 2, 3, 4)   # put arguments in frame
    43                   # if f is not known, add arguments vs. parameters check;
    44                   # to handle superfluous arguments, make a suitable object
    45                   # and fill it with all such arguments
    46 
    47 Very awkward cases:
    48 
    49   f(1, 2, 3, d=4) # extra keyword arguments
    50   f(1, 2, *args)  # positional bundles (possibly with defaults)
    51   f(1, 2, **kw)   # keyword bundles (possibly with defaults)
    52 
    53   These cases require additional structures to be created, potentially at
    54   run-time.
    55 
    56 Methods vs. functions:
    57 
    58   f(obj, 1, 2)    # f known as function at compile-time:
    59                   #   f(obj, 1, 2)
    60                   # f known as C.m at compile-time:
    61                   #   m(obj "assert isinstance(obj, C)", 1, 2)
    62                   # f not known at compile-time:
    63                   #   f(<context>, obj, 1, 2) for instance-accessed methods
    64                   #   f(obj, 1, 2) for class-accessed methods
    65                   #   f(obj, 1, 2) for functions
    66 
    67   (Could either have universal context usage even for functions, which would
    68    ignore them, or attempt to remove contexts when functions are called.)
    69 
    70 Argument lists for functions:
    71 
    72   f(obj, 1, 2)    # f known as function at compile-time
    73 
    74     f   -> f (context is null)
    75     obj -> argument #1
    76     1   -> argument #2
    77     2   -> argument #3
    78 
    79 Argument lists for methods:
    80 
    81   f(obj, 1, 2)    # f known as C.m at compile-time (context is C)
    82 
    83     f   -> C.m (context is class C)
    84     obj -> argument #1 (must be tested against the context)
    85     1   -> argument #2
    86     2   -> argument #3
    87 
    88 Argument lists for methods:
    89 
    90   f(obj, 1, 2)    # f known as C.m at compile-time (context is an instance)
    91 
    92     f   -> C.m
    93         -> context is argument #1
    94     obj -> argument #2
    95     1   -> argument #3
    96     2   -> argument #4
    97 
    98 Argument lists for classes:
    99 
   100   f(obj, 1, 2)    # f known as C at compile-time
   101 
   102     f   -> instantiator of C
   103         -> (argument #1 reserved for a new instance made by the instantiator)
   104     obj -> argument #2
   105     1   -> argument #3
   106     2   -> argument #4
   107 
   108   The new instance must be provided as the result of the call.
   109 
   110 Argument lists for unknown callables:
   111 
   112   f(obj, 1, 2)    # f not known at compile-time
   113 
   114     f   -> f
   115         -> load context for argument #1
   116     obj -> argument #2
   117     1   -> argument #3
   118     2   -> argument #4
   119 
   120   Then, check the context and shift the frame if necessary:
   121 
   122     f is class: no change
   123 
   124     <context> is class:
   125       (<context>, obj, 1, 2) -> (obj, 1, 2)
   126 
   127     <context> is instance: no change
   128 
   129 Argument lists in instantiators:
   130 
   131   f(obj, 1, 2)    # f not known at compile-time
   132 
   133     f   -> C.__new__ (known and called at run-time)
   134         -> load context for argument #1
   135     obj -> argument #2
   136     1   -> argument #3
   137     2   -> argument #4
   138 
   139   Need to call C.__init__(<instance>, obj, 1, 2), preferably with the existing
   140   frame:
   141 
   142     *** -> instance overwrites argument #1
   143     obj -> argument #2
   144     1   -> argument #3
   145     2   -> argument #4
   146 
   147   Then jump without switching frames.
   148 
   149 Defaults for unknown callables:
   150 
   151   f(obj)          # f not known at compile-time
   152 
   153     f   -> f
   154         -> load context for argument #1
   155     obj -> argument #2
   156 
   157   Then, check the number of arguments and the availability of defaults against
   158   the details provided by the callable's structure.
   159 
   160 Checking defaults for unknown callables:
   161 
   162   Approach #1 - pre-fill defaults, add arguments, check frame
   163 
   164   Approach #2 - add arguments, add defaults while checking frame
   165 
   166 Defaults for lambda functions:
   167 
   168   f = lambda x, y=default: ...
   169 
   170   Defines instance of f with method:
   171 
   172     def <lambda>(<context>, x, y=default):
   173       ...
   174 
   175   Where default is attribute #1.
   176 
   177   f(obj)          # f not known at compile-time
   178 
   179     f   -> f
   180         -> load context for argument #1 (f, since an instance is referenced)
   181     obj -> argument #2
   182 
   183 Functions as methods:
   184 
   185   def f(x, y, z): ...
   186   class C:
   187       m = f
   188   c = C()
   189   ...
   190   f(obj, 1, 2)    # no restrictions on obj
   191   obj.m(1, 2)     # f(obj, 1, 2)
   192   C.m(obj, 1, 2)  # f(obj "assert isinstance(obj, C)", 1, 2)
   193 
   194 Context propagation:
   195 
   196   fn = C.m        # has context C
   197   fn(obj, 1, 2)   # non-instance context -> explicit context required
   198                   # must perform isinstance(obj, C)
   199   fn = c.m        # table entry for m on C -> replace context
   200                   # gives context c
   201   fn(1, 2)        # instance context -> no explicit context required
   202                   # context c inserted in call
   203 
   204 Star parameters are a convenience:
   205 
   206   max(1, 2, 3)    # call to max(*args) where args == (1, 2, 3)
   207   max((1, 2, 3))  # but why not just do this instead?
   208 
   209   One motivation: avoid explicitly making sequences.
   210   Opportunity: avoid expensive dynamic allocation of sequences?
   211 
   212 Star parameters, approach #1:
   213 
   214   Make a sequence to hold the extra arguments, either in the caller for known
   215   callables or in the function itself.
   216 
   217   Such a sequence would need allocating and its contents copying from the
   218   stack.
   219 
   220 Star parameters, approach #2:
   221 
   222   Keep the extra arguments in the stack.
   223 
   224   Access to the star parameter would need to consider assignment to other
   225   things and "escape situations" for the parameter:
   226 
   227     def f(*args):
   228         return args # need to allocate and return the sequence
   229 
   230   Access to elements of the extra argument sequence would behave slightly
   231   differently to normal sequences, but this could be identified at
   232   compile-time.
   233 
   234 Star parameters, known callables and sequences, approach #1:
   235 
   236   g(1, 2, 3, 4)   # g known as function g(a, *args) at compile-time
   237 
   238     g   -> don't get any context information
   239     1   -> argument #1
   240     2   -> reference to sequence containing arguments #2, #3, #4
   241 
   242 Star parameters, known callables and sequences, approach #2:
   243 
   244   g(1, 2, 3, 4)   # g known as function g(a, *args) at compile-time
   245 
   246     g   -> don't get any context information
   247     1   -> argument #1
   248     2   -> argument #2
   249     3   -> argument #3
   250     4   -> argument #4
   251 
   252 Star parameters, unknown callables, both approach #1 and #2:
   253 
   254   g(1, 2, 3, 4)   # g not known at compile-time
   255 
   256     g   -> g
   257         -> load context for argument #1
   258     1   -> argument #2
   259     2   -> argument #3
   260     3   -> argument #4
   261     4   -> argument #5
   262 
   263   Then, check the context and shift the frame if necessary (described above).
   264 
   265   If g has a star parameter - g(a, *args) - then...
   266 
   267   Approach #1 - move arguments #3, #4, #5 (or shifted to #2, #3, #4) into a
   268                 sequence, adding a reference to the sequence in their place
   269 
   270   Approach #2 - maintain special access rules to arguments #3, #4, #5 (perhaps
   271                 shifted to #2, #3, #4) as a C-like array
   272 
   273 Tradeoffs for star parameter approaches:
   274 
   275   Approach #1 - potentially costly at run-time as arguments need moving around,
   276                 but the arguments would behave normally in functions
   277 
   278   Approach #2 - need to track usage of the star parameter and to possibly copy
   279                 its contents if assigned, as well as providing special access
   280                 mechanisms, but the invocation procedure would be simpler