-
Notifications
You must be signed in to change notification settings - Fork 0
Overview
Chris Harvey edited this page Jun 9, 2022
·
8 revisions
This page is a quick overview of the Solid language. For details, read the Reference and the Specification.
Subsections containing “(FUTURE)” describe planned features that are not yet implemented.
% line comment (no line breaks)
%% block
comment, with
line breaks,
no nesting %%
let variable_name: TypeExpr = expr;
let unfixed reassignable: TypeExpr = expr;
set reassignable = other_expr;
let `váriåblė nāmė`: TypeExpr = expr;
type TypeName = TypeExpr;
type `Typė Nāmė` = TypeExpr;
No values are assignable to the never
type.
functionFails.(); % never completes evaluation
functionReturnsNothing.(); % completes evaluation, but not an actual value
let a: .SINGLETON = .SINGLETON;
let n: null = null;
let unfixed b: bool = true;
set b = false;
let unfixed i: int = 42;
set i = -42;
set i = 42_000;
let bin: int = \b10_1010;
let quad: int = \q222;
let oct: int = \o52;
let hex: int = \x2a;
let htd: int = \z16; % hexatridecimal (base 36)
let unfixed f: float = 4.2;
set f = 42.;
set f = 0.42;
set f = 42_000.0;
set f = 4.00_000_2;
set f = 6.28318e2; % 628.318
set f = 6.28318e-2; % 0.0314159
let string: str = 'hello world';
let with_line_feed: str = 'hello
world'; % line feed is preserved
let with_line_continutation: str = 'hello\
world'; % line feed is converted to a space
let with_escapes: str = '
- hello\sworld (space)
- hello\tworld (tab)
- hello\nworld (line feed)
- hello\rworld (carriage return)
- \'apostrophes\'
- \% percent signs \%
- \\ back-slashes \\
- I \u{2764} (❤) Unicode
';
let with_instring_comments: str = '
This is a string! % line comment ignored
This is %% multiline
comment ignored %% a string!
Use \% to escape a percent sign.
';
let template: str = '''hello world''';
let with_line_feed: str = '''hello
world''';
let no_line_continutation: str = '''hello\
world'''; % preserves backslash and line feed
let no_escapes: str = '''
- \s \t \n \r do not escape
- \' \% \\ do not escape
- \u{2764} does not escape
''';
let no_comments: str = '''
% in-string line comments are *not* ignored!
%% in-string multiline comments
are *not* ignored! %%
''';
let h: str = 'Hello';
let w: str = 'world';
let unfixed interpolation: str =
'''{{ h }}, {{ w }}!'''; % 'Hello, world!'
set interpolation =
'''7 * 3 * 2 is {{ 7 * 3 * 2 }}'''; % '7 * 3 * 2 is 42'
set interpolation =
'''empty {{}} interpolation'''; % 'empty interpolation'
let unfixed interp_comment: str = '''
This is {{ %% multiline comment ignored %% }} string content!
''';
set interp_comment = '''
This is {{ 'string' % line comment ignored
}} content!
''';
let unfixed anything: obj = null;
set anything = .FORTY_TWO;
set anything = true;
set anything = 42;
set anything = 4.2e+1;
set anything = 'forty-two';
let anything: obj = any_object;
let literally_anything: unknown = anything;
type Nullish = T?; % T | null
type Exceptionish = T!; % T | Exception % (FUTURE)
type GeneratorOf = T*; % Generator.<T> % (FUTURE)
type PromiseOf = T/; % Promise.<T> % (FUTURE)
type Intersection = A & B;
type Union = A | B;
type DiscriminatedUnion = A ^ B; % (FUTURE)
let is_falsy: bool = !a; % `true` iff `a` is `null`, `false`, of type `void`, or an exception
let is_empty: bool = ?a; % `true` iff `a` is falsy, a zero, or an empty string/collection
let affirm: int | float = +a; % the value of a numeric value, otherwise no-op
let negate: int | float = -a; % negates a numeric value only
let `await`: unknown = a~~; % (FUTURE)
let next: unknown = a++; % (FUTURE)
let addition: int | float = a + b;
let subtraction: int | float = a - b;
let multiplication: int | float = a * b;
let division: int | float = a / b;
let expenontiation: int | float = a ^ b;
3 / 2 == 1;
3.0 / 2 == 1.5;
3.0 / 0; % error
4 ^ -2 == 0;
4.0 ^ -2 == 0.0625;
-3 ^ 2 == 9;
-(3 ^ 2) == -9;
a ^ b ^ c == a ^ (b ^ c);
let less_than: bool = a < b;
let less_or_equal: bool = a <= b;
let not_less: bool = a !< b;
let greater_than: bool = a > b;
let greater_or_equal: bool = a >= b;
let not_greater: bool = a !> b;
let instanceof: bool = a is b; % (FUTURE)
let notinstanceof: bool = a isnt b; % (FUTURE)
let identity: bool = a === b;
let nonidentity: bool = a !== b;
let equality: bool = a == b;
let inequality: bool = a != b;
0 === -0;
0 == -0;
0.0 !== -0.0; % -0.0 and 0.0 are not identical
0.0 == -0.0;
42 !== 42.0;
42 == 42.0;
'' === ''; % new strings reuse memory
'' == '';
let and: obj = a && b; % short-circuits
let nand: bool = a !& b;
let or: obj = a || b; % short-circuits
let nor: bool = a !| b;
let pipe: bool = a |> b; % `b.(a)`, but evaluates `a` before `b`
let `then`: bool = a ~> b;
let conditional: obj = if a then b else c; % short-circuits
let x: int = 42;
set x += expr; % x = x + (expr)
set x -= expr; % x = x - (expr)
set x *= expr; % x = x * (expr)
set x /= expr; % x = x / (expr)
set x ^= expr; % x = x ^ (expr)
set x &&= expr; % x = x && (expr) % short-circuits
set x ||= expr; % x = x || (expr) % short-circuits
let tuple: [int, float, str] = [3, 4.0, 'five'];
let a: int = tuple.0; % 3
let b: float = tuple.1; % 4.0
let c: str = tuple.2; % 'five'
tuple.0 == tuple.[0];
tuple.1 == tuple.[3 - 2];
tuple.-3 == tuple.[0];
tuple.-2 == tuple.[1];
tuple.3; % TypeError
tuple.-4; % TypeError
[3, 4.0, 'five'] == [3, 4.0, 'five']; % equal
[3, 4.0, 'five'] !== [3, 4.0, 'five']; % but not referentially identical
tuple == tuple;
tuple === tuple; % a pointer is always referentially identical to itself
let record: [
alpha: int,
bravo: float,
charlie: str,
] = [
alpha= 3,
bravo= 4.0,
charlie= 'five',
];
let a: int = record.alpha; % 3
let b: float = record.bravo; % 4.0
let c: str = record.charlie; % 'five'
record.charles; % invalid
let delta: int = 16;
let record1: [delta: int] = [delta= 32];
let record2: [delta: int] = [delta= delta]; % outer `delta`
delta == 16;
record1 == [delta= 32];
record2 == [delta= 16];
let record: [echo: bool] = [
echo= true,
echo= false, % override
];
record == [echo= false];
record.count == 1; % size
let override_count: [count: int] = [count= 2];
override_count.count == 2; % not size
let list: (int | float | str)[] = List.<int | float | str>([3, 4.0, 'five']);
let a: int | float | str = list.0; % 3
let b: int | float | str = list.1; % 4.0
let c: int | float | str = list.2; % 'five'
list.count == 3; % size
let dict: [:int | float | str] = Dict.<int | float | str>([
alpha= 3,
bravo= 4.0,
charlie= 'five',
]);
let a: int | float | str = dict.alpha; % 3
let b: int | float | str = dict.bravo; % 4.0
let c: int | float | str = dict.charlie; % 'five'
dict.count == 3; % size
let `set`: (int | float | str){} = Set.<int | float | str>([3, 4.0, 'five']);
`set`.has.(3); % true
`set`.has.(4.0); % true
`set`.count == 3; % size
let map: {int | str -> str | [str] | [i: {str -> str}]} = {
1 -> 'who',
'2nd' -> ['what'],
1 + 2 -> [i= {'don’t' -> 'know'}],
};
map.count == 4; % size
map.get.(1) == 'who';
map.get.(2).0 == 'what';
map.get.(3).i == {'don’t' -> 'know'};
let x: int = 42;
[
y= 43,
x$, % x= x
];
let tuple: mutable [int, float, str] = [3, 4.0, 'five'];
set tuple.0 = 6;
tuple == [6, 4.0, 'five'];
let record: mutable [
alpha: int,
bravo: float,
charlie: str,
] = [
alpha= 3,
bravo= 4.0,
charlie= 'five',
];
set record.alpha = 6;
record == [
alpha= 6,
bravo= 4.0,
charlie= 'five',
];
let tuple: mutable [int, float, ?:str] = [3, 4.0];
tuple.2; %: str | void % might cause a runtime error
tuple?.2; %: str | null % no runtime error
set tuple.2 = 'five';
let record: mutable [
alpha?: int,
bravo: float,
charlie: str,
] = [
bravo= 4.0,
charlie= 'five',
];
set record.alpha = 6;
[3, 4.0, 'five'] !== [3, 4.0, 'five']; % regular collections allocate new memory
@[3, 4.0, 'five'] === @[3, 4.0, 'five']; % constant collections reuse memory (like strings)
[3, 4.0, 'five'] == @[3, 4.0, 'five']; % have the same items
let contains_computable_expressions: [alpha: float] = @[alpha= @[3].0 + 2];
@[my_var, [3]]; %> SyntaxError % cannot contain variables or regular collections
let tuple: mutable [int, float, str] = @[3, 4.0, 'five']; %> TypeError % cannot be mutable
if expression then {
run_if_true;
} else {
run_otherwise;
};
if expression then {
run_if_true_then_exit;
} else if expression2 then {
run_if_true_then_exit;
} else {
run_otherwise;
};
if true then {
dangling_else;
};
unless expression then {
run_if_false;
} else {
run_otherwise;
};
unless expression then {
run_if_false_then_exit;
} else unless expression2 then {
run_if_false_then_exit;
} else {
run_otherwise;
};
unless false then {
dangling_else;
};
while expression do {
repeat_as_long_as_true;
if loop_should_end then {
break;
} else if iteration_should_stop_but_continue_looping then {
continue;
} else {};
};
do {
run_once_then_repeat_as_long_as_true;
} while expression;
until expression do {
repeat_as_long_as_false;
while inner_condition do {
if continue_inner_loop_only then {
continue 0;
} else if continue_inner_and_outer_loops then {
continue 1;
} else {};
};
};
do {
run_once_then_repeat_as_long_as_false;
} until expression;
for index from start to end by incr do {
'run while `index` is >= `start` and < `end`,
increasing `index` by `incr` each iteration,
and re-evaluating `end` each time.';
};
for index from start to end do {
'run while `index` is >= `start` and < `end`,
incrementing `index` by 1 each iteration,
and re-evaluating `end` each time.';
};
for index in 1..10 do {
'run while `index` is >= 1 and < 10,
incrementing `index` by 1 each iteration.';
};
for item of iterable do {
'run for each item in the iterable…
could be a tuple, list, set, or generator.';
};
func myFunction(x: int, y: float, z: str): bool {
return true;
}
let result: bool = myFunction.(42, 4.2, '0.42');
result == true;
let call_named: bool = myFunction.(42, z= '0.42', y= 4.2);
func implicitReturn(x: int, y: float, z: str): bool => true;
let my_lambda: (int, float, str) => bool = (x, y, z) { return true; };
let implicit_return: (int, float, str) => bool = (x, y, z) => true;
my_lambda.(42, 4.2, '0.42'); % valid
my_lambda.(x= 42, y= 4.2, z= '0.42'); % invalid
func named_params(x: int, y: float, z: str): bool { return true; }
named_params.(x= 42, y= 4.2, z= '0.42'); % valid
named_params.(42, 4.2, '0.42'); % also valid
let lambda_named_params: (x: int, y: float, z: str) => bool = (x, y, z) { return true; };
lambda_named_params.(x= 42, y= 4.2, z= '0.42'); % valid
lambda_named_params.(42, 4.2, '0.42'); % also valid
func named_aliases(x as a: int, y as b: float, z as c: str): bool {
x; y; z; %> ReferenceErrors
a; b; c; % valid
return true;
};
named_aliases.(x= 42, y= 4.2, z= '0.42');
let lambda_named_aliases: (x: int, y: float, z: str) => bool = (x as a, y as b, z as c) {
x; y; z; %> ReferenceErrors
a; b; c; % valid
return true;
};
lambda_named_aliases.(x= 42, y= 4.2, z= '0.42');
let x: int = 42;
f.(
44,
y= 43,
x$, % x= x
);
func myFunction(
required: int,
optional1: int = default1,
optional2: int = default2,
optional3 as opt3: int = default3,
): void {
required; % int
optional1; % int
optional2; % int
optional3; %> ReferenceError
opt3; % int
}
% typeof myFunction == '(required: int, optional1?: int, optional2?: int, optional3?: int) -> {void}'
myFunction.(a); % `myFunction.(a, default1, default2, default3)`
myFunction.(a, b); % `myFunction.(a, b, default2, default3)`
myFunction.(a, b, optional2= c); % `myFunction.(a, b, c, default3)`
myFunction.(a, b, optional3= d); % `myFunction.(a, b, default2, d)`, but evaluates `d` before `default2`
myFunction.(a, b, optional1= c); % `myFunction.(a, c, default2, default3)`, but evaluates `b` before `c`, then discards `b`
myFunction.(a, b, optional3= d, optional2= c); % `myFunction.(a, b, c, d)`, but evaluates `d` before `c`
func async myAsyncFunction(x: int, y: float, z: str): bool {
let xx: int | Promise.<int> = x;
let yy: float | Promise.<float> = y;
let zz: str | Promise.<str> = z;
let await_x: int = x~~;
let await_y: float = y~~;
let await_z: str = z~~;
return true;
}
let promise: bool/ = myAsyncFunction.(42, 4.2, '0.42'); %: Promise.<bool>
promise != true;
let awaited: bool = promise~~;
awaited == true;
let call_and_await: bool = myAsyncFunction.(42, 4.2, '0.42')~~;
call_and_await == true;
many.function~~.calls.().and.()~~.awaits.may~~.be.().chained.()~~;
func gen myGenFunction(x: int, y: float, z: str): str {
let xx: int = x + 2;
yield '''{{ xx }}''';
let yy: float = y * 2;
yield '''{{ yy }}''';
yield '''{{ z }}{{ z }}''';
}
let generator: str* = myGenFunction.(42, 4.2, 'hello'); %: Generator.<str>
generator.done == false;
let xxx: str? = generator++;
generator.done == false;
xxx == '44';
let yyy: str? = generator++;
generator.done == false;
yyy == '8.4';
let zzz: str? = generator++;
generator.done == false;
zzz == 'hellohello';
let last: str? = generator++;
generator.done == true;
last == null;
many.function++.calls.().and.()++.nexts.may++.be.().chained.()++;