Tip
This section is a bird view of U syntax. Please read the overview and check Syntax for more details.
U properties are:
- U syntax is designed to be concise and expressive,
- Source code is UTF-8 encoded,
- Comments, characters and string literals can contain Unicode characters,
- Default character value is as wide as a Unicode character: up to 4 bytes,
- No direct keyword: anything that starts with colon
:
or\
is a special parser hint called aperture, - U keywords are guarded with
::
, like::if
, - U is whitespace sensitive for good reasons. See Syntax,
- U uses curly braces
{}
to denote functions. U does not use indentation for good reasons. See Braces vs Indentation, - Everything is either a value or an expression,
- Values are immutable by default, but you can make them mutable,
- U has OOP with a more flexible syntax that others languages,
- Most behaviors can be customized by build system ugo.
Comments¶
Execute Without Main¶
Execute With Main¶
Statements¶
U is line-based, with optional semicolons because it's visually pleasing.
Semicolons are only necessary if you want to write multiple statements on a single line.
Symbols¶
Symbols start with colon :
followed by a name.
:var : 2 # ':var' is a Symbol named 'var', compiler will convert it to a number
f var - 3 # 'f', 'var' are Identifiers
:"a -> b" # With spaces
:1234 # From a number
:'*' # From operator
:name : :foo
:(name) # From an expression
:\'A' # From a Char
:timon : "Timon, U's logo"
# Unicode
:丁满 : "丁满 in chinese"
:Тимон : "Тимон in russian"
:🐨 : "koala that looks like Timon"
:π : 3.14159
# Operator in names
:is_enabled?
:shift->> : # function
:'+++' ...
Identifier¶
Identifiers are reference names.
Delimiters¶
In U, delimiters are Values:
(...)
: lexical level grouping{...}
: define a function, closure, or any construct that need to execute statements[...]
: define a data model that needs storage at compile time or at run time like sets, array, hash map
See below for examples.
Variables¶
In U, variables are defined with colon :
and a name.
Types¶
U infers value types. You don't need to specify them unless the compiler needs your hints.
Types starts with @
for user defined type, @
for built-in types:
:x : @int64 # Built-in 'int'
:model : @Model3D # user defined model
# Custom type - Imperative style
@Array-of-string-int-pair @[@string, @int]
No Null Value¶
U has no concept of null
only optional types.
For example:
:result : @? fun-call ...
#same as
:result : ::some fun-call ...
# 'fun-call' might not return a value
Booleans¶
Numbers¶
# Integer
1234 # Integer
1_234 # Integer
# Floating point: FP
12.34 # Decimal FP
1234e-5 # Decimal FP
# Hexadecimal FP
0x1.FFp4
Characters¶
Characters start with escape \
followed by quotes:
Strings¶
In U, three quote types denote values:
'...'
: single quote,"..."
: double quote,`...`
: backtick or left quote.
:name : 'Alice' # Immutable
:name :! 'Alice' # Mutable
\< "Welcome " + name
# Prints "Welcome Alice"
:%-"
this is a
multline string
%"
'a'.%ascii # Convert to ascii
'a'.%ascii:code # Get ascii code
'a'.%U:scalars # Get utf8 scalars
String Interpolation¶
Without spaces, use \:
\(
and \)
or any delimiter:
String Constructors¶
String Constructors let you define string behaviors before creating it. It allows powerful optimizations. String Constructors start with :%
for immutable strings, and :%!
for immutable strings.
:str : :%(max: 5)'peace'
# Immutable string with a maximum capacity of 5 characters
:str : :%{: lhs; ... }'peace'
# Immutable string with in line constructor. 'lhs' (left hand side) is 'peace'
Ranges¶
0:.:2 # 0,1,2
0:.<:2 # 0,1
0:<.:2 # 1,2
0:<.<:2 # 1
0:+2:6 #[0,2,4,6]
6:-2:0 #[6,4,2,0]
# Iterator
'a':.:'z' {: v
\< v
}
Regexp¶
:line : :/[^\n]+/
# Escaping '/'
:path : :/\/?(\w+\/)+/
# Without escaping '/', use '{}'; useful when parsing URLs
:line : ::R{/?(\w+/)+}
Variants or Enums¶
Variants starts with keywords ::Variant
, ::V
, ::Enum
, or ::E
. Variants can have methods.
::V :Day, [
:Monday: 1,
:Tuesday, :Wednesday, :Thursday, :Friday, :Saturday,
:Sunday
], {
# Define methods
:to_str : {?
:- Monday: "Monday"
...
}
}
Classes¶
Classes are defined keyword ::A
or ::An
. Inheritance, Composition, Aggregation have special meaning in U,
and are not the same as C++/Java. Please refer to syntax.
# class 'Position' with attribute 'x' as int
::A :Position, :x: @int, ...
::A :Position, {
# Constructors
(:x, :y) : (... @Int)
}, {
# Body if needed
:move : ...
}, ... # Options
Objects¶
Objects are defined with keywords ::a
, ::an
, or Object::new
.
# class 'Position' with attribute 'x' as int
::A :Position, :x: @int, ...
:pos1 : ::a @Position, ...
:pos2 : @Position::new ...
pos2.x = 1
Collections¶
Collections are structures that group values. Collections are 0-based indexed.
Sequences¶
Arrays¶
Lists¶
Sets¶
Hashes¶
:h :! [< :name: 'Megan', :role >] # Shorthand for ':role: :role'
\< h[:name]
# Prints 'Megan'
h[:name] := 'Francis'
\< h[:name]
# Prints 'Francis'
Matrices¶
:φ : 3
:mat_4_4 : :%|
1 2 3
4 \#φ 5 # Use variable <φ>
5 6 7
%|
#Same as
:mat_4_4 : [|
1,2 , 3;
4, φ, 5;
5, 6, 7
|]
Tables¶
Tables are collections of columns. Columns can have different sizes.
Which is the same as:Then:
\< t.cols-names= :c1, :c2
#(
Prints
C1 | C2
---|---
a 4
b 3
a 2
d 1
#)
#In-place modifications
t.first.sort-asc!
t.last.sort-asc!
\< t
#(
Prints
C1 | C2
---|---
a 1
a 2
b 3
d 4
#)
\< t@json
#(
Prints
{"a": 2, "b": 3, "d": 4}
# "a" with value 1 overwritten
#)
Collections Iterators¶
Collections Access¶
:a :! [0, 'blue' , 2]
a[1] # 'green'
a[0] := 'red'
a <<= 'green' # ['red', 'blue' , 'green']
#With default value
# Return element at 5 or a default string
\< a[5, 'no value']
# Prints 'no value'
Collections Specifiers¶
:a :! [:( # Specifiers start
@int, # All elements must be ints
:capacity: 2, # Only 2 elements
:before_create: :> ...., # Before creating the collection
:'before_<<': :> e :: !? e.odd # Ensure that all items are even; 'before-<<' means 'before-pushing'
): # Specifiers end
# ... elements
]
a <<= 0 # OK
a <<= 1 # OK
a <<= "hello" # Error: only ints
a <<= 2 # Error: max 2
Collection Comprehension¶
Collection Comprehensions are special kind of specifiers.
Collection Slices¶
:a : [0,1,2, 3, 4, 5, 6]
:b : a[1:.:4] # Slice from 1 to 4
:c : a[0:+2:4] # From 0 to 4 by +2; 'c' <=> [0,2,4]
Function and Closures Definitions¶
Signature¶
Signatures consist of the function’s parameters, return type, and optional specifiers.
Optional Return¶
By default, the return value is the last statement one. But you can use ::return
keyword, or \^
.
:add : {:
#implicit return
3 + 2
}
# Explicit
:add : {:
:result : ...
\^ result
# Or
::return result
}
All return statements start with \^
. The arrow visually depicts a return to the origin of the function ^
.
In-Line Function: no signature¶
Use :>
or ::>
.
In-Line Function: with signature¶
Use :>:
or ::>:
to start definition, and ::
to separate parameters and body.
# Signature: parameters 'speed', 'goal'; infered return type as 'string'
:walk ::>: speed, goal :: "Robot walking at \:speed miles/h, to \:goal..."
# Same as Above with parentheses
:walk ::>( speed, goal ) "..."
# Signature: return type 'string'; parameters 'speed' as int, 'goal' as string;
:walk ::>: @string <- @int speed, @string goal :: "..."
Block Functions: no signature¶
Block Functions: with signature¶
# Multiple lines
:add : {: x, y; # Parameters
x += 1
x + y
}
# Same as this single line
:remove : {: @int <- @int x , @int y ; # Full Signature
}
Anonymous Functions¶
\< {: a, b; a + b }. 1, 2
# Prints '3'
# Same as
\< {: a, b; a + b }(1, 2)
# Same as
:fn : {: a, b; a + b }
\< fn(1, 2)
Closures¶
:add : {: a, b
# Returning a closure that capture 'a', 'b'
:>: c :: a + b + c
}
:fc : add 1, 2 # return :>: c :: 3 + c
\< fc 3
# Prints '6' <=> 3 + (c == 3)
Function Calls¶
Pipeline¶
\< square inc 5 # Same as square( inc( 5))
# Prints 36
# With pipeline
\< 5 |> inc |> square
# Prints 36
# With method chaining
\< 5.inc.square
# Prints 36
Pipeline operator is very useful for array processing where the passed value is always an array.
Function Calls with variable function names¶
Positional, Labeled, Optional Arguments¶
Positional and optional parameters separated by a slash /
.
:move ::>: speed, direction : Forward / light-on, sound-on :: ...
# 'light-on', 'sound-on' are optionals parameters
move 1
move 2, Upward
move 2, Upward, :sound_on: true
move 2, Upward, :light_on: true, :sound_on: true
Variable Length Arguments¶
Recusive function¶
Mutually recusive function¶
Defer¶
:openFile : {:
:f : @File.open 'log.txt', ::defer f.close
# Same as
:f : @File.open 'log.txt', :close: :defer
}
Concurrency¶
# Start 10 workers
:w : :|.starts 10, :workers ...
# Or
:w : :|.workpool 10
\< w.:|idle-workers
# Prints a list of idle-workers
Sequents (Results)¶
U allows you to return an execution value, and a status value about the function execution called a sequent.
# Define an sequent called <login-status>
@!login-status :Ok, :Error
:login : {: name
...
# Return
\^! Ok, db.user name
}
login.! :Alice, {!?: status, user
# Deal with the status.
:- Ok, ...
:- Error, ...
}
Exceptions¶
login : {!> ::Exception :MyException # <login> can throws MyException
...
# Throws my exception
:!> MyException, "Exception should be catched elsewhere"
}
# Call with exception management
login.!> 'Bob', {
:!- MyException, {
...
}
}
Pointers¶
Pointer directives starts with :&
.
From typed memory locations to values, use :&<
(address at):
# Map Raspberry GPIO led at memory location 0x3e000000
# ':!' bind mutable variable
:led :! :&<int 0x3e000000
led = &(0x3e000000)
in C.
From values to typed memory locations, use :&>
(content at):
*led = 1
in C.
Documentation¶
U has documentation in a markdown and custom format:
Tests¶
U has builtin test and validation constructs:
UC¶
UC converts C/C++ codebases to U code.