3 ms·
Are there any other features in common other than closures and first class functions? I'm not sure that makes Javascript closer to Scheme than any other languag
by krackers 7y ago
Are there any other features in common other than closures and first class functions? I'm not sure that makes Javascript closer to Scheme than any other language like Python (which also has a version of SICP).
- bitwize 7y agoWell, lambdas can be multiline in JavaScript. At a higher level, JavaScript has Scheme's desirable "small language kernel" property. But ultimately, closures, first-class functions, and lexical scope are all anybody really cares about. The bits that set Scheme apart are tail-call optimization, hygienic macros, and first-class continuations. * Tail-call optimization fucks with your ability to have correct stack traces when an exception is thrown. You know, exceptions -- those things the Scheme implementor community didn't give much thought to until R6RS. Anyways, not having correct stack traces is a HUGE no-no in production code, which is why the JVM doesn't do TCO and never will. * Hygienic macros -- Common Lispers are snickering right now. As the article said, syntax-rules is tricky enough to implement without all the added shit syntax-case adds. They both are much more difficult to use than CL's DEFMACRO, and for what? To prevent a class of beginner-tier mistakes that are easily worked around with gensyms. And anyway, JavaScript programmers are one 'npm install' away from Babel or any number of other frameworks that parse, emit, or transform JavaScript ASTs, so so much for Lisp's killer feature in general. * Continuations -- you're fucking kidding me, right? Continuations are to programs what time travel is to stories: the implications of adding them will blow your brain, so if you're smart you won't use them.
- macintux 7y ago> Anyways, not having correct stack traces is a HUGE no-no in production code I think that’s misleading. Not having a comprehensive stack trace is much more painful for imperative or especially OO code, where the state at the time of failure is practically impossible to discern. Erlang gets away with it (for decidedly non-trivial production code like much of the world’s cellular routing) because state is much easier to determine. (Or maybe I’m blowing smoke. Certainly that’s how it feels to me.)
- deleted 7y ago[deleted]
- Scarbutt 7y agoTail-call optimization fucks with your ability to have correct stack traces when an exception is thrown. Safari/JScore, the only browser to implement TCO solved this using shadow stacks.
- throwaway17_17 7y agoI think it’s worth pointing out a few exceptions to what are decent critiques. As an aside, I agree that these three capabilities, along with first-class functions are essentially the commonly bullet pointed marketing keys for Scheme. TCO -> I see your point about stack tracing and tend to agree, but more importantly, one key difference between Javascript and Scheme is the focus on recursion. Javascript decided that imperative looping was the proper, idiomatic way to handle iterative expression construction. With this design decision, leaving aside whether the looping vs recursion is an equal trade, TCO was not going to be a priority and the style of programming grew around that first choice or iterative style. Hygienic Macros - I love macros. However, in contrast to your position, I like my macros like I like my martinis... clean, as a general rule. So while I like a basic assumption of hygienic macros I also want the capability to produce ugly dirty procedural macros to be available. But that is just a preference of mine. I agree that the wealth of options for automated and principled syntax tree manipulation and code generation makes the need for built in macros almost non-existent. Continuations -> while I understand the strong warning, drifted continuations enable some very nice coding possibilities, particularly implementations of generators, coroutines generally, and better callback syntax. Javascript just decided that instead of handing devs the keys to the Delorean they would just chauffeur everyone, i.e. they built constructs for these common and useful patterns directly into the language semantics. This is particularly the case for future based coroutines, now with the async/await sugar.
- kccqzy 7y agoWhile I believe general continuations are too powerful to be really useful in real-world production programs, delimited continuations really ought to be possible. See http://okmij.org/ftp/continuations/#tutorial http://okmij.org/ftp/continuations/#tutorial for example. They are quite similar to the Cont monad in Haskell, and are occasionally quite useful.
- bjoli 7y agoTCO is a great feature if you want to compile to a language. Recursion is the mother of all loops. TCO really only applies if you have things tail called, and long string of optimizable tail calls are rare. I have debugged poorly written defmacros for longer time than I spent fighting macro hygiene. I implemented defmacro using syntax rules (about 7 lines of code if you have access to schemes with optional and keyword arguments) and use it frequently. My rule is however that if I ever want to introduce bindings of any kind I will use defmacro. Simple. Saves me a lot of pain. But when it comes to macros there is no truth. This discussion has been going on long enough for most o us to know that it is a matter of taste. Call/cc is overkill. It is a shitty, leaky abstraction that nobody really wants. Delimited continuations are the bee's knees! They compose, capture just the things you tell it to and are fast. They follow the idea of having a well chosen set of primitives as building blocks. You want CL's tagbody? No problem. Fast coroutine style generators? You got it. Cooperative, fiber based multitasking? Just a pure scheme library waiting to be used!