Hacker News new | past | comments | ask | show | jobs | submit login
SICP: JavaScript Edition available for pre-order (mitpress.mit.edu)
139 points by dS0rrow on Jan 20, 2022 | hide | past | favorite | 117 comments

Note to the unaware, both* this version and the classic (Scheme) version are Creative Commons-licensed and freely available online. (*edit: thanks to keithwinstein for enlightening me -- I wrongly thought it was just the one. The publisher's site doesn't advertise this at all!)

https://sicp.sourceacademy.org/ (JS version)

https://mitpress.mit.edu/sites/default/files/sicp/index.html (1984 classic)

https://sicp.sourceacademy.org/ brings me to something called "Comparison Edition". I was looking for a straight JS version with editable/executable code, and found it at the link named "Interactive SICP JS" (which takes you to https://sourceacademy.org/sicpjs/index)

The in-line editor is a bit intrusive (fills up most of my screen, unlike say eloquentjavascript.net) but it's still pretty neat to have run-able examples. Kudos to the creators.

Is this version the same as the one that's going to be released on paperback?

I believe they are both CC-licensed. See https://sicp.sourceacademy.org/

A ton of work seems to have gone into this -- they have a meta-circular evaluator in JavaScript (and it's not that much longer than the original Scheme)!

Very respectfully disagree; but long or short, this looks really bad:

                   list("name", "size"), list("literal", 2)),
              list("binary_operator_combination", "*",
                   list("literal", 5), list("name", "size"))))
https://sourceacademy.org/sicpjs/4.1.2 ("4.1.2 Metalinguistic Abstraction / Representing Components")

This isn't an ideal language for doing this stuff. The Scheme version is completely transparent about what you're doing; whereas this kind of language makes you work through a thick veil of abstractions.

(This line doesn't occur in the Scheme version, but the analog would be (quote (let ((size 2)) (* size 5))). Which would you rather debug?)

I know which one I'd rather debug, but which one can a new student get started with faster? They are unlikely to already have a scheme interpreter on their computer.

It won't take longer than 15 minutes to get racket installed, and that's being extremely conservative. If you can't spend 15 minutes getting setup done, why would you finish a dense book on the theory of computation?

The scheme version was aimed at students who might never have touched a computer before.

Why should this book be different, though these days aimed at students who’d only operated a computer before.

When the Scheme version was written, all the programming languages were equally weird to incoming students. So Scheme was as good a starting point as any other.

Today, Scheme is still weird, but JavaScript is familiar. It's something the incoming students are at least likely to have heard of. So it makes more sense to ease them into the material with the familiar rather than drop them into something weird.

By that logic, North Korea is a better vacation spot than Niue, since most people are at least likely to have heard of North Korea.

(Just to be clear, that was intended as a friendly poke, not a scathing rebuke. I do think lisps are better suited for SICP than JS is for the reasons others have mentioned, but I’m not trying to be a jerk about it.)

It's not if the familiar language obscures the central ideas.

Making sense of those parentheses is genuinely hard for a newcomer, too. The Scheme version is more readable to you because you already know it - anyone who's actually working through this with a class level of effort instead of skimming pages is going to spend an equal amount of time learning how to read the syntax you quoted, and they'll be fine once they do.

JS is the WORST of both worlds.

With the scheme version, you have straight-up trees to work with.

With the Javascript version, you have to learn all about parsing rules and gotchas and then you STILL wind up with trees for everything.

There is also github repo https://github.com/source-academy/sicp/wiki with instruction how to generate various versions

That's wonderful! I was going to ask.

SICP in Python - https://news.ycombinator.com/item?id=22994976

You can see there's more negativity in this thread compared to the Python one. HN crowd is pretty hostile toward JavaScript.

Yet JavaScript is obviously a better choice than Python in terms of SICP Scheme substitute. For example:

- JavaScript is arguably a Scheme descendant, or at least have closer blood ties with Scheme than Python.

- The Lambda in Python is just awkward, and SICP is a book about lambdas.

- The Chapter 2: JavaScript use more anonymous object which makes it a better choice, although there are dictionaries in Python it's more favored to use Classes.

- Chapter 3, the Object-oriented Programming part: Use lexical closure to simulate object is just day to day JavaScript. So does dispatch and pattern matching messages.

- Chapter 3, the stream part: In JavaScript world the "functional" streams approach is also very popular.

- As for symbolic programming and such, they're both not particularly good. But that's a problem for all mainstream languages. At least JavaScript has programmable string template.

As you can see many SICP stuff are just day-to-day JavaScript, but not so much in idiomatic Python. Let alone JavaScript is more approachable in almost every platform, and much easier to make interactive tutorials.

I've really noticed that people rage that Javascript and npm removed so much of a barrier to tech.

Try publishing a dependency for Java. Now try doing it for JS.

Everyone was able to do highly concurrent workloads. Something that was extremely difficult before Javascript.

It just smells of elitism to me. It's a wonderful language that brought the async await system to everyone.

You mean it's super hard in java? All they have is maven with hard links into eclipse from my observation.

Npm is light years ahead in execution and usage. Python distribution is.... interesting with eggs & poetry

I agree. I don't find it's hard in Java.

But with that being said, in the JavaScript world, the tooling treat developers more like "users" rather than "engineers". For example:

- Many documentations are cohesive, well-thought, and well main-maintained.

- There are usually handy shortcuts for things like `npx` or `npm i <package name>`

- And many other improvements strive for developers' life-quality, such as call back-end and databases with strong typing, but without messy code generator at the same time.

Meanwhile, I have worked with Java and C# for quite a while, those documentations are so daunting, they feel like math textbooks from the Soviet Union. And companies like Microsoft never bother to fix their blur resolutions for SQL Server Management Studio and such. It's just like nobody cares, and they make working really feels like screwing codes on production lines.

> But with that being said, in the JavaScript world, the tooling treat developers more like "users" rather than "engineers". For example:

Tooling really is about becoming a user. It takes a dozen different file types and shoves them through at least a dozen different type-specific pieces of software. Understanding any one of those to any real degree would take weeks to months.

Just JS itself would require understanding transpilers, minifiers (an optimizing compiler), how NPM works, how these work with all the other tools, various module bundling styles, map files, feature differences for literally 10 versions of JS, browser JS limitations (eg, Chrome and FF break the JS spec for tail calls), JS API differences and polyfills, hot reloading techniques, and wrapping an entire server instance into all of this. I'm sure there are other parts I'm not thinking of.

I did the hand-rolling of all this stuff for several years before jumping on to create-react-app. I've spent many days reading the documentation only to have to read it all again when the next major version drops and everything changes in slightly incompatible ways.

I love learning, but on the whole, this adds very little value to most of the projects I've worked on (though some really did need hand-rolling for very niche requirements).

I rather like laving all the tooling to domain experts who know far more about it than I ever will. I'd rather be a "user" and leave all my engineering headspace for the problems at hand.

It's C# that created and popularized async/await, not JS (and it having an already open source implementation at the time, it was available to everyone for free).

JS introduced promises to the world around 2005 (they were in an unused experimental language a few years before).

async/await is mostly specialized syntax over generators. I'd note that ES4 had generators in the early 2000s

F# introduced async/await in 2007.

C# was mostly copying F# (like it's done for almost every new feature in the past decade or so).

Haskell libraries added support around the same time as C# (likely inspired by F#)

JS had the feature for several years via transpilers before it was finally added officially.

Based on usage numbers, I'm gonna say it was a mix of both. But JS brought it to the very mainstream.

What’s awkward about lambda in python?

Python is based on mainly on statements rather than expressions, and lambdas can’t have multiple statements, so writing lambdas is different from writing normal Python code.

In a very real sense, there is no idiomatic way to write complex lambdas in Python. What you would do instead is define a named function and pass it in as an argument. This is fine but definitely more complicated.

- No multi-line support

- Gets very messy when nested

And SICP is a book about learning computer science by abusing lambdas.

One major benefit here is how approachable this is. One could even simply open Dev Tools on their browser and use the console as a REPL. As someone who installed Scheme/Dr Scheme/Dr Racket long ago, it's nice to say, "you can get started right now". I know there'll be a lot of complaint about JS as a language choice but, it's pretty ubiquitous. And, much like Scheme, no one's saying, "you should use this for your next app that you have planned"

It's definitely a benefit but the trade-off is rough - the book itself is 'approachable' in the sense that it's written well in an accessible style. But it's dense in concepts and ideas and smacks you with them right off the bat. A lot of them are much more convoluted when expressed in JS, especially for the first time. Take a look at the sort of challenge the authors had to deal with:


We're just a few pages in and the original instructive exercise of 'why can't I make my own if out of cond' involves learning the JS ternary operator.

I agree in contrast to the previous reply I made. I still play with Shen, and I would love to see SICP in Shen, since Shen has ben implemented for many languages including JavaScript, but it's still a Lisp. I should try my hand at it if I really want to learn Shen.

I am also an APL/J fan and this footnote in SICP rings true:

[15] Richard Waters (1979) developed a program that automatically analyzes traditional Fortran programs, viewing them in terms of maps, filters, and accumulations. He found that fully 90 percent of the code in the Fortran Scientific Subroutine Package fits neatly into this paradigm. One of the reasons for the success of Lisp as a programming language is that lists provide a standard medium for expressing ordered collections so that they can be manipulated using higher-order operations. e programming language APL owes much of its power and appeal to a similar choice. In APL all data are represented as arrays, and there is a universal and convenient set of generic operators for all sorts of array operations.

I wanted to say Shen will never be relevant or useful without a change to it's licensing model, but looking at the website it seems like that exact thing has actually happened? It's hard to find concrete info so I'd love for someone to confirm, but IIRC Shen was encumbered by some sort of distasteful closed source model previously but it looks like that's no longer the case? Very excited to dive in if that's the case.

EDIT: > In 2021 the SP kernel was returned to open source forming the basis for the S series of kernels on which this manual is based.


I actually subscribed for a while to SP, but I didn't like having to be connected to the internet to run it. I own two TBOS editions, and it scratches my Haskell, Lisp, Forth (because Klambda), and Prolog itch. I've toyed with the WaspLisp version, and I really want to dive into it. Deech's YT video years ago showing how you could program the front and back end in Shen, because there was a Ruby and JavaScript port really sold me. To me it is relevant, because I can use one language deployed on so many ports. Plus, I just really got into combinators after reading the beginning chapters of Stephen Wolfram's book on them. I don't live and die for open source-only projects. I think only the SP kernel, not all the libraries (grahics, etc.) were. I believe they are still in SP, but I may be wrong.

> [15] Richard Waters (1979) developed a program that automatically analyzes traditional Fortran programs

Anyone have a PDF link to a paper about this Fortran analyzer?

This is the wrong kind of approachable, because you have to learn a ton of random web things before you do anything outside the repl and before your program can even process user input and then people struggle with those two concepts that would be trivial to them if they could be introduced earlier.

Having seen what having javascript as a first language does to first year students I can't understand why this is considered a good idea.

I'm an uncle of 6 children, ages 7 and under. My guess is that if any of them have ever seen a VT100 terminal emulator or Windows console window, it was probably only when watching me or my brother-in-law. So traditional line-oriented programs, with plain text input and output, will be alien to kids of this generation.

I know Racket has an integrated GUI toolkit, but will this new generation be able to run it on their tablets?

One benefit of the great variety in front-end JavaScript frameworks, often criticized as churn, is that we're more likely to arrive at an abstraction that will be approachable to beginners. I look forward to watching how this generation learns to program.

Bringing the best education materials to the most widely used environment, and language doesn't seem very difficult to understand.

Nothing prohibits them from learning, "better" languages after you reach them, but first you have to reach them.

Though I'm sure there are a few Scheme interpreters written in JS or that compile to WebAssembly and so are just about as accessible.

Right, but if we're looking for the quickest path, "right click on this page, and select 'Inspect'" and boom. You're there. Certainly one could go to https://replit.com/ and choose from a host of "better" languages. My approach was trying to avoid someone having to install anything at all. As soon as you say, "ok, you'll need to install NodeJS, then use npm to install this package....", things get dicey. Someone who's serious about learning will fight through it, but someone who's just starting out may be put off.

First they replace Scheme with Python for their CS classes, and now SICP in JavaScript! Isn't this another portent from Nostradamus about the coming of the end of the world?

No, it's proof that you are already in hell.

I think hell is coded in Java

Indeed, and this is common knowledge. But in hell you program in javascript. Or https://en.wikipedia.org/wiki/Malbolge .

Hell, Heaven and Earth are written in Java. That is why most people are slow after waking up and why you need to sleep for garbage collection to run.

For arguments that God wrote it all in Lisp see https://www.youtube.com/watch?v=5-OjTPj7K54

Spot on, we wake up groggy because the VM is kicking in

Like many answers in life, hell is not coded in Java or JavaScript, hell is coded by other people coding in Java or JavaScript.

Some things in life just turn into hell when you ask for everyone’s interpretation (politics, government, programming). It’s not fried chicken which most people cant fuck up even if they tried. Stick the damn chicken in the fryer, and whether you over-do it or under-do it, it’ll be fine with some ketchup.

Write Once, Burn Anywhere

I've really gotten used to hell then :>

It's not the worst thing to happen, but for the love of god, couldn't they have at least chosen an expression oriented language?! Even Ruby for god's sakes would've been better than JS!

If they were to choose another language, StandardML should have been the choice.

It was designed to be easy for students to implement with relatively easy parsing rules. It is fully functional, but allows mutations. It also has an actually sound type system.

Ruby’s awesome. This would have slapped in Ruby.

I saw this the other day on Amazon while picking up the SICP instructor's edition. For the life of me, I can't figure out why they chose JavaScript to do this. And the new authors are professors.

Since the original SICP has a permissive license, I've actually thought about doing something similar, but with a more modern functional language.

Yeah, imagine the craziness of making materials like this accessible to users of the most widely used language.

> Yeah, imagine the craziness of making materials like this accessible to users of the most widely used language.

One of the reasons it was originally written for scheme is that scheme has a small core, simple syntax and can very easily be learned while reading SICP.

More importantly, the type of user that would get put off by using/learning scheme, is probably not going to make it through SICP. Learning just enough scheme is arguably the easiest part of going through SICP.

SCIP uses an amount of high-level functions that are frankly ridiculous outside of a very functional language. Hell, maybe even outside of a Lisp-1. That's not to say that Scheme is the best language (probably not in my top 5), but there are better languages than javascript for SCIP, and better programming methods than SCIP for javascript.

Which remotely popular language would be a better choice?

The only ones that leap to mind are the ML languages.

I guess that's the rub, I'm not sure any of them are. Certainly Javascript has stronger support for functional programming than Python. Maybe Ruby? Even Haskell would get pretty much unreadable extremely quickly, though pattern matching would make some parts way easier.

I'm not coming at this from a lisp fanboy perspective (though I am one), it's just kinda the reality of SICP's style of programming. Even PAIP translates extremely well to Python, but SICP encourages a layering of abstractions that I can't picture reading without parenthesis keeping order of operations strict.

The best solution I can think of is having a pre-packaged setup for getting started with Scheme, a la Dr. Racket.

It didn't become widely used because it were any good and being widely used generally doesn't imply quality.

I think the decision on what language to use in teaching material should be made based on quality and ease use, not popularity of the language.

Education and enlightenment are not about appealing to the least common denominator and status quo.

JavaScript lacks several features that make it apt to translate this book.

Yeah, there are so many people who want to expand their experience and mind, who also can't learn a language that can be taught in 10 minutes.

Because those people were born programming Javascript?

What is "accessible" in this context is purely a state and attitude of the intellect.

One of the exercises in the first (or was that the second?) chapter is speeding up Fibonacci's iterative algorithm by viewing the state transition equations that derives F_n and F_n+1 from F_n-1 and F_n as a pair of linear transformations, therefore a matrix multiplication that can benfit from fast exponentiation (repeatedly squaring). Then in the chapters after that you code a symbolic differentiator and add pattern matching to the language.

SICP doesn't try to be accessible, it's explicitely an engineering text book made for engineers. That's even the reason some people have criticized it[1] and wrote another book[2] with the same themes and goals but ditching the excessive math focus. Anyone who can understand SICP's exercises can understand Scheme.

[1] https://en.wikipedia.org/wiki/The_Structure_and_Interpretati...

[2] https://en.wikipedia.org/wiki/How_to_Design_Programs

I got a chance to talk to Hal Abelson and two things I found surprising where: 1) he thought part of SICPs success was due to the calibre of students MIT gets and 2) He though Javascript was a fairly good scheme approximation ( although with too much syntax).

>He though Javascript was a fairly good scheme approximation ( although with too much syntax).

that one isn't too surprising because "putting scheme in the browser" was quite literally what Eich set out to do

"As I’ve often said, and as others at Netscape can confirm, I was recruited to Netscape with the promise of “doing Scheme” in the browser. At least client engineering management including Tom Paquin, Michael Toy, and Rick Schell, along with some guy named Marc Andreessen, were convinced that Netscape should embed a programming language, in source form, in HTML. So it was hardly a case of me selling a “pointy-haired boss” — more the reverse.

Whether that language should be Scheme was an open question, but Scheme was the bait I went for in joining Netscape. Previously, at SGI, Nick Thompson had turned me on to SICP."


Maybe SICP will not be better for using Javascript, but perhaps Javascript programmers will get better for reading SICP?

That would be very nice.

No, they'll get bad ideas and try to implement them even more badly.

Everybody's dealt with that one asshole* who overdosed on category theory and proceeds to write Haskell in Python for the next two years.

* It's me, I'm that asshole.

Thanks for the laugh!

Guilty here too, just not in python.

I'd say JS-only devs would benefit from getting outside of their bubble ASAP, and the original SICP is a very good way to begin doing that.

Until js runtimes implement tail call optimization, recursive coding is only really feasible in an academic sense.

In langs with proper TCO (like scheme and lua), recursion is a beautiful and practical way to solve problems.

I admit, I did a double-take: thought it was a joke,at first... like those meme-oriented O'Reilly book covers.

SICP translated to JavaScript (2013): https://news.ycombinator.com/item?id=6385617

Thanks! Macroexpanded:

SICP – Upcoming JavaScript Edition - https://news.ycombinator.com/item?id=27737942 - July 2021 (2 comments)

Structure and Interpretation of Computer Programs – JavaScript Adaptation - https://news.ycombinator.com/item?id=21822903 - Dec 2019 (180 comments)

SICP JavaScript Going Public - https://news.ycombinator.com/item?id=21779397 - Dec 2019 (1 comment)

SICP translated to JavaScript - https://news.ycombinator.com/item?id=6385617 - Sept 2013 (107 comments)

Holy crap take a look at some of the JS examples in Chapter 4 - functions declaring functions declaring functions returning functions

I hate this style of coding. I don't see how it's any better than turning everything into data and code in encapsulated class objects and passing them around

You shouldn't read SICP as a guide to practical programming. A lot of things in it would normally be bad style or contrived, but it's interesting to know that they are possible.

It's handy sometimes, but I think it starts looking worse the further from Scheme you travel. Even in Common Lisp it's probably too far, but with a Lisp-1 you get some really pretty high-level abstractions. Of course I find I don't miss them very much, but they sure are fun.

I took the CS1101S course taught by Martin Henz (who did the adaptation), where this JavaScript adaptation of SICP was the textbook. I enjoyed writing JavaScript and functional programming.

Here is an old screenshot of the interpreter that I was able to build:


SICP should be shelved into the museum of the great CS courses. It served its purpose in its generation (the early batches like 1990s were already electrical engineers).Even Discrete-Math was just an experimental collection of concepts for them[1]. My mad respect and admiration to those professors at MIT.

We moved on. Assuming we have completed nand2tetris[https://www.nand2tetris.org/], we should instead be focussing on something like HtDP[2], or maybe like how they do at Brown using Pyret[3] or my favourite, how they teach programming at CMU - C with training wheels[5][6]

SICP as a second course, will then be fun to those passionate about mariad applications in the midst of innovation decades.

Javascript (and sometimes Python) won't give you the insight these courses were designed for. To learn programming? Absoutely NO.

[1]http://www.aduni.org/courses/ [2]https://news.ycombinator.com/item?id=18890417 [3]https://www.pyret.org/ [4]https://www.cs.cmu.edu/afs/cs/local/sml/common/smlguide/inde... [5]https://news.ycombinator.com/item?id=15499160 [6]https://bitbucket.org/c0-lang/docs/wiki/Home

No, thanks. It serves as a perfect blend of a serious bullet point in the introduction entries and niche comedy. It's part of the eternal culture around it.

Insta buy. I love my SICP book. Need this for fun, perspective to teach juniors, and shelf art.

Yes, I pre-ordered.

For those complaining about it being in JS, probably didn’t read SICP as it wasn’t about LISP. This isn’t about JS.

> This isn’t about JS.

That's precisely why it shouldn't be in JS.

Edit: to clarify, javascript is full of random warts that you have to know about in order to use it effectively, that's why I think a language with less such warts would be more suitable for someone that wants to try out and use the ideas book introduces with caring too much about the language.

The most accessible runtime on the planet. To each their own. I loathe JS, but I also believe english is a crap language. English happens to be the only language I can effectively use to describe my ideas to others. :-)

> The most accessible runtime on the planet.

In what sense?

If you have a browser on a computer you have a js repl.

That's what I had assumed but wanted to double check since "accessible" is ambiguous. However, it's not all that convincing of an argument. Several languages are installed as easy as a browser is. And loading a local file, such as code included with a book, in the developer console quickly goes beyond accessible.

You don't even have to install a browser on any popular OS you can name.

JS REPL and dev tools are also far better than almost anything outside of Common Lisp.

As a former Lisper turned JS/TS apologist for practicality, I have to ask--

Et tu, Brute??

Whoops, they beat me to it. Super nice, I hope it gets very well received by all people interested in FP.

Javascript is eating the world. Only WASM can save us now.

JS isn't just popular because of the browser.

It has a TON of syntactit niceties today. Most of the warts are no longer relevant (here's to a future "use strict 2" mode that eliminates the really bad type coercion bits).

It hits a very pragmatic center where you can do OOP, but top-level functions are also possible (looking at you Java).

JS also has good functions. Closures that don't require spelling everything out, first-class functions that can be passed around to other functions, anonymous functions, etc. Outside of currying, it has almost everything you'd want functions to have. That's something sorely missing in languages like Python (lambdas), Ruby (proc/lambda/block mess), PHP (no implicit closures), Java (no first-class functions), etc.

WHAT? They skipped all the way from Lisp to JS? Why?

JS has always been a LISP in Algol clothing.

Only, you know, without List Processing. And seventeen things that test false. And all numbers being floating-point (except when optimized implementations fudgily pretend that small values are integers). And a switch statement that you have to put into a function in order to get a return value out of it (everything returns a value in Lisp). Maybe it's more of a Scheme in Algol clothing; not everything returns a value in Scheme.

And no tail-call recursion.

Actually Scheme is Algol in LISP clothing. I don’t know what that makes JavaScript.

There were some similarities, but I'd say Scheme is more different than similar.

Scheme is GC'd

Scheme is fundamentally based on functions rather than proceedures

Scheme functions are first-class

Scheme uses tail recursion in place of loops

Scheme uses CPS and continuations (even though that was no doubt a mistake)

Scheme has symbols and programs are composed of symbols.

Scheme makes use of macros pervasively (not even C-style preprocessors were in ALGOL)

Scheme has only expressions while ALGOL has statements.

A lot of surface-level API designs and names seem inspired by ALGOL, but the fundamental building blocks seem very different to me.

Scheme adapted lexical scoping and block structure from Algol 60. Lexical scoping was a major departure from LISP in 1970s. Call/CC was not in the original Scheme. Probably added in R4RS. Macros came later too. My point was that calling JS Scheme in Algol clothing even less valid than calling Scheme Algol in LISP clothing!

I never read this book during my education. Would you all say there’s something to be gleaned from reading this as an engineer with some years of experience already, or is it primarily an introduction to programming?

If you are already a programmer and mostly want to check it out for ideas and concepts, you're better off with the Scheme version. The book itself is not 'primarily an introduction to programming', at least not in the conventional sense.

It is introduction to programming like no other. It takes it to a whole new level. Mind you, it is not about software engineering just about how to solve problems with algos. It used to be in LISP (Scheme if i am not mistaken) and now they have a JS version.

I have a copy of SICP right next to me, and it's one of my favorite computer science books. I'm not sure how I feel about this javascript edition though...

I was doing some Javascript coding today.


   false != x
test failed for a zero-valued x; had to make it !==. WTF? I never want false and 0 to be other than different objects.

Almost every twist and turn in this language is an imbecillic clusterfuck.

I had one instance of a if (foo.bar = 0) typo; no warning from the implementation. Why do we want stupid C mistakes in a higher level language, without the C fixes for them?

   list.forEach(function (item, i) {
makes my eyes bleed. JavasSript borrows the syntax of languages geared toward a form of computing at which JavaScript is poorly suited for; when you're combining functions together, it looks like dog's breakfast.

To get a value out of a switch statement, you have to wrap it in a function that is immediately called?

   function () {
     switch (WTF) {
the switch statement has the idiotic break with fallthrough found in C.

One redeeming feature: A || B || C ... works a lot like (or A B C ...).

Unfortunately, this is required for the simple task of incrementing a nonexistent dictionary key from zero:

    dict[key] = (dict[key] || 0) + 1;
this calls for two dictionary key lookups. You want this sort of thing in a single operation.

Oops! In the following, j isn't lexical:

    for (let i = 0, j = 0; ....
I copy and pasted something like this from a StackOveflow answer into a recursive function and spotted that the j in a recursed frame was messing with the j in outer frames, there just being one j.

What is "function scope" and why even have something so idiotic? Just let, or GTFO! C has function scope for goto labels, that's it; why introduce something like that.

Appending together Lists has functional semantics, like Lisp:

   a.concatenate(b)  // new thing is returned, a stays the same, so you must do a = a.concatenate(b).

   a.push(b)         // mutates a in place.
Here is a shitshow, curently with a fitting number of upvotes: 666.


I accidentally wrote

   if (foo.bar.indexOf[key] < 0) { code }
code was silently skipped even though foo.bar is an empty list. No diagnostic, nothing. Oh, indexOf is a function, which is an object. Every damned object is a dictionary with properties you can access as strings with square bracket indexing, and that is always safe: it yields undefined if the property is not found.

I feel your pain, but these mostly fall into the same category of frustrations you'd get when doing something like switching operating systems, e.g. going from Windows to Mac or vice versa. You run into all kinds of things that seem stupid and you're bombarded with things that should "just work" and seem not to.

But, they disappear and are mostly non-issues once you use the alternate system/language regularly for a while. Some I think you will come to see as benefits, sensible, or find that there are trivial workarounds.

One quick improvement. The more commonly used contemporary syntax in JS for something like your list.forEach example is: `list.forEach((item, i) => ...)` —writing out the full `function` keyword is indeed an eyesore :)

> Oops! In the following, j isn't lexical:

I don't think I'm correct here. However, be that as it may, in my code, when I moved that second variable before the loop and initialized it there with a let, the behavior somehow changed.

Not to minimize these problems but typescript eases a lot of them.

Once you learn the quirks of JavaScript you get used to it. Also you should not use forEach in JS, take a quick look at this page. https://phoenix35.js.org/good-practices.html

If forEach is not to be used, it should be deprecated and removed from the language in a timely manner.

The objection that it's not functional is invalid; procedural traversal with a callback function, object or closure, is a time-honored pattern in software.

Most of the other problems cited are not with forEach per se but the language in which forEach finds itself.

None of the alternatives presented are more attractive than

  for (let i = 0; i < obj.length; i++) {
    let elem = obj[i];

If we could just run this through the C preprocessor, we could have

  foreach (i, elem, obj) {

by way of something like:

  #define foreach(ivar, elvar, obj) \
    for (let ivar = 0, elvar; \
         ivar < obj.length && (elvar = obj[ivar], true); \
Since Javascript is based on C syntax, it should have the preprocessor that the birthplace of C saw it fit for that language not to be without.

> If forEach is not to be used

That source is simply incorrect. forEach is perfectly fine to use as long as you realize what is happening. It iterates an array where each thing is a function that returns a promise. Of course the results aren't what they expect.

ES5 array additions suffer from being a little too early (though later stuff wouldn't exist otherwise, so...). They are designed to deal with holey arrays (arrays with indexes missing). This is extremely uncommon today, but was decently common once upon a time. They were also created before the iterator protocol.

The real fix is to design iterator versions that can handle things like async generator functions.

> it should be deprecated and removed from the language in a timely manner.

NOTHING can be removed from the language once added. Doing that would break all the older websites that depend on it (technically, a few minor breaks happened after they tested millions of sites and couldn't find anything that was adversely affected). At best, they can block older features from newer features. For example, using class syntax or a bunch of other ES6 language structures automatically makes your code shift into "use strict" mode.

I hope they introduce a "use strict 2" variant that strips away more of the undesirable features than the current "use strict" does.

> Since Javascript is based on C syntax, it should have the preprocessor that the birthplace of C saw it fit for that language not to be without.

That pre-processor was a source of untold nightmares. Direct injection leads to bugs. If someone is going that route, full-blown macros are the only answer. There is a full-blown macro system Mozilla created a few years ago, but it's not very popular.


There also exist some C-style pre-processors for babel too, but they should be avoided because lisp's gensym is a critical feature that they and C both lack.

Some of this is a lack of familiarity. You wouldn't dream of using C without reading a book first. You wouldn't dream of tackling a Java project without reading on the topic. You wouldn't even dream of trying something as simple as Python without a bunch of reading.

Why do you try to code JS without reading about the language? It's the only language where people consistently try this kind of thing.

> false != x

Referential equality operator is `!==` (which isn't so different from lisp where you have eq, eql, equal, string=, etc). Fun fact: Eich didn't have type coersion in the language at first. It was added at the insistence of developers (something he regrets, but Microsoft forced this to stay in the spec)

> function () { switch (WTF) { } }();

A lot of languages don't make switch statements into expressions. The fact that JS can do this via a function while most other popular languages cannot do it at all is a benefit if anything (there is a proposal to allow these to be expressions). More generally, prefer this

    let foo
    switch (abc) {
      case "blah":
        foo = 123
> the switch statement has the idiotic break with fallthrough found in C.

It actually gets this from Java. Eich was told to make the language look like Java and he did.

> dict[key] = (dict[key] || 0) + 1;

Your code is potentially bad. `||` uses "falsey" values. If the key is zero, the left-hand side will return false forcing the right-hand side. Use `dict[key] ?? 0` instead as it will only return the right-hand side if the left side is `undefined` or `null`.

If it is a pure dictionary, you are using the wrong construct too. Use `Map` instead

    let dict = new Map()
    dict.set((dict.get(key) ?? 0) + 1)
> this calls for two dictionary key lookups. You want this sort of thing in a single operation.

You get a value rather than a reference. I believe the JIT can optimize this pattern. If you are really fixated on using a reference, store an object with a value instead so you can grab and keep an object reference.

> What is "function scope" and why even have something so idiotic?

In lisp, you'd use `(let ((foo 123)) (print foo))` to set an explicit scope. ES4 proposal had a let block which I think would have been a better idea than the current stuff. Function hoisting generally occurs in other languages one way or another, but is hidden from the user.

> for (let i = 0, j = 0; ....

Yep, this is one more reason why the correct fix was a let block with `let (i=0, j=0) for (; ...)` or 1et for (var i=0, j=0...`

> Appending together Lists has functional semantics, like Lisp:

Array.prototype.concat goes back to at least the ES3 spec as does Array.prototype.push. At the time, arrays were either implemented as hashtables or linked lists. My guess is that adding a single entry to the hashtable only occasionally caused a resize while concatenating N lists was almost guaranteed to do so. I think they decided that it was easier for implementors to just create a new reference.

Since ES5, most new array APIs have favored returning new lists for everything. I think there's a case for making new versions of those older APIs that behave immutably.

> if (foo.bar.indexOf[key] < 0) { code }

This could happen in any language with a methodNotFound handler. For what it's worth, `if (foo.bar.contains(key)) {code}` would be the better way of writing it. I think Typescript would also catch this (though I'm not 100% as I don't remember ever having made that particular mistake).

> Every damned object is a dictionary with properties you can access as strings with square bracket indexing, and that is always safe: it yields undefined if the property is not found.

Garbage In; Garbage Out. At least it handles that garbage in a safe manner. What more could you ask from a dynamic language?

> Why do you try to code JS without reading about the language?

Because it's painful drivel.

> Your code is potentially bad. `||` uses "falsey" values

We know that this dictionary will only contain things to which we will be adding 1, which we expect to be numerically done.

(I have already made the point that there shouldn't be multiple falsey values.)

I mean, there could be other problems in this direction: if a string is in there like "foo", then the + operation will make it "foo1".

It's unlikely we would ever want to code a "add 1 to dictionary element, treating non-existence as zero" which will work for absolutely any dictionary regardless of knowing/assuming anything about its content.

> This could happen in any language with a methodNotFound handler.

Only if you define that handler, and have it silently return.

Handlers for method not found are a very poor idea to include in an object system. Ruby and its ilk uses it for ugly, monkey patched solutions for this and that.

I will preface this with, "I absolutely love SICP", but I think there are better places to go for everything it teaches. In terms of breadth and information per page ratio there's almost nothing better though.

- For how to actually program: How to Design Programs [1]

- For how to write programming languages: Essentials of Programming Languages [2]

- For how computers actually work: The Elements of Computing Systems (nand2tetris) [3]

I am a huge fan of How to Design Programs. It does a better, more thorough job of teaching the "core skill" of programming SICP or anything else I've come across. Its text is better paced (although very long), more approachable, and more focused on teaching how to program (as the name suggests). On top of that it has an absolutely massive number of exercises that do not require an interest in basic number theory to enjoy.

You will know how to actually solve new problems with programming when you finish HtDP (or are even part way through).

The really interesting parts of SICP are the 4th and 5th chapters any way right? Well, Ch. 4 (about "metalinguistic abstraction" or how to modify your interpreter to give your language different properties) is incredibly densely packed with information. It covers an interpreter for all of this in about 100 pages:

- lazy evaluation by default

- nondeterminism

  - aka search as a language primitive

  - the basics of continuations (but not accessible to the user)
- propositional logic

  - aka declarative (what is) vs imperative (how to) programming
It's a great appetite whetter, but it'll leave you wanting more.

If this stuff interests you Essentials of Programming Languages is a much better resource. It follows a similar style to the approach in SICP. You are walked through building interpreters for increasingly more complicated languages. Here are some brief descriptions of some of features you'll learn to add to the LET language (a very simple purely functional language that serves as the core, you'll also write this too):

- Mutually recursive procedures

- Static code transformation to use lexical addressing

- Mutation (and how to perform call-by-value, call-by-ref, and call-by-need languages)

- Continuation-passing vs Environment-passing interpreters

- Advanced control structures like exceptions and threads

- Static types and type inference

- Typed modules (I've not seen any other introductory text do this)

- Object-orientation

It contains a plethora of great exercises that ask you to extend the languages in interesting ways or to reflect more realistic demands of a language.

For chapter 5, Register Machines, I think we all know that the first half of Elements of Computing Systems (colloquially nand2tetris) is a great resource for that. The second half is excellent as well, but it's outside of the SICP scope.


;; Page Count 1374 = (+ 792 410 (/ 344 2))

In total I just recommended 1374 pages to replace 657 pages in SICP, so it's double the effort. And to be honest, if you're motivated enough to read all that then, you'll probably still read SICP if for nothing else than historical interest. If you start with SICP though, you'll still get a lot out of all the recommendations though!

[1] HtDP: http://htdp.org/2021-11-15/Book/index.html

[2] EoPL: https://eopl3.com/

[3] nand2tetris: https://www.nand2tetris.org/

I feel so conflicted about this.

I think Racket Edition would be more faithful to original SICP spirit.

JavaScript should be enough Lisp for everybody. Fite me.

SICP is a scheme course. If you want to experience SICP, why compromise? If you learned JS, you can learn scheme.

Reusing the SICP name is just a marketing tactic to sell something different and probably less special.


He had a copy of SICP on his shelf.

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