Gotchas
The things most likely to surprise you, especially coming from Python. Each links to the chapter that explains it.
Names and layout#
- A name cannot be reused while it is visible. A second
let countin an inner block, a parameter named like a top-level function, or a local named like an import, is an error. Syntax - The built-in names are reserved:
list,map,set,str,int,task,unit,print,errorand the others cannot name a variable, parameter or function; a field or a method may take one. Syntax abs,min,max,round,ord,chrandinputare in modules:import mathformath.abs(x),import textfortext.code_of(s),import consoleforconsole.read_line(). Types and valueshash(x)is a method,x.hash(). Types and values- Names are ASCII.
caféis not a valid name; text and comments may hold anything. - Indentation is four spaces; tabs are errors. There is no
\line continuation: wrap in parentheses. Syntax - An unused result is an error. Write
_ = f()to drop it on purpose. Syntax - An unused import is an error, and imports must come before declarations. Modules and packages
- Code after an unconditional
returnorerroris an error, not dead code.
Values and types#
- Structs and enums are copied on assignment and when passed, unlike Python objects. Use a class for something shared. Structs and enums
- A
letstruct cannot change at all; aletlist, map or class object can, sinceletonly fixes which object the name refers to. Collections - A method that changes a struct needs a
varreceiver. Structs and enums - A class has no
==orprintuntil it declaresEquatableorDisplay. Classes - There is no inheritance. Use interfaces, composition, or an enum. Classes
- An empty
[],{}ornoneneeds its type written:let names: list[str] = []. Types and values {}is an empty map; an empty set islet s: set[int] = {}.- Strings print without quotes, also inside lists:
[a, b], not['a', 'b']. Types and values - A fallible
initis written-> unit!. Classes
Numbers#
intandfloatnever mix:count * 1.5and1 == 1.0are errors. Convert withfloat(count). Expressionsintoverflow traps. Integers have 64 bits, not Python's unlimited size.1 / 0isinf, since/is a float division;1 // 0traps.2 ** -1traps; write2.0 ** -1.0.- No unsigned integers or other sizes. The bit operators work on the 64-bit
int, and<<traps when the result does not fit, where Python's would grow. Use a Base module for fixed sizes. Luce and Base - A format specification must fit its value's type:
f"{count:.2f}"of anintis an error; writef"{float(count):.2f}". Text and bytes math.roundtakes and gives afloat:math.round(2.5)is2.0, andmath.round(3)is an error. Types and valuesmath.minandmath.maxtake two values; a list hasvalues.min()andvalues.max().mathalone is the language's module; luce-std's isfrom luce_std import math, under another name when a module wants both. Standard library
Text#
- A string cannot be indexed:
word[0]is an error; useword[0..<1]or afor. Text and bytes - Slices use ranges:
text[1..<3],values[2..], not[1:3]. upper()andlower()change ASCII letters only. Useunicode.to_upperfor all of Unicode.split(",")keeps empty pieces, as in Python;split()splits on runs of white space.- Searches answer
none, not-1:index_of,last_index_of. Text and bytes joinis a list method:["a", "b"].join(", ").- Formatted strings are one line;
f"""is not available. - Single quotes are not strings.
Collections#
m[key]answers an optional, never raisesKeyError: writem[key] else defaultorm.get(key, default). Collections- A
forover a map gives(key, value)pairs, not keys. Collections and loops - Changing a collection's size inside a
forover it traps. sorted,min,max,sum,anyandzipover a list are methods:values.sorted(key = f), notsorted(values, key=f). Collections- A step is a method of the range:
(0..<10).step(2), notrange(0, 10, 2). Control flow - No comprehensions: use
mapandfilter. - An out-of-range slice traps instead of shortening.
Absence and failure#
- A
T?must be unwrapped before use, withif let,elseormatch; checking!= nonedoes not unwrap it. Optionals and errors - There is no
?.and no forced unwrap. - A failure passes up by itself inside a
!function, but a function without!mustcatchevery fallible call. Optionals and errors int("x")andfloat("x")can fail: in a function without!, catch them.- A trap cannot be caught, and
asserttraps, in every build. Optionals and errors - In a test, a failed
assertends the whole run;error(...)fails just that test. Testing T!cannot be stored; useResult[T]. Optionals and errors
Functions#
- Parameters cannot be assigned; bind a
varcopy. - Functions cannot be nested; use a lambda. Functions
- An expression lambda needs its parameter types from context, or written:
(n: int) => n + 1. Functions - Generic type arguments are not inferred through an interface: write
drain[int](x). Generics
Workers, modules and Base#
- Workers take copies of values; class objects and closures cannot be sent. Workers
- No global variables, and a top-level
letmust be a constant. Modules and packages - A package is not a module:
import luce_stdis an error;from luce_std import files. - Another module cannot print a struct with a private field, nor set that field or call an
initthat is notpub; the struct declaresDisplay, or its module offers apubfunction. Visibility - A program that imports Base must be built:
luce runrefuses it. Luce and Base - Base functions with pointers or other Base-only types are invisible to Luce. Luce and Base