8 ms·
The Koto Programming Language
- martin-t 2y agoThe 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.
- Sytten 2y agoWhat are you rambling about, this is a sanboxed scripting language to allow your users to define customization at runtime. This has nothing to do with rust, it could be written in C or C++. You would not run random user provided C# in your application at runtime. It is like saying browser should be coded in C# because C++ can't be use instead of JavaScript...
- 01HNNWZ0MV43FF 2y agoSince it's written in Rust, that's the easiest place to use the embedding API. https://koto.dev/docs/0.15/api/ https://koto.dev/docs/0.15/api/ I imagine one _could_ use it from C, but it wouldn't be as ergonomic as Lua's C API. And Lua in turn isn't a perfect match for embedding in Rust
- benwilber0 2y agoOr like saying that C++ was somehow deficient just because NodeJS had to be created in order to script v8.
- martin-t 2y agoIt literally says "for Rust applications" on its front page. Your tone is insulting and has no place in technical discussions.
- VWWHFSfQ 2y agoDescribing rust programmers as "zealots" also has no place in a technical discussion.
- Onavo 2y agoWe need LuaJIT in Rust.
- benwilber0 2y agoThis is already available as an optional Lua target in mlua [0]. I recently built a programmable server for Server-Sent Events scriptable with Lua [1]. I chose Lua 5.4, but it's trivial to switch it to LuaJIT, or really any other Lua derivative including Roblox Luau. It's just a matter of enabling the mlua feature you want. [0] https://github.com/mlua-rs/mlua https://github.com/mlua-rs/mlua [1] https://tinysse.com/ https://tinysse.com/
- Philpax 2y agoWhile I would like a Rust-like language that has those things, complaining that Rust, a compiled native language with no runtime whose closest competitor is C++, does not is a little strange to me. Yes, it is very multi-paradigm and can be used in many domains, but it's not trying to be C# and it can't be C#. I would love to see Rust# as a language, but Rust itself cannot be that language.
- martin-t 2y agoShould new languages artificially restrict themselves based on the restrictions of their main competitor even if it's possible to serve a wider range of usecases? Dynamic can be implemented in a compile-to-native lang. Contexts with different rules as well. Reflection support would likely have overhead which would need a granular opt in mechanism but is very likely possible. Similarly many features rust is missing like compile time reflection, field in traits, ...
- Philpax 2y ago> Should new languages artificially restrict themselves based on the restrictions of their main competitor even if it's possible to serve a wider range of usecases? Nope - and indeed, we're seeing Rust used in a more diverse set of applications than C++ (e.g. there are several Rust web frontend frameworks, it's a popular WASM language in general, etc) However, Rust is targeting the same kind of general constraints as C++ for development and deployment, which means it can't add anything that would depend on a runtime or impose an undue burden on users. (Of course, C++ cheats in this regard - RTTI and exceptions - but Rust matches that, and doesn't go beyond.) > Dynamic can be implemented in a compile-to-native lang. Requires runtime functionality, and it's not really clear what the resulting semantics would be, anyway: aside from the usual type-safety concerns, how do you deal with lifetimes and other compile-time constraints? > Contexts with different rules as well. What kind of different rules? The problem is that any deviation from the rules needs to be reconciled at some point, and that reconciliation has to be watertight: you can't weaken the guarantees somewhere that interacts with safe Rust code, because the weakness you've introduced can spread. This is already a pretty significant issue with unsafe Rust. Similarly, moving to a higher level of abstraction has similar issues: how do you reconcile the interactions of GC'd objects with the rest of Rust, which expects deterministic destruction and somewhat-predictable object lifetimes? > Reflection support would likely have overhead which would need a granular opt in mechanism but is very likely possible. If you're already committing to a granular opt-in mechanism, you might as well use a library, which offers you more options: https://docs.rs/bevy_reflect/latest/bevy_reflect/ https://docs.rs/bevy_reflect/latest/bevy_reflect/ > Similarly many features rust is missing like compile time reflection, field in traits, ... I'll give you compile-time reflection; that would have been quite nice to have, but the Rust Foundation alienated the primary person with a plan (https://thephd.dev/i-am-no-longer-speaking-at-rustconf-2023 https://thephd.dev/i-am-no-longer-speaking-at-rustconf-2023), so who knows when we'll see the next proposal? I agree that it's a shame, but there's usually ways to work around it (proc macros can be used to patch over a lot of Rust's relative deficiencies) Field-in-traits has been discussed before, but is complicated due to the borrow checker: https://internals.rust-lang.org/t/fields-in-traits/6933/1 https://internals.rust-lang.org/t/fields-in-traits/6933/1 In general, the borrow checker is the primary impediment to copying features from other languages; it's just generally non-trivial to fit them into the Rust paradigm without significant R&D. That's why I think a higher-level Rust would have to be a separate language, not an extension of Rust proper: resolving the collision of semantics between abstraction levels is just too difficult in the general case.
- jakkos 2y agoWould you be able to share examples of these "shot down proposals"? I personally haven't found Rust that difficult to prototype in, when I need to I just liberally use clone/Arc/RefCell. I see the main benefit of these scripting languages as being able to write/run code at runtime, e.g. live coding music or mods for video games.
- perrygeo 2y ago> I personally haven't found Rust that difficult to prototype in Rust is actually a pretty nice language for prototyping IMO. I agree with your take - Rust has many escape hatches you can use to develop quickly. Then when it comes time to clean up, it's obvious where the deficiencies are (look for all the clones and unwraps, etc) > I see the main benefit of these scripting languages as being able to write/run code at runtime Thank you. Some commenters seem to think a scripting language somehow reveals some deficiency in the core language. Reality: not all code is available at compile time. Many applications need some way to inject code without recompiling.
- martin-t 2y agoNiko Matsakis made a proposal on his blog for opt-in contexts with relaxed rules (such as implicit conversions) and it was hated, at least on reddit. I doubt he would delete it but i can't find it now.
- HKH2 2y agoMaybe I'm a zealot, but I use Rust-script with cmd_lib. Rust-script lets you define the libraries at the top of the file (instead of in a Cargo file) and cmd_lib gives you macros to call commands directly almost like in Bash. Then you can iterate over the output way faster than in Bash. It recompiles after any changes, and subsequent runs just call the compiled executable. The downside is that the cache does grow, but it's not that noticeable.
- jakkos 2y agoI really like the idea of rust-script but last time I looked there didn't seem to be a good way to get rust-analyzer to work when writing a script. Maybe I'm a little too reliant on LSPs but I find writing Rust painful without it, has the situation improved at all since?
- HKH2 2y agoNah, but that issue's to do with rust-analyzer looking for a Cargo file. Some people have apparently got around it by making a file. You're right that it would be great with full LSP support, but for quick scripting, I mostly just want a linter.
- hypeatei 2y ago> Contrast that with C# which has a dynamic keyword `dynamic` has a very narrow use-case and generally shouldn't be used at all (even when prototyping) I believe it was introduced to make working with poorly designed external libraries easier (e.g. Windows/Office libs)
- BiteCode_dev 2y agoI think it's just a convenient and popular language to experiment with. For production systems, people just use Python + Rust when needing a balance between dynamism and strictness. The tooling to mix them is very mature and the communities are overlapping. With uv becoming the defacto packaging solution for python, I expect the border to blur even more in the future.
- mostafah 2y agoVery 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 2y agoI 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/ https://fennel-lang.org/ [1]: https://janet-lang.org/ https://janet-lang.org/
- fstarship 2y agoIt 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.
- dustbunny 2y agoCheck out Wren. https://wren.io/ https://wren.io/ Written by Bob Nystrom, author of Crafting Interpretors.
- fstarship 2y agoThanks for your suggestion. At first glance it appears to be object oriented, which is against preference but not a deal breaker. However error case looks to be try catch which is a deal breaker.
- pansa2 2y ago> However error case looks to be try catch which is a deal breaker Wren uses coroutines ("fibers") for error handling, which is unusual. But yes, ultimately it does seem to be equivalent to try-catch.
- pansa2 2y agoWren is dynamically-typed, though
- sramsay 2y agoLast release was four years ago.
- brookritz 2y agoJabdah
- sagacity 2y agoStrange voice coming from the space!
- tzury 2y agoInteresting. 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/curieproxy/lua https://github.com/zuriby/curiefense/tree/main/curiefense/cu...
- benwilber0 2y agoI'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.
- tzury 2y agoIndeed, OpenResty comes with Lua and LuaJIT built-in. Earlier version where we've implemented all in Lua, had no need for that. However, as we went fro Lua to Rust (and speed up by using only 15% CPU comparing to the Lua), we added that Lua interface support to the rust, and it worked like a charm.
- chaosprint 2y agoShould compare with Rhai (https://rhai.rs/ 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 https://glicol.org/tour#meta2
- nine_k 2y agoRhai 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 2y agoIsn't Rhai extremely slow? The website itself says that it's roughly 2x slower than Python3: https://rhai.rs/book/about/benchmarks.html 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#signals 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!
- chaosprint 2y agoYou are absolutely right. Thanks for the correction and info! I gave Lua a shot, but getting the toolchain set up in wasm was a hassle: https://bytedream.github.io/litbwraw/introduction.html https://bytedream.github.io/litbwraw/introduction.html So at least I can say Rhai has some advantages on syntax and compatibility with wasm
- mentalgear 2y ago> Syntax: [...] minimizing visual distractions, while also managing to avoid inexpressive terseness. Nice! Now, if it only had type support.
- pansa2 2y agoIt 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."
- nine_k 2y agoOh, the usual Coffeescript footguns :( One of the problems of terse syntaxes is that one typo away from a syntactically valid program lies another syntactically valid program with entirely different semantics. I prefer a syntax that has enough "gaps" between syntactic constructs, so that a single typo usually leads to an obvious syntax error. In this regard, Python or Java or TS are comfortable, Haskell or Lisp or C are okay, and Coffescript or Scala or C++ are terrible.
- Mawr 2y agoOh it has optional parentheses? Into the trash it goes. I'm guessing because "it's cleaner/simpler", but that's a shallow understanding of those words. Just because there are two characters fewer on the screen doesn't make the code simpler. Simple semantics are what you should aim for and inconsistencies like these throw a wrench into that. For example, strings in JSON vs YAML. Isn't it "simpler" to not have to quote every string? So long as your string isn't "no" that may be true. So now instead of a simple mental model of "every string must be quoted" it's "strings don't need quotes except for these specific exceptions that cause issues: <list>". So much simpler... sigh.
- dboreham 2y ago
- esafak 2y agoWould this compile fast enough to be used in shell scripts? #/usr/bin/env koto
- irh 2y agoYes! I'm using it for adding commands to Helix. e.g. https://github.com/irh/dotfiles/blob/main/scripts/.scripts/toggle-markdown-bullet.koto https://github.com/irh/dotfiles/blob/main/scripts/.scripts/t...
- seivan 2y agoThe 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.
- amadoury 2y agoKoto means big brother in Fulani (a West African language).
- spacechild1 2y agoIt's named after https://en.wikipedia.org/wiki/Koto_(instrument) https://en.wikipedia.org/wiki/Koto_(instrument)
- replwoacause 2y agoElegant syntax!
- fithisux 2y agoKoto? Like the Italo-Disco band?
- account-5 2y agoIf 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.
- irh 2y agoKoto creator here, nice surprise to see this on HN so I'm a bit late to the discussion. Happy to answer any questions!
- riidom 2y agoWould 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.?
- irh 2y agoYes I would certainly hope so, you shouldn't need to know any Rust if you want to learn Koto. The guide assumes that the reader has some general experience with programming, but not from using any specific language. https://koto.dev/docs/next/language/ https://koto.dev/docs/next/language/
- epage 2y agoWhat are your plans for language and in-language library compatibility?
- irh 2y agoLimited for now, Koto's main role as an embedded language has meant that I haven't had a need, but I would like to provide bindings for other languages at some point, and to enable dynamically loaded Rust libraries. I'd start by trying UniFFI [1] which looks much simpler than the approach of manually writing a C API and using that as a foundation for higher-level language bindings. This would also likely be the starting point for a package management system (if there ends up being demand for one). Rust doesn't have a stable ABI so to make sure that dynamically loaded Rust packages are compatible, either Koto would need to be in the business of Rust toolchain management so that packages can be recompiled when needed, or an API layer would be needed. There are some projects that provide ABI-compatibility shims but I don't like the idea of having two separate approaches to FFI, so I'd want to try to build on the foreign-FFI layer once it's in place. I'm half hoping that by the time I'm interested in working on this Rust will have decided to pursue ABI stability. And there's also something in the back of my mind that's yelling 'Wasm!' at me but I would need someone wiser to convince me that it would be the right direction. [1] https://github.com/mozilla/uniffi-rs https://github.com/mozilla/uniffi-rs
- shahriarhus 2y agoIt's reminds me of Lua for C++, am I correct?
- irh 2y agoYes, 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 2y agoIs this the equivalent of Lua for Rust?
- irh 2y agoYes that's essentially where it started, although it feels quite different to use now.
- aerzen 2y agoRecently 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.
- irh 2y agoHaha well I'm sure if you put your mind to it you could create some madness in Koto! If it helps here's a git blame helper script I made for Helix (as an example of practical code without any effort put in to making it readable for others): https://github.com/irh/dotfiles/blob/main/scripts/.scripts/git-blame.koto https://github.com/irh/dotfiles/blob/main/scripts/.scripts/g...