Docs / Language Manual / StringAndChar

String and Char

String

Reason strings are delimited using double quotes (single quotes are reserved for the character type below).

RE
let greeting = "Hello world!"; let multilineGreeting = "Hello world!";

Special characters in the string need to be escaped:

RE
let oneSlash = "\\";

To concatenate strings, use ++:

RE
let 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

RE
let 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:

RE
let 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:

RE
let r = Str.regexp({|hello \([A-Za-z]+\)|});

as opposed to

RE
let 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:

RE
let 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:

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