Show HN: OtterLang – Pythonic scripting language that compiles to native code

2 days ago (github.com)

Hey HN! I’ve been building OtterLang, a small experimental scripting language designed to feel like Python but compile down to native binaries through LLVM.

The goal isn’t to reinvent Python or Rust, but to find a middle ground between them:

Python-like readability and syntax Rust-level performance and type safety Fast builds and transparent Rust FFI (you can directly import Rust crates without writing bindings)

OtterLang is still early and very experimental. the compiler, runtime, and FFI bridge are being rewritten frequently.

Please star the repo, and contribute to help this project.

> Python-like readability and...

Some thoughts on the syntax, naming etc.:

      fmt.println("Point: (" + stringify(p.x) + ", " + stringify(p.y) + "), distance: " + stringify(dist))

* A "fmt" (presumably "format") package is not where I would expect to find a send-to-stdout function. I'd expect that in "io", and I'd expect "fmt" to provide helpers for actually creating the string to output. (Which would be that much more necessary here, since I assume you don't intend to emulate anything like all the bells and whistles of Python's built-in `print`)

* I don't know where `stringify` is supposed to come from. But the Pythonic way is that you just call the `str` type/constructor. That seems at least as doable as a `stringify` function; either way you're presumably stuck with static overloads for built-in types. (It doesn't look like you plan on supporting a protocol for user-defined type conversions?)

* Putting a string together like this is really unpleasant. I'd advise looking into the new template strings in Python (https://peps.python.org/pep-0750/); they form a solid basis for all kinds of other formatting. The important work is done at compile time; it generates code to create an object using current variable values, packing them for later formatting. For type-safety reasons I suppose the interpolated values have to be coerced to string at compile-time as well, but storing the values this way allows for choosing a different algorithm for assembling the final string (e.g., one that does quoting and escaping for some particular environment).

I could imagine having something like

  use otter:fmt
  use otter:io

  # ...

  io.println(fmt.format(t"Point: ({p.x}, {p.y}), distance: {dist}"))

where the t-string gets converted at compile time to something like

  fmt.Template(["Point: (", str(p.x), ", ", str(p.y), ", distance: ", str(dist), ""])

(Empty strings are preserved in the sequence so that formatting code knows what was literal and what came from an interpolated value.)

Of course, if you have other approaches in mind for things like type-safe SQL query generation, this could be simplified by just producing the string concatenation directly and avoiding the need for a separate formatter function etc.

Made just for fun or any issues with other languages that it tries to solve? You say "scripting language that compiles". That mean it has fast compilation and meant to use a "$lang run" shebang similar to Nim/Go/etc?