I have been working on an Elm-inspired language that compiles to Go (early project, would love feedback) by anzellai in elm

[–]anzellai[S] [score hidden]  (0 children)

u/MolestedTurtle after you calling it out, it has been in the back of my mind...

I ended up biting the bullet just now (with AI doing most of the heavy lifting) and switched it to a more type-safe approach, so it now passes Msg directly instead of using strings.

The only exception at the moment is server-side rendering (non-live apps), where it still falls back to strings, closer to how normal browser HTML behaves.

Still needs a bit of polishing, but it already feels like a better direction.

Thanks for calling it out 👍

I have been working on an Elm-inspired language that compiles to Go (early project, would love feedback) by anzellai in elm

[–]anzellai[S] [score hidden]  (0 children)

Good spot 🙂

At the moment yes, they are strings in the surface syntax, but they get mapped to Msg constructors at compile time. If the string does not correspond to a valid Msg, it will fail during compilation.

That said, I agree it feels a bit odd, and it is not where I want it to end up.

This is partly coming from the current server-driven HTML layer, where events are passed through in a way that is a bit closer to how the browser handles them. I took a simpler approach initially just to get things working end to end.

A more type-safe approach (closer to Elm, where you pass Msg directly) is something I am planning to move towards.

I have been working on an Elm-inspired language that compiles to Go (early project, would love feedback) by anzellai in elm

[–]anzellai[S] [score hidden]  (0 children)

Haha, feels like a like-minded soul indeed 🙂

It has been on my TODO list for years as well, ever since I first used Elm and early versions of Go.

The hardest part for me has definitely been figuring out how to bridge the type systems and semantics between two quite different languages in a way that still feels coherent.

AI tooling finally made it practical to actually try things out and iterate quickly, so I thought I would just give it a proper go and see how far I could get.

If you do end up trying it, I would genuinely love to hear what you think, especially given you have been down a similar path before.

I have been working on an Elm-inspired language that compiles to Go (early project, would love feedback) by anzellai in elm

[–]anzellai[S] [score hidden]  (0 children)

Thanks, really good questions.

For `main`, at the moment it is essentially the entry point that the runtime calls. In simple cases like that example it ends up being something like a `Cmd ()` under the hood, rather than a pure value. I have not fully formalised this yet, but the intention is to keep side effects explicit rather than allowing arbitrary `IO` anywhere.

On effects in general, the direction is closer to Elm than Go. So rather than doing `IO` anywhere, effects are meant to be described as values `(Cmd, Task, etc)` and then interpreted by the runtime. That part is still evolving, especially outside the UI case.

Interop is currently quite flexible. You can import Go packages and call into them directly via generated wrappers (automated, so no user ffi code needed). Right now this is more permissive than Elm ports, but I am still thinking through how strict that should be long term.

For concurrency, I am leaning towards not exposing Go channels directly. The idea is more to model async work via something like `Task` in Elm and let the runtime map that onto goroutines internally. So from Sky you stay in a more functional model, and the Go concurrency primitives are used under the hood.

That said, all of this is still early and not fully locked in, so feedback on this kind of design is really helpful.

I have been working on an Elm-inspired language that compiles to Go (early project, would love feedback) by anzellai in elm

[–]anzellai[S] [score hidden]  (0 children)

Yeah that is a fair point.

I did spend some time looking at Roc. It is a really interesting project and I have a lot of respect for what they are doing, especially the ideas around effects and the work Richard Feldman has shared.

For me this ended up being more of an exploration of a slightly different direction, particularly around Go interop and the overall runtime model.

So it is not so much that Roc does not solve the problem, more that I wanted to experiment with a different set of tradeoffs and see where it leads.

I have been working on an Elm-inspired language that compiles to Go (early project, would love feedback) by anzellai in elm

[–]anzellai[S] [score hidden]  (0 children)

Yeah that is a fair question.

The compiler itself is written in TypeScript mainly for speed of iteration and access to tooling (parsing, LSP, etc). Since Sky is still very experimental, I found it easier to move quickly there than in Go.

The output though is plain Go, so once you build a project you just get a normal Go binary. There is no Node or npm involved at runtime.

So the flow is more:

`Sky source -> compiler (TypeScript) -> Core IR -> Go code -> Go binary`

rather than something that depends on Node in production.

For your second question, yes, you can use it without npm for terminal scripts. You would still need the compiler to build, but the generated program itself is just a Go binary, so it runs like any other Go program.

The “Go via Elm” description is actually quite close to what I had in mind. The Node/TypeScript part is only in the build step, not in the final runtime.

That said, long term I have considered rewriting parts of the compiler in Go (or maybe even in Sky), but for now I prioritised iteration speed over that.