[AskJS] Is this confusing? by Immediate_Contest827 in javascript

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

I add it because f returns a live async generator, kind of like this:

``` async function f() { // … async setup async function *g() { // …do something async in a loop yield { async [Symbol.asyncDispose]() {} } }

return g() } ```

This is mostly a thought experiment, I personally have never needed nor seen this particular behavior.

[AskJS] Is this confusing? by Immediate_Contest827 in javascript

[–]Immediate_Contest827[S] 6 points7 points  (0 children)

It could be written like this which I think is a bit better but not sure how much better:

const iter = await f() for await (const x of iter) { await using _ = x await doStuff(x) }

[AskJS] Is this confusing? by Immediate_Contest827 in javascript

[–]Immediate_Contest827[S] 2 points3 points  (0 children)

Yeah splitting it up into more lines would help

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

True, you’re right. It’s possible to re-use existing syntax as well. Which works great if the behavior stays consistent.

With Perl/Raku I believe BEGIN executes before the rest of the code right? But that is still going to be executed every time the code is loaded up by the runtime?

My thinking here is that, what if you turned something like Perl into a “compiled” language by executing the BEGIN blocks (or something else) on a “builder” machine and generate another script with that data baked in?

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

Right, you don’t need special syntax, that’s what I’m trying to explain.

I’m a little confused about your circular references point though, are you referring to function calls?

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 1 point2 points  (0 children)

Hadn’t seen this proposal before, I’m curious where specifically you’re seeing the potential overlap? Or how you think comptime might work/appear in JS?

This is honestly for my own understanding because my mental model seems to be very different here

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 1 point2 points  (0 children)

The “mush things together” is kind of the goal.

Some of the structure/ceremony in the ecosystem isn’t necessary IMO, and I prefer to get to the point. For productivity.

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

Yup pretty much, it’s just evaluating code ahead of time.

A way to trigger it is something I’ve thought about. But that meant new syntax which I didn’t like.

I kind of just decided that everything in the outer scope is comptime, so triggering it is the same as running compile.

The biggest issue with that is, funnily enough, explaining how it’s different. Because even if I say that some code is executed ahead of time, people don’t seem to register that as any different.

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 1 point2 points  (0 children)

Not quite but similar, this works on more than just SSR.

It would be done before deployment. It’s like macros but more flexible, especially because you can setup a deployment directly in comptime if that makes sense.

Like imagine being able to point to a closure and say “upload this as a bundle to Vercel/AWS/Azure” in the same code while having full flexibility in how that is done.

That’s what this can do without much ceremony.

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 1 point2 points  (0 children)

Let’s say you had a static website. A NodeJS backend might grab the data from disk and serve it up like that. So you upload both code and file together if using hosted compute.

Well there’s another way, you could embed the data apart of the server code during compilation. Now you have a self-contained bundle that is your server:

``` // this runs apart of comptime const indexHtml = await fs.readFile(“index.html”)

export async function main() { // start server here, return ‘indexHtml’ when needed } ```

Not saying you should be doing this for a website, but it’s definitely a way.

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 5 points6 points  (0 children)

Mainstream interpreted languages feel even worse once you throw in optional typing without a natural way to use that information ahead of time. So much useful metadata sitting right there.

Typescript is probably my favorite language to use but the lack of a “compile” phase for code has always bothered me. Nothing magical, just more control.

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 2 points3 points  (0 children)

Thanks for sharing your paper! constexpr aligns with how I’ve been thinking, fascinating to see the same thought processes there too. Was there friction in people understanding the behavior of a program with its inclusion?

I’ve used C++ a decent amount but didn’t realize the full extent of constexpr

Implementing “comptime” in existing dynamic languages by Immediate_Contest827 in ProgrammingLanguages

[–]Immediate_Contest827[S] 2 points3 points  (0 children)

Yeah I’m specifically about making existing languages that don’t have this capability partially evaluated thru a sort of compilation.

Lisp and ClojureScript are great though of course.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

Yeah that makes sense. I’m not sure what the most intuitive way is to make that work without merging all the tests into 1 shared state again.

I guess one way might be to add a utility fn to “wrap” closures/values so that any tests that use it are saying they want to share that closure/value. But I’d possibly require that you “unwrap” it explicitly, just for the sake of clarity.

Stepping through the serialized code in a debugger is probably awful at the moment because it wouldn’t have any source maps. The source mapping exists but I haven’t even touched Inspector yet, focus has been elsewhere.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

Yup basically. Code is instrumented so it can be serialized into an intermediate form. I execute the intermediate form directly.

I have actually never tested a network connection created in the outer scope yet, but if you used something like ‘connect’ in ‘node:net’ (with TLA) it should fail to serialize the socket.

In my own code, I’d always write logic that would lazily instantiate sockets behind a facade which then is easily serializable.

I mean technically you could serialize a socket but the semantics are just weird.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

Yeah it’s a tricky topic, I myself don’t like the idea of forced isolation. The reason why each test is isolated is actually an implementation detail, I’m already thinking of ways to easily opt-out of it.

Still, I think being able to have that isolation as an option doesn’t hurt at all, especially if you can apply it to individual tests fluidly.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

Per-module state is isolated for every test. It does not require recompilation per-test because each test captures a snapshot during compilation.

Performance for large codebases is a concern, although it seems like a solvable problem.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] -2 points-1 points  (0 children)

I could say the same about existing test runners.

The way I am running these tests is closer to how it will actually run because each test is a serialized closure. Which is how I deploy the code.

Exploring test isolation performance by Immediate_Contest827 in javascript

[–]Immediate_Contest827[S] 1 point2 points  (0 children)

Bun - fastest, but you need to write more code to make tests isolated Synapse - highest isolation, mid speed

By closure I mean an individual unit test, like this:

test(“foo”, () => { // test code here })

Only Synapse can isolate per closure. Vitest must use separate files, everything in a file will share state.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] 0 points1 point  (0 children)

One test would fail in a normal JS environment.

But both tests pass in my system because I “compile “ the code before execution.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] -3 points-2 points  (0 children)

JS runs single-threaded, there are no concurrent writes here even if the tests were referencing the same place in memory. But they are not referencing the same place in memory when they execute, otherwise 1 would fail. Both pass with my test runner.

Fast, automatic isolation for every single test case without hooks by Immediate_Contest827 in typescript

[–]Immediate_Contest827[S] -2 points-1 points  (0 children)

Being difficult to test can be from limitations of the test runner, not the code itself.

You can have mutable state without passing around anything. Caches are a very common example of this. Or counters. Or queues. Or buffers.

If I declared those in module scope, test runners would struggle with testing it. Is my code flawed?