Nix is a language with built-in support for URI literals typed as strings [1], which is a source of confusion and edge-cases, and I believe the feature is now discouraged in general use.
[0] https://roto.docs.nlnetlabs.nl/en/stable/reference/language_...
[1] https://nix.dev/manual/nix/2.34/language/string-literals
Places where we would benefit the most from this is in the Games and UI space. I know game devs have already started by integrating lua, like with mlua [1]. In the UI space i think Makepad is the best example of a team making a dedicated DSL that can be hot-reloaded [2].
I think we need more of this! Go make a DSL next time you feel crushed by the weight of compiling Rust crates!
---
[0] and by my research i mean Claude. this is a great blog with many posts about improving compile times https://nnethercote.github.io/
[1] https://crates.io/crates/mlua . I don't have a reference for a project using it though so please reply if you know of one!
The syntax is of course very Rusty, which is cool. However, a sort of obvious question comes to mind - what is the benefit of this over just writing rust, then? Just because the compile times are shorter?
EDIT: should mention I understand why embedded scripting languages exist, having embedded Lua many times. And I love a lot of these features, but to me having an embedded scripting language should simplify the language/API surface area instead of mirroring it almost 1:1. That's what I'm a bit undersold on.
When you made Roto what kind of workloads were you optimizing for? How are you guys benchmarking performance?
I ran a quick benchmark based on my recent work (Used AI for the code here): ``` fn sum_scalar(n: u64) -> u64 { let total = 0; let i = 0; while i < n { total = total + i; i = i + 1; } total }
fn sum_list(xs: List[u64]) -> u64 {
let total = 0;
for x in xs { total = total + x; }
total
}
```Rust benchmark.rs ```
use std::time::Instant;
use roto::{List, Runtime};
fn main() {
let rt = Runtime::new();
let mut pkg = rt.compile("bench.roto").unwrap();
let sum_list = pkg.get_function::<fn(List<u64>) -> u64>("sum_list").unwrap();
let n = 1024;
let iters = 50_000;
let xs: List<u64> = (0..n).collect();
let t = Instant::now();
for _ in 0..iters { sum_scalar.call(n); } // adds 0..n with a counter
let scalar = t.elapsed();
let t = Instant::now();
for _ in 0..iters { sum_list.call(xs.clone()); } // adds the SAME 0..n from a List
let list = t.elapsed();
println!("sum_scalar (counter): {scalar:?}");
println!("sum_list (List[u64]): {list:?}");
println!("-> {:.0}x slower", list.as_secs_f64() / scalar.as_secs_f64());
}
``` Output:
sum_scalar (counter): 28.56ms
sum_list (List[u64]): 590.48ms
-> 21x slower
I'm happy to cut a PR against your repo with some of the benchmarks I run on every commit in my own language projects if that would be helpful!
[1]. https://github.com/ianm199/lua-rs/tree/mainA big problem I encountered in using Lua in Rust for my game engine was that I wasn't able to serde the Lua runtime such that I can snapshot a game session and save it in a file, and retrieve it in another context.
fn contains(range: &AddrRange, addr: &IpAddr) -> bool {
range.min <= addr && addr <= range.max
Looks ugly as fudge.Syntax is not everything, but it also shows that people too easily think they are great at language design when they really aren't. It's fascinating to watch how people continue with such an approach. How many people are going to use that over, say, python?