String and Char
#String
Reason strings are delimited using double quotes (single quotes are reserved for the character type below).
RElet greeting = "Hello world!";
let multilineGreeting = "Hello
world!";
Special characters in the string need to be escaped:
RElet oneSlash = "\\";
To concatenate strings, use ++
:
RElet greetings = "Hello " ++ "world!";
#Quoted String
There's a special syntax for string that allows
multiline string just like before
no special character escaping
hooks for special pre-processors
RElet greetingAndOneSlash = {|Hello
World
\
Hehe...
|};
Analogically speaking, it's like JavaScript's backtick string interpolation, except without needing to escape special chars, and without built-in interpolation of variables. Though you can trivially restore the latter functionality, as BuckleScript has done:
RElet world = {js|世界|js}; /* Supports Unicode characters */
let helloWorld = {j|你好,$world|j}; /* Supports Unicode and interpolation variables */
BuckleScript's special pre-processor can then look for such js
and j
markers around the string and transforms it into something else.
#Usage
More string operations can be found in the standard library. For JS compilation, see the familiar Js.String
API in the BuckleScript API docs. Since a Reason string maps to a JavaScript string, you can mix & match the string operations in both standard libraries.
#Tips & Tricks
https://twitter.com/jusrin00/status/875238742621028355
You have an expressive type system now! In an untyped language, you'd often overload the meaning of string by using it as:
a unique id:
var BLUE_COLOR = "blue"
an identifier into a data structure:
var BLUE = "blue"; var RED = "red"; var colors = [BLUE, RED]
the name of an object field:
person["age"] = 24
an enum:
if (audio.canPlayType() === 'probably') {...}
(ಠ_ಠ)other crazy patterns you'll soon find horrible, after getting used to Reason's alternatives.
The more you overload the poor string type, the less the type system (or a teammate) can help you! Reason provides concise, fast and maintainable types & data structures alternatives to the use-cases above (e.g. variants, in a later section).
Under native compilation, Reason strings compile to a simple representation whose performance is straightforward to analyze, at the expense of sometimes requiring manual performance tuning. For example, naively concatenating strings like "hi " ++ "how " ++ "are " ++ "you?"
unnecessarily allocates the intermediate strings "are you?"
and "how are you?"
(though it might be optimized into a single string in these simple cases). In this case, prefer String.concat
. In a way, it's somewhat nice that the traditional runtime analysis we've learned in school can finally be useful again.
Under JavaScript compilation, a Reason string maps to a JavaScript string and vice-versa, so no such above concern or analysis opportunities apply.
#Design Decisions
Quoted string's feature of not escaping special characters enables neat DSLs like regular expression:
RElet r = Str.regexp({|hello \([A-Za-z]+\)|});
as opposed to
RElet r = Str.regexp("hello \\([A-Za-z]+\\)");
Though for JS compilation, you'd use [%bs.re]
and Js.Re
instead, since Str
is not available.
Reason/OCaml's emphasis on simplicity over cleverness can be seen here through its straightforward native string implementation. An overly sophisticated string implementation can sometimes backfire.
#Char
Reason has a type for a string with a single letter:
RElet firstLetterOfAlphabet = 'a';
Note: Char doesn't support Unicode or UTF-8.
#Tips & Tricks
A character compiles to an integer ranging from 0 to 255, for extra speed. You can also pattern-match (covered later) on it:
RElet isVowel = (theChar) =>
switch (theChar) {
| 'a' | 'e' | 'i' | 'o' | 'u' | 'y' => true
| _ => false
};
To convert a String to a Char, use "a".[0]
. To convert a Char to a String, use String.make(1, 'a')
.