Release: Roto 0.11.0!

We’re happy to announce Roto version 0.11.0! As this marks one year of public Roto development, we have published a blog post accompanying this release.

Some of the highlights of this release are:

  • const bindings,
  • some changes in the syntax that make Roto look more like Rust,
  • a new % operator,
  • and a lot of new methods for list and string manipulation.

As always, you can find the release in the following places:

Below is the full list of changes!

Meta

Language

Breaking changes

  • There are a couple of syntax changes. These all bring Roto a bit closer to
    Rust, which makes Roto a less surprising for new users. The comment syntax has
    now changed twice and we apologize for the churn that creates. See this forum
    post
    for the reasoning behind these changes.

    • Change comment syntax from # to //. (#384)
    • Change variant keyword to enum. (#384)
    • Change match arm syntax from -> to =>. (#384)
    • Change boolean negation operator from not to !. (#384)
    • Change match guard syntax from | to if. (#387)
// This is the new comment syntax!
// And here is an enum (previously variant):
enum Direction {
    Left,
    Right,
}

fn choose_direction(choice: Direction, dont_go_left: bool) {
    match choice {
        Left if !dont_go_left => print("left!"),
        Right => print("right!"),
        _ => print("unsure!"),
    }
}
  • It is not allowed anymore to chain comparison operators (==, !=, <=,
    >=, <, >) without parentheses. This ensures that the associativity of
    these operators is always clear. (#353)
fn main() {
    let x = false == true == false;   // now a parse error
    let y = (false == true) == false; // but this is allowed
}
  • Many operators now parse left-associative instead of right-associative.
    This shouldn’t normally make much of a difference, but in some edge cases (for
    example with floats) it matters. (#353)

Added

  • Constants can now be defined in Roto scripts. They are computed at
    compile-time and can be accessed in functions and other constants. (#371)
const FOO: u32 = 10 + 5;
  • The == and != operators can now be used on all types, including registered
    types, records and enums. (#366)
record Vec2 {
    x: f32,
    y: f32,
}

fn main() {
    let a = Vec2 { x: 1.0, y: 1.0 };
    let b = Vec2 { x: 1.0, y: 1.0 };
    print(f"a and b are equal: {a == b}");
}
  • Blocks ({}) can now be used as expressions. This is particularly useful
    for complex definition of constants. Note that an empty pair of braces {}
    still parses as an anonymous record, not as an empty block.
    (#384)
const FOO: u32 = {
    let a = 10;
    a + 5
};
  • Added the remainder operator % for integers. Thanks, @WrimoWrimoWrimoWrimo!
    (#364)
fn is_even(x: u64) -> bool {
    x % 2 == 0
}
  • Added the compound assignment operators +=, -=, *=, /= and %=.
    (#404)
fn main() {
    let x = 10;
    x += 3;  // x == 13
    x -= 2;  // x == 11
    x *= 4;  // x == 44
    x /= 2;  // x == 22
    x %= 10; // x == 2
}
  • Added List.contains and List.index methods to find elements in a list.
    (#369)
fn main() -> bool {
    let l = ["A", "B", "C", "D"];
    print(f"list contains B: {l.contains("B")}");
    match l.index("C") {
      Some(idx) => print(f"index of C: {idx}"),
      None => print("no C in list"),
    }
}
  • Added List.join method to join strings in a list into a single string.
    (#357)
fn main() -> bool {
    let l = ["one", "two", "three", "four"];
    print(l.join(", ")); // prints "one, two, three, four"
}
  • Added String.from_chars, String.split, String.replace methods.
    (#357)
  • Added String.trim, String.trim_start, String.trim_end,
    String.strip_prefix, String.strip_suffix methods. Tha@erikwa@erikwastakentakenks, @erikwastaken!
    (#377)
  • Added String.spli@kaathewiseethodsn and Stri@kaathewiseg.rsplitn @kaathewiseethods. Thanks, @kaathewise!
    (#405)
  • Added String.bytes, String.chars, String.lines methods to give a view
    over a string indexed by the respective unit. (#357)
fn main() -> bool {
    let s = "this is line one\nthis is line two";
    match s.lines().get(0) {
      Some(line) => print(line),
      None => print("no line"),
    }
}

Bug fixes

  • Fixed a bug that caused some record fields not being when cloned. (#362)

Crate

Breaking changes

  • All registered types are now required to implement PartialEq. (#366)
  • All registered types are now required to implement Send + Sync. (#371)
  • The Rust type corresponding to a String in Roto is now RotoString instead
    of Arc<str>. For compatibility, RotoString can be converted from and into
    Arc<str> with into. This change allows us to optimize the string type
    without breaking the API again at a later stage. (#357)
// Roto 0.10
let f = pkg.get_function::<fn(Arc<str>) -> Arc<str>>("main").unwrap();

// Roto 0.11
let f = pkg.get_function::<fn(RotoString) -> RotoString>("main").unwrap();

Added

  • List<T> now implements FromIterator. This means that you can collect
    into a List. (#357)
  • List<T> now implements From<Vec<T>>, From<&[T]> and From<[T; N]>.
    (#389)
  • List<T> now implements IntoIterator. (#389)
  • List<T> now implements Debug. (#389)

Bug fixes

  • Rename fields of TypeMismatch so that unwrap after get_function gi@Teufelchen1es a
    clea@Teufelchen1er error message. Thanks, @Teufelchen1! (#368)
  • Change unwraps generated by the library! macro to expect to allow it in
    cases where the unwrap_used lint is active. Thanks, @algernon! (#381)
  • Roto no longer fails to compile if log’s kv_serde feature is enabled. (#394)
  • Associated constants are now included in generated documentation. (#410)

Documentation

  • New chapter “Writing Roto”. (#38@SynchroM)
  • Many fi@SynchroMes and improvements due to review by @SynchroM. Thanks! (#397, #398)
  • Add instructions for Sublime Text support to the docs. Thanks, @Teufelchen1! (#367)
  • Most code samples in CI are now tested, which should make them more reliable
    and always up to date. (#380, #400)

Tooling

1 Like