essenceDocumentation
essenceDocs
on this pageBindings
Coming from JavaScript?

Coming from JavaScript

Every JavaScript habit beside its Essence spelling and the error you get if you forget, in one lookup table per topic.

Each row of a topic table pairs a JavaScript or TypeScript habit with its Essence spelling and the error you get if you write the habit instead. A dash in the error column means the habit carries over or has no error. Nothing here is explained: each Essence cell links to the page that explains it, and each error code links to its entry in the diagnostics reference. To look up a message the compiler printed, see What the compiler says when you type JavaScript.

Here is a five-line TypeScript function, then the same function in Essence. Both drop the empty names and greet the rest.

function greeting(names: string[]): string {
	const known = names.filter((name) => name.length > 0)
	if (known.length === 0) return "Hello, nobody"
	return `Hello, ${known.join(" and ")}`
}

console.log(greeting(["Ada", "", "Grace"])) // Hello, Ada and Grace
console.log(greeting([])) // Hello, nobody
implementation {
	function greeting(to names: List<String>) -> String {
		constant known = names::everyItem(where (name) {
			<- name::hasCharacters()
		})

		if known::isEmpty() {
			<- "Hello, nobody"
		}

		<- "Hello, {known::join(with " and ")}"
	}

	Terminal.print(greeting(to ["Ada", "", "Grace"])) § Hello, Ada and Grace
	Terminal.print(greeting(to [])) § Hello, nobody
}

This program uses parts the language pages teach later. Programs and values teaches implementation, the § comments, constant, string and list literals, List<String> and the {…} interpolation. Method calls teaches :: calls and their labels, and Conditions teaches if. Functions teaches function, the to label, -> String and <-, and Functions as values teaches the (name) { … } literal. The library calls are everyItem(where:), isEmpty(), join(with:), hasCharacters() and Terminal.print.

Five differences show at once. A method is called with ::, and . calls a static such as Terminal.print. A function’s return type is required, where TypeScript would infer it. <- returns, inside the callback too. Each call writes its labels: to, where, with. And the comparisons > 0 and === 0 are the methods hasCharacters() and isEmpty().

Bindings

constant and variable replace const and let. A variable can be reassigned, and a record, a list or a dictionary is never changed in place.

JavaScript or TypeScript Essence If you forget
const total = 1 constant total = 1 foreign-syntax
let count = 0, var count = 0 variable count = 0 foreign-syntax
a ; at the end of a statement constant total = 1, with no ; foreign-syntax
count += 1 count = count::add(1) operator-not-supported
assigning to a const declare it with variable constant-reassignment
let count = 0, then count = "none" a variable keeps the type it was declared with assignment-type-mismatch
let count: number, assigned later the value is part of the declaration: variable count: Integer = 0 foreign-syntax, then syntax-error for the missing value
user.name = "Ada" a new record, Essence’s object: { user with name = "Ada" } foreign-syntax
const { x, y: row } = point constant { x, y as row } = point foreign-syntax for the const; unknown-type for constant { x, y: row } = point, since : annotates a type
reading a const above its line refused, as in the temporal dead zone unknown-name
snake_case names camelCase; _ cannot appear in a name syntax-error
// note, /* note */ § note foreign-syntax
/** Documentation. */ §§ Documentation. foreign-syntax

Operators

There are none. Arithmetic, comparison and logic are method calls, read left to right.

Every row of this table reports operator-not-supported, whose helps name the method for the operator you wrote. Only the last row is something else.

JavaScript or TypeScript Essence If you forget
a + b a::add(b) Essence has no '+' operator
a - b a::subtract(b) Essence has no '-' operator
a * b a::multiply(with b) Essence has no '*' operator
a / b a::divide(by b), an Optional (a value that may be missing) unless b is known not to be zero Essence has no '/' operator
a % b a::remainder(dividingBy b) Essence has no '%' operator
a === b, a == b a::is(b), which compares records and lists by content Essence has no '===' operator
a !== b a::isNot(b) Essence has no '!==' operator
a < b, a <= b a::isLessThan(b), a::isLessThanOrEqualTo(b) Essence has no '<' operator
a > b, a >= b a::isGreaterThan(b), a::isGreaterThanOrEqualTo(b) Essence has no '>' operator
a && b a::and(b); both sides are evaluated, so nest an if when the right side must not run Essence has no '&&' operator
a || b a::or(b); both sides are evaluated Essence has no '||' operator
!a a::negate() Essence has no '!' operator, and the help names a
-x x::negate(); - only signs a number literal Essence has no '-' operator
(a + b) * c a::add(b)::multiply(with c); there are no grouping parentheses Essence has no '+' operator, at the + inside the parentheses
c ? a : b define { as a if c as b otherwise } foreign-syntax

Numbers

There is no number and no floating point. An Integer is a whole number with no largest value; a Rational is an exact fraction.

JavaScript or TypeScript Essence If you forget
number Integer or Rational unknown-type
1n 1: every Integer is arbitrary precision invalid-number
0.75 0.75, an exact Rational that prints as 3/4 —
0.1 + 0.2 === 0.3 is false 0.1::add(0.2)::is(0.3) is true —
10 / 4 is 2.5 10::divide(by 4) is 5/2 operator-not-supported
-7 % 3 is -1 -7::remainder(dividingBy 3) is 2; -7::remainder(dividingBy 3, as #Truncating) is -1 operator-not-supported
Math.floor(7 / 2) 7::quotient(dividingBy 2) is 3 operator-not-supported at the /; foreign-syntax for Math
Math.max(a, b), Math.min(a, b) Number.highest(a, b), Number.lowest(a, b) foreign-syntax
Math.abs(n), Math.round(x) n::absolute(), x::round(), which rounds halves away from zero: -7/2::round() is -4, where Math.round(-3.5) is -3 foreign-syntax
NaN, Infinity none; a division that can fail returns an Optional foreign-syntax
parseInt("42") Integer.parse("42") is #Value(42); Integer.parse("4x") is #Empty foreign-syntax
n.toFixed(2) n::toString(as #Decimal, toPlaces 2) type-without-members
0xff, 1e3 decimal digits only: 255, 1_000 invalid-number

Strings

Double quotes only, and every string literal interpolates. length() counts characters as a reader sees them.

JavaScript or TypeScript Essence If you forget
'hi', `hi` "hi" foreign-syntax
`Hello, ${name}` "Hello, {name}" none: "Hello, ${name}" compiles and prints a $ before the value
'{ "a": 1 }' "\{ \"a\": 1 }": a literal { is written \{ unclosed-string for "{ \"a\": 1 }"
a + b a::append(b), or "{a}{b}" operator-not-supported
s.length counts UTF-16 units: "🇩🇪".length is 4 s::length() counts characters: "🇩🇪"::length() is 1 method-called-with-dot
s[0], s.charAt(0) s::character(at 0), an Optional<Character> foreign-syntax for s[0], at the brackets; type-without-members for s.charAt(0), since a String has no charAt under any spelling
s.toUpperCase() s::uppercase() type-without-members; unknown-method for s::toUpperCase()
s.trim(), s.includes(t) s::trim(), s::contains(t) method-called-with-dot for trim; type-without-members for includes
s.split("\n") s::split(on "\n") method-called-with-dot
s.indexOf(t) is -1 when absent s::firstIndex(of t) is #Empty when absent type-without-members
"café" === "cafe\u0301" is false ::is returns true for the same two spellings of é —
"\u00e9" "\u{e9}" — the braces are not optional, and they take one to six digits unbraced-unicode-escape, whose help rebrackets the digits you wrote
"\uD83D\uDE00", a surrogate pair "\u{1F600}", one escape for one character unbraced-unicode-escape; "\u{D83D}" alone is surrogate-unicode-escape

Collections

Records, lists and dictionaries are all immutable. A method that would change one returns a new one.

JavaScript or TypeScript Essence If you forget
{ x: 1, y: 2 } { x = 1, y = 2 } foreign-syntax
{ ...point, x: 9 } { point with x = 9 } syntax-error
{ x, y }, point.x the same —
[1, 2, 3] the same —
items[0], items.at(-1) items::item(at 0), items::item(at -1), an Optional foreign-syntax for items[0], at the brackets; type-without-members for items.at(-1)
items.length items::length() method-called-with-dot
items.push(4), [...items, 4], items.concat(more) items::append(4), items::append(contentsOf more), a new list type-without-members, since a list has no push under any spelling; syntax-error for [...items, 4]
items.pop(), items.shift() items::lastItem() reads the item and items::removeLast() returns the rest; firstItem() and removeFirst() at the front type-without-members; unknown-method for items::pop()
items.map(f) items::map(f) method-called-with-dot
items.map((x, i) => …) items::enumerate(), then map reading entry.index and entry.item foreign-syntax as written; uninferable-parameter-type, then no-matching-overload, for items::map((x, i) { … })
items.reduce(f, 0) items::reduce(startingWith 0, f) method-called-with-dot
items.filter(p) items::everyItem(where p) unknown-method for items::filter(p)
items.find(p), items.findIndex(p) items::firstItem(where p), items::firstIndex(where p), an Optional unknown-method for items::find(p)
items.indexOf(x) is -1 when absent items::firstIndex(of x), an Optional unknown-method for items::indexOf(x)
items.some(p), items.every(p) items::hasItems(where p), items::hasOnlyItems(where p) type-without-members; unknown-method for items::some(p)
items.includes(x) items::contains(x) unknown-method for items::includes(x)
items.slice(1, 3) items::slice(from 1, to 3) no-matching-overload for items::slice(1, 3)
items.join(", ") items::join(with ", ") method-called-with-dot
items.flat() items::flatten() unknown-method for items::flat()
items.sort(), items.toSorted() items::sort(), a new list in the items’ own order unknown-method for items::toSorted()
items.sort((a, b) => a - b) items::sort(by (a, b) { <- a::compare(to b) }), where the function returns an Ordering foreign-syntax as written; no-matching-overload without by
items.reverse() items::reverse(), a new list method-called-with-dot
names.map((name, i) => [name, prices[i]]) names::pair(with prices), a list of { first, second } records foreign-syntax as written; unknown-method for names::zip(prices)
const [first, second] = items none; read items with item(at:), since there is no list pattern syntax-error for constant [first, second] = items
new Map(), Record<string, number> a Dictionary: ["ann" = 31], or [=] when empty foreign-syntax for new and for Map; type-not-generic for Record<String, Integer>: Essence’s Record takes no type arguments
ages.get("ann") ages::value(at "ann"), an Optional type-without-members
ages.set("bob", 40) ages::set("bob", to 40), a new dictionary method-called-with-dot
new Set(items) a list, with removeDuplicates() and contains foreign-syntax

Null, undefined and exceptions

There is no null and no undefined. A value that may be missing is an Optional; an operation that can fail with a reason returns a Result.

JavaScript or TypeScript Essence If you forget
null, undefined Optional<T>: #Value(x) or #Empty foreign-syntax
string | null Optional<String> unknown-type
x ?? d x::value(defaultingTo d) operator-not-supported
user?.name user::map(.name), still an Optional; andThen when the step returns an Optional foreign-syntax
user! none; take the value out with match or value(defaultingTo:) foreign-syntax
if (user) if user::hasValue(), a Boolean; it does not narrow user, so read the value with a match syntax-error as written; condition-not-boolean for if user
user.name on a value that may be missing refused: an Optional is taken apart, never reached through type-without-members; unknown-method for a :: call
throw new Error("…") return #Failure(reason) in a Result<T, F> foreign-syntax
try { … } catch (error) { … } recover(with:), reason(), or a match foreign-syntax

Functions

A function declaration writes the type of every parameter and its return type. A call writes each label, in order.

JavaScript or TypeScript Essence If you forget
function add(a, b) { … } function add(_ a: Integer, _ b: Integer) -> Integer { … }; _ means the call passes the argument with no label syntax-error
a function with no return type -> Type is always written; -> {} returns nothing, like : void syntax-error
return x <- x foreign-syntax, and the function still returns, so nothing cascades off it
a path that falls off the end every path returns missing-return
(n) => n + 1 as an argument, with its implicit return (n) { <- n::add(1) }; a value leaves only through <- foreign-syntax; uninferable-return-type without the <-
const double = (n) => n * 2 constant double = (_ n: Integer) -> Integer { <- n::multiply(with 2) }; only an argument infers its types foreign-syntax twice, for the const and the =>; uninferable-parameter-type and missing-return-type once it is written with braces
greet({ name: "Ada", loud: true }) labels, in declaration order: greet(name "Ada", loud true) foreign-syntax as written; argument-label-mismatch for greet("Ada", true) or labels out of order
function f(a, b = 1) function f(_ a: Integer, b: Integer = 1), called as f(1, b 5) argument-label-mismatch for f(1, 5)
(product) => product.price .price —
overload signatures overload entries inside a namespace, each with its own body —
function first<T>(items: T[]): T function first<infer T>(…); TypeScript’s infer keyword is unrelated uninferred-type-parameter at the declaration
identity<string>(x) none; every type argument is inferred foreign-syntax

Control flow

if is a statement and produces no value. define is the conditional expression, and match branches on a value’s case; both produce a value. There is no loop statement.

JavaScript or TypeScript Essence If you forget
if (c) { … } else if (d) { … } else { … } if c { … } else if d { … } else { … }, with no parentheses syntax-error
if (count) if count::isNot(0); only a Boolean is a condition syntax-error as written; condition-not-boolean for if count
an if used as a value define { as a if c as b otherwise } syntax-error
switch (x) { case …: } match x -> T { case … }, exhaustive, with its result type written, -> T foreign-syntax for switch; missing-case when a case is left out
default: case _ —
for (const item of items) items::map(f), reduce, or loop(from 1, through 10, startingWith 0, f) syntax-error; uninferable-return-type for a function passed to map with no <-
items.forEach(f) none; to print each item, print items::join(with "\n") once, or map with a function that returns: items::map((item) { <- Terminal.print(item) }) type-without-members for items.forEach(f); unknown-method for items::forEach(f); uninferable-return-type for a function with no <-
while (c) { … } loop(startingWith s, while p, f), where p is a function from the state to a Boolean foreign-syntax, whatever the body holds
break, continue loop(startingWith s, step f), where f returns #Done(value) to stop and #Continue(next) to go round again foreign-syntax

Types

A type names a shape and is structural. A choice is a closed set of cases and is nominal. There are no classes.

JavaScript or TypeScript Essence If you forget
type Point = { x: number } type Point = { x: Integer }; a record with more members still fits unknown-type
interface Point { x: number } type Point = { x: Integer } foreign-syntax
{ kind: "circle", radius } | { kind: "square", side } choice Shape { Circle { radius: Rational }, Square { side: Rational } }, built as #Circle({ radius = 1/2 }) missing-case when a match leaves a case out
"fast" | "slow" choice Speed { Fast, Slow }; there are no literal types syntax-error
enum Color { Red, Green } choice Color { Red, Green }, used as #Red; to print one, declare namespace Colors for Color is Printable {} foreign-syntax for enum; unsatisfied-bound when printed without that namespace
Red for a case of choice Color #Red; the # is what tells a case from a name unknown-name, naming every choice that declares the case
A | B A | B, the same; narrowed by match, never by typeof foreign-syntax for typeof
[string, number] a record with two named members; there are no tuples syntax-error
class a type for the shape and a namespace for its methods foreign-syntax
value as Point constant point: Point = value; there is no cast unknown-name
readonly, Readonly<T> nothing to write; records, lists and dictionaries are immutable —
type Tree = { children: Tree[] } none; a type or choice cannot name itself recursive-type-declaration
T extends Comparable <infer T is Comparable> syntax-error
a branded type checked by a type guard a checked refinement: type Positive = Integer where @::isPositive(), proven by an if —

Namespaces and protocols

Methods live in namespaces, outside the type. A protocol is a contract: a namespace declares it meets one with is Named (a conformance), and a type parameter requires one with <infer T is Named> (a bound).

JavaScript or TypeScript Essence If you forget
value.method() value::method() method-called-with-dot where the method exists; type-without-members where it does not
Money.of(12) Money.of(12): . calls a static, as in JavaScript static-method-on-value when called with :: on a value
this @ foreign-syntax
class Money { euros() { … } }, Number.prototype.euros namespace Money for Integer { euros() -> Integer { … } } foreign-syntax, once; the class body is read past rather than into
using a class above its declaration a namespace cannot be used by a statement above it use-before-declaration
static rate = 100 static rate = 100, read as Money.rate —
interface Named { name(): string } protocol Named { name() -> String } foreign-syntax
class Person implements Named namespace People for Person is Named; having the method is not conforming syntax-error for implements; unsatisfied-bound without is Named
a concrete method on an abstract class a method with a body in the protocol —
interface Loud extends Named { shout(): string } protocol Loud is Named foreign-syntax, naming the extends
Named as a type, Named[] none; a protocol is a bound or a conformance, and a union such as Book | Movie stands in, reaching name() when both types conform protocol-as-type
T extends A & B one bound per parameter; protocol Both is A, is B combines them syntax-error

Modules

A file is a module with named exports, the way ES modules work.

JavaScript or TypeScript Essence If you forget
import { a, b as c } from "./x" import { from "./x.es" { a b as c } }, with no commas syntax-error
"./x" with no extension "./x.es" invalid-module-specifier
export function f … export { f }, in a block below implementation unknown-name inside implementation; unexpected-token below it
export default f none; every export is named unexpected-token
export { a } from "./x" from "./x.es" { a } inside the export block —
import * as money from "./x" none; each name is imported syntax-error
import { chunk } from "lodash" none; a specifier is a relative path to an .es file invalid-module-specifier
require("./x") none; import only foreign-syntax
two modules importing each other allowed; a constant of the other module is read only once the modules have loaded cyclic-load-time-use

Tooling

One essence command does the work of several tools, and tests live in the source file.

JavaScript or TypeScript Essence If you forget
tsc --noEmit essence check —
esbuild --bundle essence build, one self-contained JavaScript file —
node file.js, tsx file.ts essence run file.es —
vitest, jest essence test; the tests are a tests { … } section at the end of the file test-outside-tests
describe, it, expect(x).toBe(y) suite "…", test "…", expect x::is(y) foreign-syntax at the => of describe("…", () => …); unknown-name for expect(x).toBe(y)
tsconfig.json essence.json, optional, written by essence init —
prettier essence format, with nothing to configure —
console.log(x) Terminal.print(x) foreign-syntax
console.dir(x) Terminal.inspect(x) foreign-syntax

What the compiler says when you type JavaScript

Most of these errors name the JavaScript habit they refuse, and the table below pairs each with its fix. Each error starts with its code in brackets and a one-line message, then points at the code, like this one for constant total = 1 + 2:

[operator-not-supported]
Error: Essence has no '+' operator
   ╭─┤ Total.es:2:21 │
   │
 2 │     constant total = 1 + 2
   │                        ▲  
   │                        ╰── this is not a Method call
   │ 
   │ Help 1: Write 'a::add(b)' for Numbers.
   │ Help 2: Write 'a::append(b)' to join two Strings.
   │ 
   │ Note: Arithmetic, comparison and logic are Method calls in Essence, read left to right — there are no operators, and so no precedence to remember.
───╯

The table lists the errors you are likely to hit first: what you typed, the error’s code and message, and the fix. Where your editor offers a Quick Fix, it writes the fix for you.

You typed The compiler says The fix
1 + 2 operator-not-supported: Essence has no '+' operator 1::add(2)
"a" + "b" operator-not-supported: Essence has no '+' operator "a"::append("b")
count / 3 operator-not-supported: Essence has no '/' operator count::divide(by 3)
1 == 1, 1 === 1 operator-not-supported: Essence has no '==' operator 1::is(1)
true && false operator-not-supported: Essence has no '&&' operator true::and(false)
!true operator-not-supported: Essence has no '!' operator true::negate()
-price operator-not-supported: Essence has no '-' operator price::negate()
Terminal.print(items[0]) foreign-syntax: A value is not indexed with brackets Terminal.print(items::item(at 0))
text.length method-called-with-dot: 'length' is a Method, not a member text::length()
text.charAt(0) type-without-members: This value has no members to look up text::character(at 0)
const total = 1 foreign-syntax: 'const' is not how Essence declares a binding constant total = 1
let count = 0 foreign-syntax: 'let' is not how Essence declares a binding variable count = 0
constant total = 1; foreign-syntax: A Statement does not end with ';' constant total = 1
{ x: 1, y: 2 } foreign-syntax: A Record member is written with '=' { x = 1, y = 2 }
point.x = 2 foreign-syntax: A Record's member can not be assigned { point with x = 2 }
return n foreign-syntax: 'return' is not how Essence answers with a value <- n
(n: Integer) => n foreign-syntax: A Function literal has no '=>' (_ n: Integer) -> Integer { <- n }
[1, 2]::map(n => n) foreign-syntax: A Function literal has no '=>' [1, 2]::map((n) { <- n })
(n) { n::add(1) } uninferable-return-type: The return Type could not be inferred from the body (n) { <- n::add(1) }
true ? 1 : 2 foreign-syntax: Essence has no conditional operator define { as 1 if true as 2 otherwise }
identity<Integer>(1) foreign-syntax: A call writes no Type Arguments identity(1)
if (count::isEven()) { syntax-error: Expected a Type but found ':'. if count::isEven() {
if (ready) { syntax-error: Expected '{' but found '}'. if ready {
`hi` foreign-syntax: A String is written in double quotes "hi"
'hi' foreign-syntax: A String is written in double quotes "hi"
// a comment foreign-syntax: A Comment is written with '§' § a comment
console.log("hi") foreign-syntax: 'console' names nothing in Essence Terminal.print("hi")
null foreign-syntax: 'null' names nothing in Essence #Empty, in an Optional
Red, for a case of choice Light unknown-name: 'Red' is not declared, with a note naming Light #Red
number as a type unknown-type: Type 'number' is not declared Integer or Rational
interface Point { x: Integer } foreign-syntax: 'interface' declares nothing in Essence type Point = { x: Integer }
constant snake_case = 1 syntax-error: Expected '=' but found '_'. constant snakeCase = 1

Same as JavaScript

These need no relearning. Each carries its one caveat.

  • Function hoisting. A function can be called above its declaration. Caveat: a namespace cannot be used by a statement above it.
  • The constant’s dead zone. A constant cannot be read above its line, the way const has a temporal dead zone. Caveat: a function body written above the constant cannot read it either.
  • { x, y } shorthand. It builds a record from the names in scope. Caveat: { point with x } merges a record named x; it is not shorthand for x = x.
  • Structural object types. A record with more members passes where a narrower type is asked for, and keeps them. Caveat: a literal written where a type is declared is checked for extra members, as TypeScript’s excess-property check does; a value passed along keeps them.
  • Renames with as. constant { y as row } = point and from "./Money.es" { twice as double }. Caveat: in a pattern, : annotates a type instead of renaming.
  • ES-module shape. A file imports by relative path and exports by name. Caveat: the .es extension is written, and there is no default export.
  • Default parameters are evaluated per call, in the callee. A default runs on every call that leaves its argument out, and may read the parameters to its left. Caveat: a call that passes the argument still writes its label.
  • reduce is accumulator-first. [1, 2, 3]::reduce(startingWith 0, (total, item) { <- total::add(item) }) is 6. Caveat: the start value comes first, labelled startingWith.
  • 1_000. Digit groups are separated with _, after a decimal point too: 1_000.000_5. Caveat: _ belongs to numbers only, so snake_case is not a name.
  • "".split("\n") is [""]. ""::split(on "\n") prints [""]. Caveat: the separator is labelled on.

What is not in the language

Each entry names what stands in its place, where anything does.

  • Operators. Arithmetic, comparison and logic are method calls.
  • null and undefined. A value that may be missing is an Optional.
  • Truthiness. A condition is a Boolean; if count is refused as condition-not-boolean.
  • Exceptions. There is no throw, try or catch; a failure with a reason is a Result.
  • Mutation of data. Records, lists and dictionaries are immutable; with builds a new record and append a new list.
  • Loop statements. There is no for, while, break or continue; iteration is map, reduce and the loop family.
  • Classes and new. A type names a shape, a namespace holds its methods, and a literal builds the value.
  • Recursive type declarations. A type or choice cannot name itself, so a tree is not a type you can declare.
  • Tuples. A pair is a record with two named members.
  • File or JSON in the standard library. Terminal prints, writes, inspects and reads the program’s input, and Http sends a request.
  • async, await and Promise. Work that has not run is a Future, a value: complete waits for what one answers with and start puts one in flight. See Asynchrony.
  • Floating point. Integer and Rational are exact: 0.1::add(0.2)::is(0.3) is true.
  • Calling JavaScript from Essence. An import names .es files only; a .js specifier is an invalid-module-specifier. JavaScript calls Essence instead, as Calling Essence from JavaScript shows.
  • Call-site type arguments. identity<Integer>(1) is refused as foreign-syntax: a call writes no type arguments, and every one of them is inferred.
  • More than one protocol bound per parameter. <infer T is A, is B> is a syntax error. Combine them through a protocol: protocol Both is A, is B is the one bound.
  • Reading program arguments. No standard-library function reads the arguments a program was started with.
esc