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')
.