The interpreter needs a multitude of different methods to visit the different node types. This problem of single dynamic dispatch (choosing a method overload based on the argument type not at compile time, like in C, but at runtime) is currently solved with the type name serving as a lookup with getattr into the list of methods provided in the interpreter.
This approach is slow and error-prone. Typos in the method name are caught only at runtime and may not be tracked down immediately. Also, getattr in conjunction with the string formatting (involving concatenation) seems like an expensive operation, especially when considering it is done on every node of the syntax tree recursively.
Python has a standard library solution for this: the functools.singledispatchmethod decorator. This decorator uses Python's support for type annotations and types themselves to check all dispatch methods and their argument types at compile time (or module load time, for that matter) and automatically perform the dispatch via optimized code at runtime. It may be used in the following manner:
The specific methods will not appear independently in the class (the annotation removes them from the class dir() immediately), so they can be given any placeholder name, like _. Note the use of the StringNode type annotation in its formal arguments. Although type annotations are optional and not checked at runtime, they can reflectively be queried, which is done by the singledispatchmethod logic to determine which type of argument is handled by this "overload". The default method that was annotated in the first place is only called when no other overload with appropriate argument type was found, so it can do the error handling, which currently resides in no_visit_method. The @visit.register command can be repeated any number of times for all methods.
More information on how singledispatchmethod can be used and how it works internally can be found in the Python documentation, which I have linked above.
I don't have the skill working with Dip to think that I could implement this properly, however, @raghavnautiyal , this would be an easy change to make which does not alter the language's properties, but makes it faster, safer and more extensible. A small bonus is the fact that all the visit overloads and the error handler are not vebosely accessible outside of Interpreter.
The interpreter needs a multitude of different methods to visit the different node types. This problem of single dynamic dispatch (choosing a method overload based on the argument type not at compile time, like in C, but at runtime) is currently solved with the type name serving as a lookup with
getattr
into the list of methods provided in the interpreter.This approach is slow and error-prone. Typos in the method name are caught only at runtime and may not be tracked down immediately. Also, getattr in conjunction with the string formatting (involving concatenation) seems like an expensive operation, especially when considering it is done on every node of the syntax tree recursively.
Python has a standard library solution for this: the
functools.singledispatchmethod
decorator. This decorator uses Python's support for type annotations and types themselves to check all dispatch methods and their argument types at compile time (or module load time, for that matter) and automatically perform the dispatch via optimized code at runtime. It may be used in the following manner:The specific methods will not appear independently in the class (the annotation removes them from the class
dir()
immediately), so they can be given any placeholder name, like_
. Note the use of theStringNode
type annotation in its formal arguments. Although type annotations are optional and not checked at runtime, they can reflectively be queried, which is done by thesingledispatchmethod
logic to determine which type of argument is handled by this "overload". The default method that was annotated in the first place is only called when no other overload with appropriate argument type was found, so it can do the error handling, which currently resides inno_visit_method
. The@visit.register
command can be repeated any number of times for all methods.More information on how
singledispatchmethod
can be used and how it works internally can be found in the Python documentation, which I have linked above.I don't have the skill working with Dip to think that I could implement this properly, however, @raghavnautiyal , this would be an easy change to make which does not alter the language's properties, but makes it faster, safer and more extensible. A small bonus is the fact that all the
visit
overloads and the error handler are not vebosely accessible outside of Interpreter.