It's not just DEFINE, TO acts the same way. TO BAD_PROC :a 1 [:b 2] OUTPUT LIST :a :b END BAD_PROC 10 b has no value in BAD_PROC [OUTPUT LIST :a :b] (BAD_PROC 10) b has no value in BAD_PROC [OUTPUT LIST :a :b] (BAD_PROC 10 20) too much inside ()'s I guess you could interpret "if the default parameter number is given, it must be last" as "wherever the default parameter number is, that is the end of the parameter list". But it would be nice if trying to define a procedure like this raised an error...
Another interesting corner case: TO FOO OP [{1}] END SETITEM 1 FIRST FOO 2 SHOW FOO I don't think it's possible to do "what the programmer intended" every time, so maybe the behavior should just be documented. There are workarounds to get the other behavior in either case (wrap in a list literal or unwrap into a LIST invocation).
Is this really a bug? It might be simpler to call this intended behavior, because the array is turned into a literal. The desired behavior can be achieved using RUN (LIST "SETITEM 1 ":array 2).
If quoted was a primitive, it could just call maybe_quote... If backtick was a primitive, making performant macros would be so much easier...
I spotted an interesting idiom in the new dequeue implementation! Is [first [x]] the most efficient way to construct a value that evaluates to x when fed into run regardless of the type of x? Better than using quoted?
Copying the arguments into a new list would nullify all the sound uses of the argument modification pattern, like preserving invisible modifications like string interning and conversions to numbers.
MEMBERP and SUBSTRINGP unsoundly modify their arguments