micropython

docs/invocation.txt

232:2ede6db71ceb
2009-05-31 Paul Boddie Fixed the structure of "if" statement code. Fixed comparison method definitions for equality and inequality. Added optimisation where exception handlers are pushed and popped without any code defined between these operations. Reviewed exception handling including that employed around operators, introducing PopHandler and ClearException instructions in order to properly maintain exception state. Added RSVP support for some integer comparisons. Split the compare2 test program into separate tests. Added some exception-related documentation.
     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         -> load context for argument #1
   133     obj -> argument #2
   134     1   -> argument #3
   135     2   -> argument #4
   136 
   137   Need to call C.__init__(<instance>, obj, 1, 2), preferably with the existing
   138   frame:
   139 
   140     *** -> instance overwrites argument #1
   141     obj -> argument #2
   142     1   -> argument #3
   143     2   -> argument #4
   144 
   145   Then jump without switching frames.
   146   It should be possible to replace the old, tentative context information in the
   147   frame.
   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 Functions as methods:
   167 
   168   def f(x, y, z): ...
   169   class C:
   170       m = f
   171   c = C()
   172   ...
   173   f(obj, 1, 2)    # no restrictions on obj
   174   obj.m(1, 2)     # f(obj, 1, 2)
   175   C.m(obj, 1, 2)  # f(obj "assert isinstance(obj, C)", 1, 2)
   176 
   177 Context propagation:
   178 
   179   fn = C.m        # has context C
   180   fn(obj, 1, 2)   # non-instance context -> explicit context required
   181                   # must perform isinstance(obj, C)
   182   fn = c.m        # table entry for m on C -> replace context
   183                   # gives context c
   184   fn(1, 2)        # instance context -> no explicit context required
   185                   # context c inserted in call
   186 
   187 Star parameters are a convenience:
   188 
   189   max(1, 2, 3)    # call to max(*args) where args == (1, 2, 3)
   190   max((1, 2, 3))  # but why not just do this instead?
   191 
   192   One motivation: avoid explicitly making sequences.
   193   Opportunity: avoid expensive dynamic allocation of sequences?
   194 
   195 Star parameters, known callables and sequences:
   196 
   197   g(1, 2, 3, 4)   # g known as function g(a, *args) at compile-time
   198 
   199     g   -> don't get any context information
   200     1   -> argument #1
   201     2   -> reference to sequence containing arguments #2, #3, #4
   202 
   203   (This according to approach #1 described for unknown callables. With approach
   204    #2, normal argument positioning would occur.)
   205 
   206 Star parameters, unknown callables:
   207 
   208   g(1, 2, 3, 4)   # g not known at compile-time
   209 
   210     g   -> g
   211         -> load context for argument #1
   212     1   -> argument #2
   213     2   -> argument #3
   214     3   -> argument #4
   215     4   -> argument #5
   216 
   217   Then, check the context and shift the frame if necessary (described above).
   218 
   219   If g has a star parameter - g(a, *args) - then...
   220 
   221   Approach #1 - move arguments #3, #4, #5 (or shifted to #2, #3, #4) into a
   222                 sequence, adding a reference to the sequence in their place
   223 
   224   Approach #2 - maintain special access rules to arguments #3, #4, #5 (perhaps
   225                 shifted to #2, #3, #4) as a C-like array
   226 
   227 Tradeoffs for star parameter approaches:
   228 
   229   Approach #1 - potentially costly at run-time as arguments need moving around,
   230                 but the arguments would behave normally in functions
   231 
   232   Approach #2 - need to track usage of the star parameter and to possibly copy
   233                 its contents if assigned, as well as providing special access
   234                 mechanisms, but the invocation procedure would be simpler