Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This is great writing: very clear and easy to understand!

I feel that dynamic variable lookup is a mistake, though -- it's just so painful to have to wait until runtime to discover you've made a typo. Is supporting mutual recursion really important enough to offset this pain?



Yeah, it's a... choice is the best way to put it. It has upsides and downsides.

I do think supporting mutual recursion is very important. People expect it to simply work, especially in an object-oriented language. It does work out of the box in JavaScript, Python, Ruby, and Lua. (And note that also none of those will detect access to undefined variables until runtime.)

Early versions of my main hobby language Wren did detect this error statically but it ended up interacting poorly with the REPL and I became convinced it didn't provide enough value to justify the static checking.

The main thing that tipped the scales for me was that Scheme works this way. That seems like a pretty reasonable path to follow for a dynamically typed language.


I don't think dynamic variable lookup should be required for mutual recursion. There are plenty of static languages that support mutual recursion.


This topic is covered in a sidebar in the chapter: allowing the top level to be list of statements instead of declarations means that each function definition must happen in order. Otherwise you can end up with troublesome code like this:

    function f() { g() }
    f()
    var x = read_user_input()
    function g() { print x }
Static languages typically don't allow the calls to f() and read_user_input() -- maybe that's the right answer here. There are other answers that come to mind as well. But, either way, I don't think we should perpetuate the mistake of dynamic variable lookup.


Ah, this is solved in OCaml using the 'and' keyword:

    let rec even n =
        match n with
        | 0 -> true
        | x -> odd (x-1)
    and odd n =
        match n with
        | 0 -> false
        | x -> even (x-1)
Although personally I've never liked the idiom where everything at the top-level is a statement. Even in OCaml I usually define a 'main' function, and call it at the bottom of the file:

    let main args = do stuff...
    ...
    let () = main Sys.argv


Yes, more specifically, the "let rec" is what begins the series of mutually recursive definitions. The "rec" is a clue that this is specifically for supporting this exact recursive case.

> Although personally I've never liked the idiom where everything at the top-level is a statement.

For statically-typed languages, I'm not a huge fan of it either. But for dynamically-typed ones, I think it works out OK.


Typography and layout is also very pleasing.


Thank you! I put more time into this than most people probably realize.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: