Closed adri326 closed 2 years ago
I think what I'd rather do here is enforce it at a type level. The way I see it working is:
pub struct Symbol(pub String);
Value::Symbol(String)
becomes Value::Symbol(Symbol)
Lambda
's argnames
becomes a Vec<Symbol>
This way we're forced by Rust to validate the lisp form before we can even construct a Lambda
struct, and we avoid a bunch of runtime checking complexity down the line
I can go ahead and implement this, or if you prefer, you're welcome to implement it yourself in the PR and we can get it merged that way (I don't want to rob you of the contribution if you care about having it under your name, since you've put effort into it already, but if you don't care about that then I'm also happy to make the changes)
To your concern about it being a breaking change- I've just been incrementing the semver as needed when making breaking changes, so I'm not too worried about that
We can also use the opportunity to introduce a call
method on Lambda
and maybe even currying.
I'm not too worried about the contribution thing, implementing my PR only took me about an hour. I think github supports co-authoring in the commit message, if you want to do it that way.
When constructing a
Lambda
instance insrc/interpreter.rs
, the value forargnames
is not checked. This later causes an assertion error, asargnames
is expected to be aList
containing onlySymbol
s. The following piece of code demonstrates this issue:Expected: The interpreter should return an
Err
, explaining that3
is not a valid symbol for a function's argument Actual:With this PR:
Runtime error: Argument names in function definition for "lambda" should only contain symbols, got 3
This PR fixes that, by introducing the requirement for
argnames
to be aList
ofSymbol
s as a class invariant forLambda
. This invariant is enforced on the creation of a newLambda
instance, and theargnames
field has been made private and is now read-only through the newargnames()
method.The check in this PR is also catches instances of this issue that may seem less obvious, like
(lambda (f) (f 3))
: heref
is interpreted asValue::False
, which triggers the error message.Notes
I see two reasons to reject this PR:
Lambda
instances by hand will need to get addressedLambda
instance