You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In my quest to adapt Python syntax to C-style block scoping, several oddities have arisen. It may be worthwhile to examine some options for improving these situations.
One of the most notable issues is local function declarations. Within a scope that produces locals, if one function needs to call another, the caller must be defined after the callee, or a sort of forward-declaration must be present that is later assigned the referent function.
ifTrue:
letbdefa():
b()
def_b():
passb=_b
Due to the rules around duplicate declarations, making these forward declarations requires the use of two names. Attempting to use the same name again will raise an error at compilation time. On the surface, this is intentional behavior - shadowing declarations within the same scope is almost definitely a mistake, and it is better if we can catch it - but it does make things awkward. For one, the function's runtime name, used in debugging, will be the one found alongside the def, but the callers appearing before the definition will use the name in the let - this is bound to be a source of confusion.
So, what can we do to fix this? I'm open to suggestions on syntax.
One thought was to have an explicit forward-declaration syntax for functions, such that an assignment in the same scope is required and failing to provide one would result in an error. This syntax could be as simple as let def b; the stack space would be allocated as usual, and the variable would be marked as in need of later assignment. Further, local references to the variable before it is assigned a function definition could be tagged as errors ("Forward-declared function referenced as local before definition"), while non-local references would continue to be allowed (potentially getting None if the assignment has not yet happened, temporally, before it is referenced, same as they would now).
letdefbdefa():
b()
defb():
pass
A question to answer is how this would work with multiple such forward-declarations. Would let def be its own statement with a list of variables to follow? This seems the most straight-forward to implement, and avoids having to deal with the possibility of mixed function declarations and variable declarations, or whether we allow assignment in such a case...
An alternative syntax may be to just reuse def on its own - with no parameter list and semicolon, we would have forward declaration.
A somewhat silly idea is to use the for keyword in a construction like def for b or for def b to represent a forward declaration, but this reuse of an existing keyword for a very different purpose seems undesirable.
Another approach would be to specify that the def is for an already-declared name, but I'm not sure what syntax would be good for this. One thought was to reuse assignment syntax such that this would be:
letbdefa():
b()
b=def ():
pass
... but this seems like more trouble than it's worth unless a block function expression syntax was introduced (and even then, I foresee issues with the function name, as in the original problem - with a simple single-target assignment it's easy enough to determine the target name, but if function expressions were introduced we would likely need to do something like what we do with lambdas...). I also don't like this because it means more things need to change when porting Python code - the added letand the change in the function definition - better to keep everything in the let so it is all the needs to be changed.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
In my quest to adapt Python syntax to C-style block scoping, several oddities have arisen. It may be worthwhile to examine some options for improving these situations.
One of the most notable issues is local function declarations. Within a scope that produces locals, if one function needs to call another, the caller must be defined after the callee, or a sort of forward-declaration must be present that is later assigned the referent function.
Due to the rules around duplicate declarations, making these forward declarations requires the use of two names. Attempting to use the same name again will raise an error at compilation time. On the surface, this is intentional behavior - shadowing declarations within the same scope is almost definitely a mistake, and it is better if we can catch it - but it does make things awkward. For one, the function's runtime name, used in debugging, will be the one found alongside the
def
, but the callers appearing before the definition will use the name in thelet
- this is bound to be a source of confusion.So, what can we do to fix this? I'm open to suggestions on syntax.
One thought was to have an explicit forward-declaration syntax for functions, such that an assignment in the same scope is required and failing to provide one would result in an error. This syntax could be as simple as
let def b
; the stack space would be allocated as usual, and the variable would be marked as in need of later assignment. Further, local references to the variable before it is assigned a function definition could be tagged as errors ("Forward-declared function referenced as local before definition"), while non-local references would continue to be allowed (potentially gettingNone
if the assignment has not yet happened, temporally, before it is referenced, same as they would now).A question to answer is how this would work with multiple such forward-declarations. Would
let def
be its own statement with a list of variables to follow? This seems the most straight-forward to implement, and avoids having to deal with the possibility of mixed function declarations and variable declarations, or whether we allow assignment in such a case...An alternative syntax may be to just reuse
def
on its own - with no parameter list and semicolon, we would have forward declaration.A somewhat silly idea is to use the
for
keyword in a construction likedef for b
orfor def b
to represent a forward declaration, but this reuse of an existing keyword for a very different purpose seems undesirable.Another approach would be to specify that the
def
is for an already-declared name, but I'm not sure what syntax would be good for this. One thought was to reuse assignment syntax such that this would be:... but this seems like more trouble than it's worth unless a block function expression syntax was introduced (and even then, I foresee issues with the function name, as in the original problem - with a simple single-target assignment it's easy enough to determine the target name, but if function expressions were introduced we would likely need to do something like what we do with
lambda
s...). I also don't like this because it means more things need to change when porting Python code - the addedlet
and the change in the function definition - better to keep everything in thelet
so it is all the needs to be changed.Any other ideas?
Beta Was this translation helpful? Give feedback.
All reactions