micropython

docs/invocation.txt

217:62219b8d6baf
2009-05-17 Paul Boddie Fixed context detection in CheckFrame.
     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   -> don't get any context information
    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 - don't get any context information
    84     obj -> argument #1
    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   -> C.__init__
   103         -> new instance is argument #1
   104     obj -> argument #2
   105     1   -> argument #3
   106     2   -> argument #4
   107 
   108   The new instance must be manually provided as the result after 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     <context> is module or class:
   123       (<context>, obj, 1, 2) -> (obj, 1, 2)
   124 
   125     <context> is instance: no change
   126 
   127 Argument lists in instantiators:
   128 
   129   f(obj, 1, 2)    # f not known at compile-time
   130 
   131     f   -> C.__new__ (known and called at run-time)
   132 
   133   Need to call C.__init__(<instance>, obj, 1, 2), preferably with the existing
   134   frame:
   135 
   136     <insert instance before received arguments>
   137     obj -> argument #1
   138     1   -> argument #2
   139     2   -> argument #3
   140 
   141   Then jump without switching frames.
   142   It should be possible to replace the old, tentative context information in the
   143   frame.
   144 
   145 Defaults for unknown callables:
   146 
   147   f(obj)          # f not known at compile-time
   148 
   149     f   -> f
   150         -> load context for argument #1
   151     obj -> argument #2
   152 
   153   Then, check the number of arguments and the availability of defaults against
   154   the details provided by the callable's structure.
   155 
   156 Checking defaults for unknown callables:
   157 
   158   Approach #1 - pre-fill defaults, add arguments, check frame
   159 
   160   Approach #2 - add arguments, add defaults while checking frame
   161 
   162 Functions as methods:
   163 
   164   def f(x, y, z): ...
   165   class C:
   166       m = f
   167   c = C()
   168   ...
   169   f(obj, 1, 2)    # no restrictions on obj
   170   obj.m(1, 2)     # f(obj, 1, 2)
   171   C.m(obj, 1, 2)  # f(obj "assert isinstance(obj, C)", 1, 2)
   172 
   173 Context propagation:
   174 
   175   fn = C.m        # has context C
   176   fn(obj, 1, 2)   # non-instance context -> explicit context required
   177                   # must perform isinstance(obj, C)
   178   fn = c.m        # table entry for m on C -> replace context
   179                   # gives context c
   180   fn(1, 2)        # instance context -> no explicit context required
   181                   # context c inserted in call
   182 
   183 Star parameters are a convenience:
   184 
   185   max(1, 2, 3)    # call to max(*args) where args == (1, 2, 3)
   186   max((1, 2, 3))  # but why not just do this instead?
   187 
   188   One motivation: avoid explicitly making sequences.
   189   Opportunity: avoid expensive dynamic allocation of sequences?
   190 
   191 Star parameters, known callables and sequences:
   192 
   193   g(1, 2, 3, 4)   # g known as function g(a, *args) at compile-time
   194 
   195     g   -> don't get any context information
   196     1   -> argument #1
   197     2   -> reference to sequence containing arguments #2, #3, #4
   198 
   199   (This according to approach #1 described for unknown callables. With approach
   200    #2, normal argument positioning would occur.)
   201 
   202 Star parameters, unknown callables:
   203 
   204   g(1, 2, 3, 4)   # g not known at compile-time
   205 
   206     g   -> g
   207         -> load context for argument #1
   208     1   -> argument #2
   209     2   -> argument #3
   210     3   -> argument #4
   211     4   -> argument #5
   212 
   213   Then, check the context and shift the frame if necessary (described above).
   214 
   215   If g has a star parameter - g(a, *args) - then...
   216 
   217   Approach #1 - move arguments #3, #4, #5 (or shifted to #2, #3, #4) into a
   218                 sequence, adding a reference to the sequence in their place
   219 
   220   Approach #2 - maintain special access rules to arguments #3, #4, #5 (perhaps
   221                 shifted to #2, #3, #4) as a C-like array
   222 
   223 Tradeoffs for star parameter approaches:
   224 
   225   Approach #1 - potentially costly at run-time as arguments need moving around,
   226                 but the arguments would behave normally in functions
   227 
   228   Approach #2 - need to track usage of the star parameter and to possibly copy
   229                 its contents if assigned, as well as providing special access
   230                 mechanisms, but the invocation procedure would be simpler