But I keep wondering if they could integrate at a lower-level than the source code. Like how JVM languages integrate at the bytecode level, or LLVM languages at the LLVM level
isUpperStart : String -> Bool
isUpperStart name =
case String.slice 0 1 name of
"A" ->
True
"B" ->
True
"C" ->
True
... for 23 more cases.
And the corresponding go code in the bootstrap compiler is even worse.edit: looking through the docs/examples some more, it looks like javascript interop is fairly clunky, both because it relies on string concatenation to embed fragments of javascript, and because the string concatenation syntax is not great (and the formatter makes it even worse - see the example at https://github.com/anzellai/sky/blob/main/examples/13-skysho...)
I would encourage you to at the least add multiline strings with interpolation support, and ideally add a small compiler for html literals.
Phoenix LiveView (the inspiration) defaults to using WebSockets because it's much more efficent, but falls back to Long polling if not available.
One thing that I don't see is a way to mitigate the "andThen" pyramid of doom.
This happens when you have a language without early returns and you have chain multiple Result returning operations. You can use nested case expressions:
case operation1 x of
Ok value -> case operation2 value of
Ok value2 -> value2
Err msg -> "error from operation2: " ++ msg
Err msg -> "error from operation1: " ++ msg
Or nested `andThen` calls operation1 x
>> mapError (\msg -> "error from operation1: " ++ msg)
>> `andThen` (\value -> operation2 value)
>> mapError (\msg -> "error from operation2: ++ msg)
This is nicer to read, but still a lot of noise.Haskell has `do` notation to alleviate this but that brings with it the type-class that shall not be named.
Some languages, like Rust, introduce different per-type syntactical solutions such as `async/await` for Promises and `?` for Result.
I particularly like Gleam's `use` notation, which is syntactical sugar around functions that take a callback as their final argument.
Do you have a solution for this in Sky?
I've never liked Go, but its strengths are absolutely compiling to single binaries, fast compile times, and concurrency primitives (not necessarily using them) etc. Compiling to Go is a great idea.
I am comparing this https://github.com/anzellai/sky#tea-architecture with this https://harcstack.org (my thing) ... guess I have some work to do ;-)
Have you seen Lamdera? They have a way to use Elm on the server-side that is supposedly acceptable to the Elm-BDFL Evan Czaplicki.
This talk explains it well: https://www.youtube.com/watch?v=4T6nZffnfzg
Sky does all on the server (more popular lately with HTMX and LiveView), where Elm+Lamdera is basically 2 project and Lamdera ties you into a propietary-ish ecosystem.
Now that you got foundation created, let's see how to move it forward.
But I'm curious to get your thoughts on the process in hindsight.
I understand why it's valuable: to cast a wide net in catching bugs and give a good signal that your language is generally "ready".
I'm working on a similar language, but worried about going down the self-hosting path, as I think it'd slow me down rather than speed me up.
How did it work for you?
> The compiler bootstraps through 3+ generations of self-compilation.
I guess it applies to any language compiler, but f you are self-hosting, you will naturally release binary packages. Please make sure you have enough support behind the project to setup secure build pipeline. As a user, we will never be able to see something even one nesting-level up.