top | item 43514915

The Koto Programming Language

214 points| virtualritz | 11 months ago |koto.dev

149 comments

order
[+] chaosprint|11 months ago|reply
Should compare with Rhai (https://rhai.rs/)

I found rhai's syntax very straightforward, and I could almost accomplish my needs just by looking at some basic examples.

I use Rhai in wasm, and it can handle real-time audio blocks, which is really impressive:

https://glicol.org/tour#meta2

[+] nine_k|11 months ago|reply
Rhai looks somehow more OO, and is somehow conceptually bigger, with function overloading, operator overloading, currying, etc. Koto looks more like FP an stream processing, with pervasive anonymous functions, very simple data structures, and an emphasis on iterators.

Rhai also offers some safety guarantees: no panics, no stack overflows, etc. Rhai seemingly requires slightly less ceremony when interfacing with Rust: direct use of many things, as opposed to implementing a trait to interact with Koto.

(Disclaimer: I spent 5 minutes skimming the docs of each.)

[+] spacechild1|11 months ago|reply
Isn't Rhai extremely slow? The website itself says that it's roughly 2x slower than Python3: https://rhai.rs/book/about/benchmarks.html. Apparently, Rhai doesn't even compile to bytecode and instead walks the AST! This doesn't sound like a language I would pick as for DSP...

On the other hand, you can always write your own Rhai interpreter if necessary. And if you restrict the language to a limited set of features, which you need to do anyway to keep it realtime-safe, you could even compile it to native code.

> and it can handle real-time audio blocks, which is really impressive:

Any scripting language can do this as long as you stick to operations that don't cause memory allocations, system calls or other non-realtime-safe operations.

For example, you can use Lua to write process functions for Pd objects: https://agraef.github.io/pd-lua/tutorial/pd-lua-intro.html#s...

The question is rather how much you can do in a given audio callback.

---

All that being said, Glicol is very cool!

[+] 0x3444ac53|11 months ago|reply
I looked into Rhai but was disappointed that it doesn't have first class functions.
[+] irh|11 months ago|reply
Koto creator here, nice surprise to see this on HN so I'm a bit late to the discussion. Happy to answer any questions!
[+] riidom|11 months ago|reply
Would you say Koto (or some direct competitors, for that matter), is viable to learn when I otherwise don't intend to learn Rust at all? But let's say, want to keep the option open to participate in Rust-based projects which support Koto et al.?
[+] epage|11 months ago|reply
What are your plans for language and in-language library compatibility?
[+] mostafah|11 months ago|reply
Very cool. I really like the idea of implementing higher level features as extensions on top of a smaller core. I wish real scripting languages like this were more common and in use. Lua comes to mind when thinking about a generic scripting language, but even that is not that widespread.
[+] nine_k|11 months ago|reply
I think "implementing higher level features as extensions on top of a smaller core" is a hallmark of the Lisp family. Check out Fennel [0] or Janet [1] for two different approaches. On top of everything, Fennel is 100% Lua-compatible.

[0]: https://fennel-lang.org/

[1]: https://janet-lang.org/

[+] tzury|11 months ago|reply
Interesting.

At the time we did it with Lua.

We extended Nginx and Envoy-proxy with a Rust library (and a server), and added a Lua interface, so users can further tweak the config and the flow.

https://github.com/zuriby/curiefense/tree/main/curiefense/cu...

[+] benwilber0|11 months ago|reply
I've used OpenResty extensively which is basically just nginx + luajit with a lot of additional APIs and features. The nginx-lua-module is available separately from the OpenResty distribution of nginx, so you can just install and run it as a dynamic nginx module.
[+] aerzen|11 months ago|reply
Recently I've started evaluating new languages in terms of "how difficult would it be to read working code in this language, written by an insane person".

After looking at this for 5 minutes it seems it is better than rhai according to my metric. But not necessarily better than lua.

[+] account-5|11 months ago|reply
If I was going to chose a scripting language for rust I'd pick nushell's syntax. Nushell is an amazing shell and it's syntax is one of the reasons why.
[+] mentalgear|11 months ago|reply
> Syntax: [...] minimizing visual distractions, while also managing to avoid inexpressive terseness.

Nice! Now, if it only had type support.

[+] pansa2|11 months ago|reply
It says Coffeescript and Moonscript influenced Koto's syntax, which is a little worrying. IMO those languages are a little too flexible and sail too close to ambiguity - very small changes to code can sometimes radically change its meaning.

Edit: Sure enough, "whitespace is important in Koto, and because of optional parentheses, `f(1, 2)` is not the same as `f (1, 2)`. The former is parsed as a call to f with two arguments, whereas the latter is a call to f with a tuple as the single argument."

[+] iTokio|11 months ago|reply
It has optional types
[+] shahriarhus|11 months ago|reply
It's reminds me of Lua for C++, am I correct?
[+] irh|11 months ago|reply
Yes, I was missing a 'companion language' for Rust similar to Lua for C and C++, I tried Lua bindings and other Rusty scripting languages but felt like starting a new project would be worthwhile.
[+] f18m|11 months ago|reply
Is this the equivalent of Lua for Rust?
[+] irh|11 months ago|reply
Yes that's essentially where it started, although it feels quite different to use now.
[+] fstarship|11 months ago|reply
It seems every scripting language does duck/dynamic typing (as far as I can tell this applies to Koto).

I don’t understand why… inferred typing is nearly as easy to use while being more robust.

For me the biggest gap in programming languages is a rust like language with a garbage collector, instead of a borrow checker.

Rust has a lot of features that should be strongly considered for the next generation of programming languages such as

result/sum types

Inferred typing

Not object oriented or overly prescriptive with functional programming.

I think the closest language to filling that gap is occaml (I am not familiar with it).

I have coworker's that are more skilled in domain logic that can write basic self contained programs, but stuff like traits, OOP functional programming is a bridge too far.

I feel like a language that fills that gap could be useful, context is a manufacturing ERP system.

[+] ossopite|11 months ago|reply
I think you really are describing ocaml, which is a great language, although its ecosystem isn't the best. It probably inspired most of the features you mentioned in rust. It also supports OOP (hence the O) but it's easy to avoid.

That said, I wouldn't compare it to scripting languages. The lack of implicit conversions / traits / ad-hoc polymorphism means it's not that convenient for scripting.

[+] pansa2|11 months ago|reply
> It seems every scripting language does duck/dynamic typing (as far as I can tell this applies to Koto).

It looks like Koto supports type hints - not sure if these are checked at compile-time, run-time, or both.

> I don’t understand why… inferred typing is nearly as easy to use while being more robust.

Is it (nearly as easy to use)? Every static type system seems to have special cases and exceptions which are avoided by dynamic typing. I'd love to find one that's actually simple.

Also, it's definitely not nearly as easy to implement - which is important for a language being designed and built by a small team and targeting a lightweight runtime.

[+] sparkie|11 months ago|reply
> I don’t understand why…

Because dynamic typing has its own advantages, which are worthy of experimentation even if you perceive absence of static typing as a weakness.

Gradual typing can offer us the benefits of both worlds.

> inferred typing is nearly as easy to use while being more robust.

Implementing type inference can be fairly trivial if your types are all disjoint. Hindley-Milner type inference is well studied and there's plenty of literature.

But as soon as you introduce subtyping, the traditional methods are not sufficient. It's only in the past decade that good solutions have been discovered, notably Dolan & Mycroft's MLsub[1], based on Dolan's Algebriac Subtyping thesis[2], and Parreaux & Chau's MLstruct[3], which uses a boolean algebra approach[4]. Type inference with subtyping is not a solved problem - these developments are big steps forward, but there are still open problems under research.

Subtyping doesn't imply object-oriented. Structural typing (ie "static duck typing") is a form of subtyping.

[1]:https://github.com/stedolan/mlsub

[2]:https://www.cs.tufts.edu/~nr/cs257/archive/stephen-dolan/the...

[3]:https://github.com/hkust-taco/mlstruct

[4]:https://dl.acm.org/doi/pdf/10.1145/3563304

[+] zozbot234|11 months ago|reply
Rust will probably gain support for "pluggable" and optional garbage collectors as part of its upcoming local allocators API. This will ultimately give devs the best of both choices - use tracing GC where it's actually needed (because you're working with totally general graph-like data and that's the only feasible memory management strategy) and manual memory management (supplemented by RAII and reference counting) elsewhere - for other parts of the program that don't have to manage general "spaghetti" graphs. Unfortunately the way GC's trace objects and collect garbage varies wildly among implementations, so there's no easy way to standardize a "generic" interface to pluggable garbage collection, that all custom crates might be expected to tap into by default. But other uses should be quite feasible.
[+] rTX5CMRXIfFG|11 months ago|reply
I'm not sure what you're getting at here but none of the features you mentioned are groundbreaking anymore? At least in Swift:

result/sum types = enums whose cases have associated values

inferred typing = Swift "type inference"

Not object oriented or overly prescriptive with functional programming. = Uh, yes

Those features map to Kotlin too

[+] teleforce|11 months ago|reply
>For me the biggest gap in programming languages is a rust like language with a garbage collector, instead of a borrow checker.

I cannot agree more that's the much needed sweet spot/Goldilock/etc. Personally I have been advocating this approach for some times. Apparently the language is already widely available and currently has stable and wide compiler support including the venerable GNU compiler suite (GDC). It also one of the fastest, if not the fastest programming in existence for both compilation and execution [1].

It has been beating Fortran in its number crunching territory, no small feat given the Fortran pedigree with many languages still depending on Fortran based infrastructure for their number crunching capabilities including Matlab, Julia, Rust, Go, C, C++, etc [2].

It also has a nice bulti-in REPL system due to its very fast compilation and execution [3].

For an excellent overview of D programming language please check this presentation at ACCU conference [4].

[1] D website:

https://dlang.org/

[2] Numeric age for D: Mir GLAS is faster than OpenBLAS and Eigen:

http://blog.mir.dlang.io/glas/benchmark/openblas/2016/09/23/...

[3] Why I use the D programming language for scripting (2021):

https://news.ycombinator.com/item?id=36928485

[4] How DLang Improves my Modern C++ and Vice Versa - Mike Shah - ACCU 2024:

https://youtu.be/CnKsOak0DHU

[+] nine_k|11 months ago|reply
The point of many scripting languages is quick tinkering, mucking with stuff in a REPL, on top of a complex contraption of already-live objects. This works well with duck typing. It does not work with nice static type inference, because once you change something high upstream, it potentially invalidates everything downstream, your entire current session you've spent an hour building.

"Everything should be built top-down, except for the first time" (See #15 in https://www.cs.yale.edu/homes/perlis-alan/quotes.html)

[+] letmeinhere|11 months ago|reply
For one thing, inferred types may feel easy to use when implemented (well) but they are not easy to implement.
[+] IshKebab|11 months ago|reply
I totally agree. I think it's simply because most of these projects are pretty much one-man efforts and implementing static typing is a lot more effort than dynamic typing.
[+] seivan|11 months ago|reply
The documentation and integration with Rust for this amazing, well done! Like other commenters, I also wish it had better static typing and looked more like Elixir with anonymous sum types and template literal types.
[+] martin-t|11 months ago|reply
The amount of scripting languages _for Rust_ is a symptom of how Rust fails to satisfy the need to write code with less strict requirements.

It makes perfect sense to use Rust as the main language for your application but have areas which are either in the prototype stage, need to be written quicker or which simply don't need the performance. But Rust does not offer a way to enter such a less strict context and such proposals keep getting shot down by the community, even when they are made from core members of the Rust team.

Contrast that with C# which has a dynamic keyword, allows enabling a checked context (not just in code where you can't miss it but also from csproj), has reflection, etc.

I really want Rust to succeed but sometimes the attitude borders on zealotry.