You are browsing as a guest. Sign up (or log in) to start making projects!

No Let

  • 6 Devlogs
  • 28 Total hours

A JavaScript coding puzzle site where you aren't allowed to declare let variables or use anything with mutable state.

Ship #1

No Let is a JavaScript puzzle site where you have to use pure functional programming, which means that you aren't allowed to use let variables or anything else with mutable state.

I learned how to use QuickJS-emscripten, Prism code editor, and AcornJS, all of which are skills that I intend to reuse for later projects. I also learned a lot about pure functional programming itself while designing the puzzles.

I'm especially proud of how the linter/test messages smoothly animate in and out. The animation itself was just a simple slide transition with Svelte, but in order to make it work I had to refactor and unify the error message generation into one big array, which was unexpectedly difficult.

  • 6 devlogs
  • 28h
  • 18.96x multiplier
  • 499 Stardust
Try project → See source code →
Open comments for this post

3h 11m 47s logged

I wrote the README and also fixed a minor performance bug.

Because Prism code editor only initializes once Svelte finishes hydrating, there’s a delay of a few hundred milliseconds between when the page becomes visible and when the editor initializes. This caused a layout shift on each puzzle page, which was making Lighthouse take away a few points in the performance category. So I precalculated the height of each puzzle editor in advance and applied that minimum height to the placeholder text. This fixed the layout shift, so now Lighthouse gives the site perfect 100s in performance, best practices, and SEO, which is cool.

0
0
6
Open comments for this post

47m 12s logged

I just added some error handling for infinite loops and infinite recursion.

Before, if you wrote while (true) {} in the editor and pressed run, it would permanently lock up the UI and crash the browser tab. Now the logic test just interrupts the execution after 1000ms and fails your code for taking too long.

Likewise, if you wrote const r=()=>r();r(); and ran it, QuickJS would silently throw an uncaught error and the logic test would be stuck at “Waiting…” forever. Now it just instantly fails the code because it recurses too deeply and QuickJS can’t execute it.

I’m probably going to ship No Let soon, unless I have more puzzle ideas, find more bugs to patch, or think of more features to add.

0
0
3
Open comments for this post

3h 29m 25s logged

I spent the last 3.5 hours making a single puzzle. It’s the hardest puzzle yet and took the most time to create, and by a lot.

The puzzle is called Headcount, and it involves extracting a total count from a deeply-nested data object. I considered using nested arrays instead, but that would have a pretty trivial solution: return input.flat(Infinity).length. JS has far fewer built-in utilities for manipulating objects than it does for arrays, so I figured that using objects would pose more of a challenge, which I think it does.

You can play the new puzzle here: https://ethmarks.github.io/nolet/headcount.

0
0
6
Open comments for this post

1h 56m 21s logged

I added more puzzles and wrote a congrats page for users who finish the whole site.

The congrats page finally gave me the excuse to reference xkcd 1312, which I’d been dying to do since I started this project.

Next, I just need to make more puzzles. I have 4 so far, which I don’t think is nearly enough. Puzzle design is really hard though.

0
0
1
Open comments for this post

11h 27m 53s logged

I’ve made a lot of progress since my last devlog. I’d say that No Let is basically feature-complete now. All that’s left to do is adding polish and creating a bunch more puzzles.

You can try No Let right now at https://ethmarks.github.io/nolet/.

Here are some of the highlights of the changes in this devlog.

  • I added the Output.svelte component that runs the logic test and the linter and outputs their results into a human-readable HTML list. I also made it use Svelte’s slide transition, which required a lot of refactoring.
  • I made each puzzle a separate page. I was originally planning on making the site an SPA, but I decided that a MPA was probably a better fit. Because the puzzles are defined as classes and not as separate Svelte routes, I had to add a dynamic route. I’m using SvelteKit’s static adapter because I prefer static sites, but that meant that I had to tell SvelteKit which pages to prerender.
  • I added description text and suggested solutions for each puzzle. The descriptions provide instructions, tips, and flavor text, and the solutions should keep users from getting stuck or frustrated.

But most of the work I did has been refactors, fixes, and creating new puzzles.

0
0
2
Open comments for this post

6h 54m 18s logged

So my idea for this project is that it’s a JavaScript puzzle site which forces you to use pure functional programming, which means that you aren’t allowed to use let or anything else with mutable state.

Basically, pure functional programming says that you should never ever reassign variables after you declare them. Ever. Because you can’t reassign variables, you also can’t increment counters, which means that it’s impossible to use for loops. The same logic applies to while loops, and to a few other things. These extremely restrictive self-imposed limitations force you to do things the functional programming way, which involves lambda calculus, recursive functions, currying, etc.

I think that this project will have four main parts. I’ve been working on it for about 7 hours and I’ve made some good progress, but there’s still a lot to do.

  1. Running the user’s code and reading the result. I can just wrap quickjs-emscripten and remove a few built-in methods like Math.random() that are considered “impure” by functional programming because they’re non-deterministic.
  2. Linting the user’s code to check if it uses any banned syntax like let. I can use acornjs to parse the code into an AST, then applying a bunch of custom rules to it.
  3. Allowing the user to write their code. The conventional choice would be to use Monaco or CodeMirror, but they’re extremely heavy and I don’t like VSCode anyways, so I’m going with Prism code editor, which is much lighter and in my opinion nicer.
  4. Having puzzles for the user to complete. Each puzzle should have a test function that can check if the code logic is correct, and also should have some initial code that has correct logic but fails the linting because it uses let and whatnot.

Right now I have minimal versions of parts 1, 2, and 3. They do work (mostly), but they’re missing features and don’t integrate well with each other.

1
0
3

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…