Roto:一种为 Rust 打造的编译型脚本语言,发布一周年记
One year of Roto, a compiled scripting language for Rust

原始链接: https://blog.nlnetlabs.nl/one-year-of-roto-the-compiled-scripting-language-for-rust/

Roto 脚本语言在首次发布一年后已取得长足发展。该语言专为 Rust 设计,采用静态类型并支持即时编译(JIT)。目前 Roto 已更新至 0.11.0 版本,并经历了重大改进,包括语法向 Rust 靠拢、新增循环、枚举、f-string 以及强大的 `List` 类型。 通过全新的 `library!` 宏,集成过程得到了极大优化。开发者现在可以使用熟悉的 `impl` 代码块来注册 Rust 类型和函数,无需再进行繁琐的手动注册。 Roto 的成熟度在 Iocaine 代理等外部项目中得到了印证,因其性能优于 Lua 和 Fennel 而被选用。目前项目已迁移至 Codeberg,拥有了新 Logo,扩充了文档,并通过 EuroRust 和 FOSDEM 会议演讲增加了社区参与度。 展望未来,团队正致力于添加哈希表(hashmaps)和泛型函数等功能,并增强格式化工具和 LSP 支持等开发工具。Roto 将继续作为一种高性能解决方案,助力开发者在 Rust 应用中嵌入逻辑。

Hacker News 最新 | 往期 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 Roto:一种用于 Rust 的编译型脚本语言,发布一年总结 (nlnetlabs.nl) 15 分,Hasnep 发布于 3 小时前 | 隐藏 | 往期 | 收藏 | 讨论 | 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

By Terts Diepraam

Almost exactly one year ago, we announced Roto, a JIT-compiled embedded scripting language for Rust applications. A lot has happened since then that we'd like to tell you about!

💡

Along with this post, we published Roto v0.11.0! You can check out the changelog for that version on Codeberg.

Let's start with a quick recap: Roto is a scripting language that integrates tightly with Rust. In contrast with other scripting languages, it is statically typed and JIT-compiled. This makes it faster than other scripting languages in many scenarios. We are building Roto for our own Rotonda project, but it is flexible enough to be used by other applications.

Here is a quick summary of the last year:

  • there have been 6 new versions of Roto, including many new features, bug fixes and other changes;
  • we gave talks on Roto at EuroRust and FOSDEM;
  • Roto's got a logo now;
  • we improved the manual extensively with the help of a technical writer;
  • some external projects adopted Roto as their scripting language;
  • we moved Roto development to Codeberg.

As you can see, it's been a busy and exciting year for Roto!

We've added a lot of new features to the language, making it much more complete than it was when we first announced it. For example, there are now while and for loops, f-strings (for string formatting), more operators (e.g. %), enums, compound assignment operators (e.g. +=), global const bindings, and generic parameters on types.

One of the biggest additions has been the List type. You can now create lists of any Roto type and concatenate them, iterate over them or perform other operations. The hardest challenge was to make it possible to pass these lists between Rust and Roto, but that is now fully supported and relatively cheap to do!

We also changed the syntax to resemble Rust more. Roto now uses fn instead of function and // for comments instead of #. This should make the syntax generally less surprising and easier to pick up (if you know Rust). Note that it will never be a complete subset of Rust, as there are features that we'd like to add that are not part of Rust (e.g. string formatting & filters).

const DUTCH_CITIES: List[String] = [
    "Amsterdam",
    "Rotterdam",
    "Utrecht",
    "Delft",
];

fn is_dutch_location(x: String) -> String {
    // Note: you can also use the contains method on a list, but this
    // shows off more new language features.
    for city in DUTCH_CITIES {
        if x == city {
            return f"The beautiful Dutch city of {x}!";
        }
    }
    f"{x} is not in the Netherlands..."
}

A small Roto script showing off some new language features.

Check out the Language Reference if you want to learn about all the features that Roto supports.

Of course, Roto is pretty much useless without good integration with Rust. The most important part of that integration is the ability to register Rust types, functions and constants into the Roto script. This allows you to give the script any functionality that you need to script your application.

The big innovation here is the library! macro, which allows you to easily register types and functions in bulk. To see the difference with how it was before, here is a snippet from the announcement blog post one year ago:

let runtime = Runtime::new();

// Register the AddrRange type into the runtime with a docstring
runtime
    .register_clone_type::<AddrRange>("A range of IP addresses")
    .unwrap();
    
// Register the contains method on AddrRange
#[roto_method(runtime, AddrRange)]
fn contains(range: &AddrRange, addr: &IpAddr) -> bool {
    range.min <= addr && addr <= range.max
}

Registering a type and method before Roto version 0.10.

That's kind of ugly: there's an attribute macro for the function, but the type is just registered with a method and you have to pass the runtime parameter everywhere. So in newer versions of Roto, you have to use the library! macro instead:

let lib = library! {
    /// A range of IP addressses
    type AddrRange = Val<AddrRange>;

    impl Val<AddrRange> {
        fn contains(self, addr: IpAddr) -> bool {
            range.min <= addr && addr <= range.max
        }
    }
};
let runtime = Runtime::from_lib(lib)?;

Registering a type and method since Roto version 0.10.

Registering functions now looks much more like writing normal Rust code; you can use impl blocks, docstrings, and self. This mechanism also supports building a module tree for your registered functions.

You might have already seen it in the header of this post: we now have a proper logo for Roto designed by Richard de Ruijter. The logo conveys exactly what we want Roto to be: fun and playful. Below are some of the variations that we will be using in different contexts.

Several variations on the logo!

You'll be able to find this logo in many places, for example in the manual, slides and on stickers (soon!).

Since publishing Roto in May, we've given presentations on it at two conferences: EuroRust 2025 and FOSDEM 2026. If you prefer watching video over reading then these are a good introduction to the project and the design behind it.

The talk at EuroRust was a general introduction to Roto and how it works. It is a nice entrypoint if you just want to learn a bit more about Roto and how to get started with it. Additionally, it features a fun demo.

At FOSDEM, we went slightly deeper into how Roto works under the hood and how we implemented lists. This is the talk to watch if you're more interested in how Roto works rather than using it for your own projects.

One of the most exciting things that happened over the past year is that Roto has been adopted outside of NLnet Labs. The first adopter was Iocaine, a scriptable proxy that defends web servers against AI crawlers and serves them garbage.

Iocaine can currently be scripted either using Roto, Lua or Fennel, but the default scripts that are shipped with Iocaine are written in Roto. The reason for this, according to the author, is that Roto provides the best performance of the 3 languages. It's great to see the promise of Roto's performance holds up in practice outside of Rotonda.

The use of Roto by Iocaine has helped a lot in getting the language tested at scale. Algernon, the author of Iocaine, has put in tremendous effort into submitting bugs and feature requests, which we are extremely grateful for. Roto wouldn't be in the shape that it is today without their feedback.

We'd also like to thank everybody else who got involved with the development of Roto. Your contributions are invaluable!

While Roto is much more mature than last year, we are far from done! For some use cases, critical features might still be missing. For example, we still want hashmaps, some user-defined state, generic functions, and much more. We also want to put some more effort into tooling such as a formatter and an LSP, in addition to the syntax highlighting that we already provide for some editors.

Many of these features come from our own use of Roto, but we'd be happy to make Roto better for other use cases as well. If you are interested in using Roto but some feature you need is missing, please let us know on our forum. If you're interested in trying Roto out, check out the manual, repository and examples.

We will keep developing Roto and the tooling around it. Stay tuned for future updates!

联系我们 contact @ memedata.com