Exercise 1: Arity Checking Applies Identically to Bound Methods — Possible Solution ==================================================================== THE PROGRAM ------------------------------ class Greeter { init(name) { this.name = name; } greet(a, b) { return this.name; } } var g = Greeter("wisp"); print g.greet(1); RESULT ------------------------------ WispRuntimeError: expected 2 arguments but got 1 THE RELEVANT CODE (unchanged from Chapter 7) ------------------------------ def visit_call(self, node): callee = node.callee.accept(self) arguments = [arg.accept(self) for arg in node.arguments] if not isinstance(callee, (WispFunction, WispClass)): raise WispRuntimeError("can only call functions and classes") if len(arguments) != callee.arity(): raise WispRuntimeError( "expected " + str(callee.arity()) + " arguments but got " + str(len(arguments)) ) return callee.call(self, arguments) WHY THIS WORKS AS AN ANSWER ------------------------------ There is no special-casing for methods anywhere in visit_call, and that's the actual point of the exercise. `g.greet` is evaluated first (as the `callee` of the Call node) via visit_get, which returns `method.bind(self)` -- a perfectly ordinary WispFunction object, the exact same type visit_call already knows how to call for a plain top-level function. By the time visit_call's own arity check runs, it has no idea -- and has no need to know -- that this particular WispFunction happens to be a bound method rather than a standalone function. `callee.arity()` just reads `len(self.declaration.params)` off the FunctionStmt node, which for `greet(a, b)` is 2, regardless of whether that FunctionStmt was declared inside a class body or at the top level. This is a direct, useful consequence of Chapter 8's own design choice to make WispFunction.bind() return an ordinary WispFunction rather than some special "BoundMethod" subtype -- every piece of interpreter code written since Chapter 7 (visit_call's arity check, the WispRuntimeError message format, even stringify()'s own "" formatting) keeps working on class methods for free, without a single line needing to be aware that classes exist at all.