From e103c8e66c1880453e10730a30805a809a383291 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 22 Jul 2020 21:32:56 +0800 Subject: [PATCH] Refine string docs. --- doc/src/language/strings-chars.md | 17 ++++++-------- doc/src/language/values-and-types.md | 2 +- doc/src/rust/strings.md | 33 ++++++++++++++++++++-------- src/syntax.rs | 2 +- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/doc/src/language/strings-chars.md b/doc/src/language/strings-chars.md index acdb06f4..81ca6258 100644 --- a/doc/src/language/strings-chars.md +++ b/doc/src/language/strings-chars.md @@ -20,9 +20,14 @@ The `ImmutableString` Type ------------------------- All strings in Rhai are implemented as `ImmutableString` (see [standard types]). +An `ImmutableString` does not change and can be shared. -`ImmutableString` should be used in place of the standard Rust type `String` when registering functions -because using `String` is very inefficient (the `String` must always be cloned). +Modifying an `ImmutableString` causes it first to be cloned, and then the modification made to the copy. + +### **IMPORTANT** - Avoid `String` Parameters + +`ImmutableString` should be used in place of `String` for function parameters because using +`String` is very inefficient (the `String` argument is cloned during every call). A alternative is to use `&str` which maps straight to `ImmutableString`. @@ -67,14 +72,6 @@ Individual characters within a Rhai string can also be replaced just as if the s In Rhai, there are also no separate concepts of `String` and `&str` as in Rust. -Immutable Strings ----------------- - -Rhai use _immutable_ strings (type `ImmutableString`) and can be shared. - -Modifying a Rhai string actually causes it first to be cloned, and then the modification made to the copy. - - Examples -------- diff --git a/doc/src/language/values-and-types.md b/doc/src/language/values-and-types.md index 55b03229..11426e84 100644 --- a/doc/src/language/values-and-types.md +++ b/doc/src/language/values-and-types.md @@ -14,7 +14,7 @@ The following primitive types are supported natively: | **Immutable Unicode [string]** | `rhai::ImmutableString` (implemented as `Rc` or `Arc`) | `"string"` | `"hello"` etc. | | **[`Array`]** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` | | **[Object map]** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `"#{ "a": 1, "b": 2 }"` | -| **[Timestamp]** (implemented in the [`BasicTimePackage`][packages], disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`] if not [WASM] build) | `"timestamp"` | _not supported_ | +| **[Timestamp]** (implemented in the [`BasicTimePackage`][packages], disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`] if [WASM] build) | `"timestamp"` | _not supported_ | | **[Function pointer]** | `rhai::FnPtr` | `Fn` | `"Fn(foo)"` | | **[`Dynamic`] value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ | | **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. | diff --git a/doc/src/rust/strings.md b/doc/src/rust/strings.md index 0d54d87b..f1d421ea 100644 --- a/doc/src/rust/strings.md +++ b/doc/src/rust/strings.md @@ -4,19 +4,32 @@ {{#include ../links.md}} +Avoid `String` +-------------- + +As must as possible, avoid using `String` parameters in functions. + +Each `String` argument is cloned during every single call to that function - and the copy +immediately thrown away right after the call. + +Needless to say, it is _extremely_ inefficient to use `String` parameters. + + `&str` Maps to `ImmutableString` ------------------------------- Rust functions accepting parameters of `String` should use `&str` instead because it maps directly to [`ImmutableString`][string] which is the type that Rhai uses to represent [strings] internally. -The parameter type `String` is discouraged because it involves converting an [`ImmutableString`] into a `String`. +The parameter type `String` involves always converting an [`ImmutableString`][string] into a `String` +which mandates cloning it. + Using `ImmutableString` or `&str` is much more efficient. A common mistake made by novice Rhai users is to register functions with `String` parameters. ```rust -fn get_len1(s: String) -> i64 { s.len() as i64 } // <- Rhai finds this function, but very inefficient -fn get_len2(s: &str) -> i64 { s.len() as i64 } // <- Rhai finds this function fine +fn get_len1(s: String) -> i64 { s.len() as i64 } // <- Very inefficient!!! +fn get_len2(s: &str) -> i64 { s.len() as i64 } // <- This is better fn get_len3(s: ImmutableString) -> i64 { s.len() as i64 } // <- the above is equivalent to this engine @@ -24,9 +37,9 @@ engine .register_fn("len2", get_len2) .register_fn("len3", get_len3); -let len = engine.eval::("x.len1()")?; // error: function 'len1 (&str | ImmutableString)' not found -let len = engine.eval::("x.len2()")?; // works fine -let len = engine.eval::("x.len3()")?; // works fine +let len = engine.eval::("x.len1()")?; // 'x' is cloned, very inefficient! +let len = engine.eval::("x.len2()")?; // 'x' is shared +let len = engine.eval::("x.len3()")?; // 'x' is shared ``` @@ -37,9 +50,11 @@ Rhai functions can take a first `&mut` parameter. Usually this is a good idea b cloning of the argument (except for primary types where cloning is cheap), so its use is encouraged even though there is no intention to ever mutate that argument. -`ImmutableString` is an exception to this rule. While `ImmutableString` is cheap to clone (only -incrementing a reference count), taking a mutable reference to it involves making a private clone -of the underlying string because Rhai has no way to find out whether that parameter will be mutated. +[`ImmutableString`][string] is an exception to this rule. + +While `ImmutableString` is cheap to clone (only incrementing a reference count), taking a mutable +reference to it involves making a private clone of the underlying string because Rhai has no way +to find out whether that parameter will be mutated. If the `ImmutableString` is not shared by any other variables, then Rhai just returns a mutable reference to it since nobody else is watching! Otherwise a private copy is made first, diff --git a/src/syntax.rs b/src/syntax.rs index 33b0c9e4..654daea1 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -1,7 +1,7 @@ //! Module containing implementation for custom syntax. use crate::any::Dynamic; use crate::engine::{Engine, Imports, State, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT}; -use crate::error::{LexError, ParseError, ParseErrorType}; +use crate::error::{LexError, ParseError}; use crate::fn_native::{SendSync, Shared}; use crate::module::Module; use crate::parser::Expr;