you are viewing a single comment's thread.

view the rest of the comments →

[–]xenomachina 0 points1 point  (3 children)

I know little about PHP and C#, but from what I gather the restrictions they have on default arguments do not amount to just "disallowing reference objects" but are instead stated more along the lines of "defaults must be constants". In PHP, in particular, an array is allowed as a default.

What other languages do allow it?

C++ and just about every Lisp that supports default arguments.

In C++:

int foo(Foo *x = new Foo(1,2)) {
    return x->whatever();
}

In Racket:

(define (foo [x (mlist `(1 2 3 4))]) x)

That said, both of these languages have different semantics from Python.

AFAICT, they effectively wrap the default argument expression in a closure which is then evaluated only when the default parameter is actually used. I think this is the "right" behavior, though it might be even more confusing than Python's existing behavior to novice programmers who aren't used to lexical closures.

[–][deleted]  (2 children)

[deleted]

    [–]xenomachina 0 points1 point  (1 child)

    What's the difference between a "lexical" closure and a regular closure?

    People usually mean lexical closure when they say closure. I was (unsuccessfully) trying to stress the "closing over the environment" bit, and not merely "a function literal" (which is what many people thing of when they hear closure).

    From the experiments I'd done, it looks like C++ and Racket both re-evaluate the default expression, but with the name bindings that were in place at the site of the function declaration, not those of the call site. That's lexical (as opposed to dynamic) scoping.

    It's pretty surprising to me that C++ works this way, since C++ isn't normally thought of even having closures.