# Arturo Programming language
## Language overview
Arturo is a **refreshingly simple** language. Even with no prior coding experience, you can expect to be comfortable enough to write your first program in roughly 30 minutes.
This single page provides the definitive reference: everything you need to know about the language - and, perhaps, even a bit more.
---
- [Introduction](#introduction)
- [The basics](#the-basics)
* [Words](#words)
* [Labels](#labels)
* [Symbols](#symbols)
* [Attributes](#attributes)
- [:attribute](#attribute)
- [:attributeLabel](#attributeLabel)
* [More values](#more-values)
- [:null](#null)
- [:logical](#logical)
- [:integer](#integer)
- [:floating](#floating)
- [:complex](#complex)
- [:rational](#rational)
- [:version](#version)
- [:type](#type)
- [:char](#char)
- [:string](#string)
- [:range](#range)
- [:regex](#regex)
- [:path](#path)
- [:pathLabel](#pathLabel)
- [:literal](#literal)
- [:symbolLiteral](#symbolLiteral)
- [:pathLiteral](#pathLiteral)
- [:inline](#inline)
- [:block](#block)
- [:dictionary](#dictionary)
- [:store](#store)
- [:object](#object)
- [:module](#module)
- [:function](#function)
- [:method](#method)
- [:unit](#unit)
- [:quantity](#quantity)
- [:color](#color)
- [:date](#date)
- [:database](#database)
- [:socket](#socket)
- [:binary](#binary)
- [:bytecode](#bytecode)
- [:error](#error)
- [:any](#any)
- [Important concepts](#important-concepts)
* [Precedence and evaluation](#precedence-and-evaluation)
- [The right-to-left rule](#the-right-to-left-rule)
* [Scope and rules](#scope-and-rules)
- [Blocks](#blocks)
- [Iterators](#iterators)
- [Functions](#functions)
* [In-place variable modification](#in-place-variable-modification)
- [Using literals](#using-literals)
- [Syntactic sugar](#syntactic-sugar)
* [Right-arrow operator: `->`](#right-arrow-operator)
* [Fat right-arrow operator: `=>`](#fat-right-arrow-operator)
* [Pipe operator: `|`](#pipe-operator)
* [Exclamation-mark operator: `!`](#exclamation-mark-operator)
* [Double-colon operator: `::`](#double-colon-operator)
- [Conclusion](#conclusion)
---
Introduction
Arturo's syntax is probably as easy as it could get. Basically, you could say: *there is no syntax*.
Let's try to resume some key points of Arturo's no-syntax:
- Code is just a list of **words**, **labels**, **symbols**, **values** and **attributes** (you'll learn what all this is about very soon!)
- Code can be grouped into **blocks** (that is: a *list* of words, labels, symbols, and values within square brackets: `[ ... ]`)
- A block has no meaning until it is given one, or interpreted within some specific context, that is: `[ lorem ipsum ]` is perfectly valid Arturo code, until you try to "run" it - where the interpreter will complain that it has no idea what `lorem` and `ipsum` is. Pretty much like if I tell you a word in Swahili - you'll most likely need a dictionary to figure out what it might mean.
- There are no reserved "keywords". Every word can be re-defined.
- You can format your code any way you want: no semicolons to add, no obligatory newlines, no commas, no parentheses, no Python-style indentation rules
- Every **function** expects a pre-determined number of arguments. Initially, we check during evaluation, and during runtime, we "consume" values until we reach the number of arguments required.
As you can see, there is not much to learn from scratch here:
Once you learn what the language [**building blocks**](#the-basics) are & a few details about **[precedence and evaluation](#precedence-and-evaluation)**, then only with the [**Library Reference**](../library/) at hand (the built-in functions that are already there for you, available to use), you're pretty much ready to write *any* program. ;-)
So, let's get to the gist of the matter!
The basics
Words
*Words* in Arturo are pretty much like words in English: a series of characters separated by *spaces* or some [*symbol*](#symbols). E.g.: `this is a series of words` (in this case, `this`, `is`, `a`, `series`, `of`, `words` are all - well... - *words*).
> [!TIP] In Arturo, a word can start with any letter or followed by any letter/numbers/underscore or a question mark (`?`).
As with a real (spoken) language, every word has a specific meaning. And if you don't know the meaning of a word, you'll have to look it up in the dictionary. That's pretty much the way things work in Arturo as well.
In Arturo, a *word* may have 3 main different uses:
- refer to a value (that is: a variable, e.g. `x + 2`)
- refer to an action, which does something (that is: a function, e.g. `doSomething`) - Arturo comes with hundreds already defined in its standard library
- refer to nothing (that is: a word without meaning, as in the `[lorem ipsum]` example above)
Labels
A label is nothing but Arturo's way of assigning meaning (to be read as a value) to a word - what you would normally call *variable assignment* or *variable initialization*. (In Arturo, these two terms can be used interchangeably, since there is practically no difference: you can set and re-define a word/variable as many times as you wish).
So, let's say you want to give a new meaning to the word `x`:
```arturo
x: 2
```
That was it: from now on, `x` will mean `2` (until and if it's changed). So if you follow the above statement with:
```arturo
print x
```
...Arturo will print `2` for you.
Symbols
As the word says, *symbols* are used to symbolize something, mainly as an alias to an existing *word* - although, by convention, as *infix* operators.
Hence, let's take the function add. This takes two parameters, adds them up, and returns the result.
So, you may write:
```arturo
print add 2 3
```
and Arturo will print out `5` for you.
Now, if you don't want to use the add function (and *prefix notation*, which is the standard for *all* function calls), there is a *symbol-alias* for that: `+`
So, you could just as well write:
```arturo
print 2 + 3
```
Only, this time you're expressing it more like you would in a normal math expression: with *infix notation*.
Here is the complete list of symbols recognized in Arturo, along with their predefined usage - if any:
Attributes
Another interesting feature of Arturo is what we'll analyze here: attributes.
Technically, *attributes* are nothing but an easy way of defining optional named parameters for functions - but which can however transcend between different function calls.
There are two types:
a. attributes
b. attribute labels
:attribute
Attributes are actually optional on/off-type values, set during a function call, that are there to denote some variation of the initial meaning of the function. To define an attribute, we'll use a `.`(dot) followed by a normal word: `\.\w+`
Let's say we used the function split, to split a string into parts:
```arturo
split "hello world"
; => ["h" "e" "l" "l" "o" " " "w" "o" "r" "l" "d"]
```
That does what it says: splits the string into an array of strings.
What if we want to split the string into words? For that, there is the `.words` attribute for the function split. So:
```arturo
split.words "hello world"
; = ["hello" "world"]
```
> [!TIP] The order in which you pass the different attributes does not matter. Also, there is no issue at all whether you want to use spaces between them and the surrounding function call; Arturo will still be able to parse them and recognize them fine.
:attributeLabel
Attribute labels are pretty much like simple *attributes*, only they can also take a value. As with *attributes*, we'll use a `.`(dot) followed by a normal word, but now also followed by a `:`(colon) -- exactly like with normal *labels*, as we've seen above.
Here's an example:
```arturo
split .every: 2 "hello world"
; => ["he" "ll" "ow" "or" "ld"]
```
More Values
Values are the very core of Arturo and are used to refer to pretty much all the different kinds of data you can have.
> [!IMPORTANT] Words, labels, and symbols - that we already saw above - can be considered "values" as well; and treated as such, unless we proceed to evaluate them!
We could split values into 2 categories: a) literal values - that is, values you can directly define in your code and b) constructible - values that are created using some function.
The (hopefully) complete list follows.
:null
Null values generally denote *nothing* and are mostly used as a return value by functions to inform us that something went wrong. If you want to set it as a value, you may just use the *word* null, like:
```arturo
x: null
```
:logical
Logicals are Arturo's logical values. They are like normal boolean values (true, false), with a twist: they fully support ternary logic and an additional maybe value.
```arturo
x: true
y: false
z: maybe
```
:integer
Integers represent positive or negative integers. When they are declared they are comprised only of digits (`[0-9]+`) and they can be as long as you want - Arturo does support big numbers.
```arturo
x: 2
y: 876528347613438247982374913423423947329
```
:floating
Floating values are basically floating-point numbers, that is: decimals. They begin with an initial all-digit part, followed by a `.` (dot) and another all-digit part: `[0-9]+\.[0-9]+`
```arturo
pi: 3.14159
```
:complex
Even though there is no special syntax for defining a complex number, you can always create one using to. Arturo comes with full support for complex numbers and all the associated operations.
```arturo
a: to :complex [1 2] ; a: 1.0+2.0i
b: to :complex @[pi pi] ; b: 3.141592653589793+3.141592653589793i
print a + b
; 4.141592653589793+5.141592653589793i
```
:rational
The syntax for rational literals is simply a number followed by a colon, followed by a number (pretty much like you would normally represent a ratio).
```arturo
a: 1:2 ; 1/2
b: 3:4 ; 3/4
```
As with complex numbers, rationals can also be defined using to. And again, Arturo comes with full support for rational numbers and all the associated operations.
```arturo
a: to :rational [1 2] ; 1/2
b: to :rational [3 4] ; 3/4
print a + b
; 5/4
```
:version
Version values are nothing but a fancy and portable way of defining SemVer-compliant versions (e.g. for packaging an application). The rule is rather simple: it has three numeric parts, separated by a `.` (dot) and an optional part with build or prerelease information.
```arturo
package: 1.0.3
if package > 1.0.0 -> print "yep, the version is right!"
```
or
```arturo
version: 1.2.3-rc1+build123
```
:type
Type is a value representing another... type. To specify a type value, the format is a `:` (colon) followed by a word - the type's name: `:\w+`
```arturo
myType: :integer
```
or
```arturo
if (type x) = :integer [ print "it's an integer!" ]
```
> [!TIP] If you want to define your own custom types (think "classes" in OOP languages), we have define for that: e.g.
> ```arturo
> define :person [
> init: method [name :string][
> \name: name
> ]
> ]
> p: to :person ["John"]!
> print p\name ; John
> ```
:char
Characters in Arturo can be declared using single quotes: `'\w'`
```arturo
ch: 'a'
```
:string
A string is nothing but a series of characters, seen as one unit. In Arturo, to define a string, there are various ways:
**Single-line strings**
- using double quotes: ```x: "this is a string"``` (with escaped characters)
- using right *smart-quote* notation ```x: « This is a string``` (in this case, everything following `«` till the end of the line will be stripped and considered one string)
**Multi-line strings**
- using curly-brace blocks (the result will be stripped and un-indented):
```arturo
x: {
this is yet
another
very
long string
that spans more
than
one
line
}
```
- using verbatim curly-brace blocks (the result will remain exactly as-is):
```arturo
x: {:
this is yet
another
very
long string
that spans more
than
one
line
:}
```
- using dash notation (where everything after the line, until the end of the file, is a string - stripped and un-indented):
```arturo
x:
------
this is the last very
long string
that spans more
than
one
line
```
> [!TIP] If you want your string to contain sub-expressions that will be evaluated on the fly - that is *string interpolation* - all you have to do is include your code inside the string within pipe-bars and then call the function render (or `~`) to process it accordingly: e.g.
> ```arturo
> x: 2
> print ~"my variable is: |x|"
>
> ; prints:
> ; my variable is: 2
> ```
:range
Arturo comes with full support of lazy ranges.
To create a range all you have to do is use the built-in range function (or its `..` infix equivalent):
```arturo
numbers: 1..10 ; contains all numbers from 1 to 10 (inclusive)
downwards: 10..1 ; this is valid as well
chars: 'a'..'z' ; yes, we can actually have character ranges too
```
Ranges can be used in most functions as-is, e.g. Iterators, where we can take full advantage of their "lazy" nature: they are not evaluated until needed.
However, you can still evaluate a lazy range into its corresponding block any time you want:
```arturo
@1..10 ; [1,2,3,4,5,6,7,8,9,10]
```
:regex
A regex value is nothing but a string containing a regular expression (that is then compiled and treated as such).
The normal syntax is `{/regex/}`:
```arturo
type {/[A-Z]/} ; => :regex
replace "HelLo" {/[A-Z]/} "X" ; here we replace all capital letters
; with an X
```
While we may - optionally - use any of the supported PCRE-compliant flags:
- `i`: case-insensitive matching
- `m`: multiline
- `s`: dot-all
```arturo
match "Hello" {/he/i} ; => ["He"]
```
:path
Paths in Arturo are a way of defining some hierarchy between values, something along the lines of *parent* -> *child* -> *grandchild*. For this, in Arturo, we'd use a series of *values* or *words* delimited with a `\` (backslash). You can think of them as *indexes* in other programming languages.
```arturo
print user\name
```
or
```arturo
x: "name"
print user\[x]
```
or
```arturo
myArray: ["zero" "one" "two" "three"]
print myArray\1
; prints "one"
```
:pathLabel
If paths are the way of defining some hierarchy between values, with *pathLabel*s we are also able to assign values to some specific path.
```arturo
user: #[
name: "John"
surname: "Doe"
]
print user\name ; will print "John"
; let's change this user's name
user\name: "Jane"
; we can also do it like that
x: "name"
user\[x]: "Jane"
print user\name ; ok, now it should print "Jane"
```
> [!TIP] If we are inside a custom type, an easy way to refer to fields of the same object is using `this`. However, Arturo comes with a shortcut: e.g.
> ```arturo
> define :person [
> init: constructor [name :string]
> sayHello: method [][
> print ["Hello" \name] ; this is equivalent to `this\name`
> ]
> ]
> ```
> which generally helps us write better-looking code. :)
:literal
Literals in Arturo are just a way of referring to the *name* of a word or symbol. Think of it as the *string* version of a word, or like Ruby's *symbols*.
For example, the function info takes as an argument the name of the function for which you want some information. If you wrote like `info print`, the interpreter would execute the function print and try to... print something (which would not be there). If you wanted to refer to the *name* of the function -- that is: without actually calling it -- you would precede it with a `'` (single-quote): `'[\w+]`
```arturo
func: 'print
info func
```
However, literals may be used for much more - e.g. modifying a passed parameter in-place, without having to re-assign the result of an operation to a new variable. To learn more, have a look at **[In-place variable modification](#in-place-variable-modification)**.
:symbolLiteral
Symbol literals are to symbols pretty much what literals are to words. That is: the "literal", unevaluated form of the symbol.
To declare a symbol literal, we may follow the example of normal literals: `single quote` + the symbol in question:
```arturo
type '++ ; => :symbolliteral
```
:pathLiteral
Now that we've seen both "normal" literals and paths, I guess you can already imagine what Path Literals are about... :)
And, yes, you guessed right:
```arturo
type 'this\is\a\path ; => :pathliteral
```
:inline
*Inline*s in Arturo generally denote a list of words/symbols/values that are grouped and given some type of priority in evaluation. An *inline* block is denoted by `(...)` (parentheses).
```arturo
print (2+3)*4
```
Please note though that, apart from precedence, `:inline` is a value type on its own:
```arturo
a: [(one) two three]
print type a\0 ; that is: (one)
; prints :inline
```
:block
Blocks are a fundamental part of Arturo.
As we've already said, it's just a `[...]` (square-bracket enclosed) block of words/symbols/values that - in contrast with *inline* blocks above which are evaluated in-place - are not evaluated until it's necessary.
```arturo
myBlock: [one two three]
anArray: [1 2 3 4 5]
anotherArray: ["zero" 1 "two" 3 "cuatro"]
```
As you can see, blocks can contain practically anything: any word, any symbol, and any value. Of course, they can contain other blocks too:
```arturo
x: [
1 2 [
3 4 [
5 "six" 7
]
8
]
9
]
```
:dictionary
Dictionaries in Arturo are what in other languages you'd call an *associative array* or *hash table*. In Arturo, it's practically the same, only with an added twist: they are *ordered* hash tables.
If you want to create one, just give the dictionary function (or use the `#` alias) a block with different labels, and it'll automatically convert it to a dictionary.
```arturo
user: #[
name: "John"
surname: "Doe"
age: 34
]
```
What the `#` function here does is:
- execute the block
- retrieve only the words/variables defined in there
- return a dictionary with the aforementioned words
> [!IMPORTANT] As you can probably assume from the above definition, a dictionary block doesn't necessarily have to contain just labels and word definitions - it may contain whatever you want, even function calls; only it will return you back just a table with the defined words in there.
:store
Now that you've seen Dictionaries, imagine a dictionary that could actually save its contents to disk for every change you make to it.
Or retrieve it from disk when you start your program again, offering you seamless integration with your data. And safety too.
Well, that's exactly what Stores are. :)
```arturo
d: store "mystore" ; initialize your Store and
; specify where you want to store it
; (if the store already exists, it'll automatically load it)
d\name: "John" ; and you can use it as any normal dictionary
```
:object
Object values are intimately related to custom types, as we have already seen above.
And while Arturo isn't properly speaking a primarily Object-oriented language, it offers more than enough functionality that will cover most OOP needs.
The normal way to create a new object is by using to and a new custom type you have defined before:
```arturo
newClient: to :person ["John" "Doe"]!
; yep, we've just created a new Object value!
```
Technically, Objects are nothing but supercharged Dictionaries that come with a twist:
their functions (see: methods) can have access to their own fields and methods, *from within* - using `this`. But other than that, don't let them scare you: it's just another tool in our toolkit! ;-)
:module
Module values represent encapsulated namespaces in Arturo, created using the module function. Modules allow you to organize code and create isolated scopes with their own functions and variables.
By default, only methods marked with `.public` are accessible from outside the module. You can use export to make the module's public members available in the outer scope:
```arturo
ui: module [
; private method - not accessible outside
namedRule: method [title :string width :integer][
title: ~" |title| "
pad.center.with: '=' title width
]
; public method - accessible via export
section: method.public [title :string content :string width :integer][
~{
|\namedRule title width|
|content|
|\namedRule title width|
}
]
]
export ui!
print section "Hello" "World" 50
; ===================== Hello ======================
; World
; ===================== Hello ======================
```
Modules can also be initialized with parameters using `.with:`:
```arturo
ui: [
init: method [symbol :char][
\symbol: symbol
]
namedRule: method [title :string width :integer][
title: ~" |title| "
pad.center.with: \symbol title width
]
section: method.public [title :string content :string width :integer][
~{
|\namedRule title width|
|content|
|\namedRule title width|
}
]
]
export module.with: ['~'] ui!
print section "Example" "This is an example" 40
; ~~~~~~~~~~~~~~~ Example ~~~~~~~~~~~~~~~~
; This is an example
; ~~~~~~~~~~~~~~~ Example ~~~~~~~~~~~~~~~~
```
Modules are particularly useful for:
- Creating libraries and reusable code
- Encapsulating implementation details (private vs public methods)
- Avoiding naming conflicts
- Organizing larger programs
:function
Functions are another important value type in Arturo - and yes, you heard right: *functions* are a *value* too. You can assign them to a word/variable, pass them around, re-define them and whatever you want with them, pretty much as you would do with another value, let's say a number.
To define a function, all you have to do is call the function... function (or use the `$` alias) followed by two parameters:
- the parameters' names (this can be either a literal, e.g. `'x` - if it's just one argument - or a block, e.g. `[x y]`. If you want to use commas for readability, like `[x,y]` you are free to do so: Arturo will simply ignore them.)
```arturo
multiply: function [x y][
x * y
]
print multiply 2 3
; would print 6
```
or
```arturo
addThemUp: $[x,y][x+y]
print addThemUp 2 3
; would print 5
```
:method
Methods in Arturo are pretty much like functions. With a couple of asterisks:
- They are meant to be used only inside a custom type (in define) or in a module context
- We'd use them only when we want to have access to `this` (= in a few words, when we want to access other fields/functions/methods of the same object; if we don't need that, we could still use a function)
A quick example:
```arturo
define :car [
init: method [; our constructor
brand :string
speed :quantity
][
this\brand: brand
this\speed: speed
]
distanceTravelled: method [inHours :quantity][
this\speed * inHours
]
]
myCar: to :car ["Volvo" 100`km/h]!
print ["In 2 hours, we'll have travelled:" myCar\distanceTravelled 2`h]
```
We may also have *magic methods*, that is: making our custom types accessible-to or "overloading" normal stdlib methods.
For example, if we want to be able to print one of our custom objects, we'd first have to define a way that this custom object is meant to be converted to a string.
For that, we'd define a `string` magic method:
```arturo
define :car [
; as previously
string: method [][
return "CAR :: " ++ \name
]
]
myCar: to :car ["Volvo C30" 100`km/h]!
print myCar ; this would print: CAR :: Volvo C30
```
**Supported Magic methods:**
```
get: method [what] ; this\what
set: method [what, value] ; this\what: value
changing: method [] ; object about to change
changed: method [] ; object changed
compare: method [that] ; comparator definition (to compare between `this` and a second object)
equal?: method [that] ; this = that
less?: method [that] ; this < that
greater?: method [that] ; this > that
add: method [that] ; this + that
sub: method [that] ; this - that
mul: method [that] ; this * that
div: method [that] ; this / that
fdiv: method [that] ; this // that
mod: method [that] ; this % that
pow: method [that] ; this ^ that
inc: method [] ; inc this
dec: method [] ; dec this
neg: method [] ; neg this
key?: method [key] ; key? this key
contains?: method [field] ; contains? this field
append: method [what] ; this ++ what
remove: method [what] ; this -- what
string: method [] ; to :string this
integer: method [] ; to :integer this
floating: method [] ; to :floating this
rational: method [] ; to :rational this
complex: method [] ; to :complex this
quantity: method [] ; to :quantity this
logical: method [] ; to :logical this
block: method [] ; to :block this
dictionary: method [] ; to :dictionary this
```
:unit
Arturo has very advanced capabilities related to physical quantities, measurements and the related operations.
And everything begins with the concept of *units*.
To declare a Unit value, all you have to do is use a backtick, followed by the unit in question:
```arturo
Meters: `m
SquareMeters: `m2
Becquerels: `Bq
```
The list of builtin, supported Units is quite... long:
```
m, s, K, g, A, mol, cd, USD, B, rad, sr, in, ft, yd, ftm, rod, mi, fur, nmi, ang, au, ly, px, pt, pc, sqin, sqft, ac, are, ha, barn, L, gal, bbl, qt, p, cup, floz, tbsp, tsp, bu, cord, min, h, day, wk, mo, yr, lb, slug, oz, ct, t, ton, lt, st, Da, gr, dwt, ozt, lbt, mps, kph, mph, kn, fps, mach, Gal, N, dyn, lbf, kgf, pdl, Pa, atm, bar, pz, Ba, mmHg, psi, Torr, J, Wh, cal, BTU, eV, erg, th, thm, W, hp, statA, abA, Bi, V, statV, abV, Ohm, statOhm, abOhm, S, C, statC, abC, Fr, F, Daraf, H, abH, Wb, Mx, T, G, degC, degF, degR, b, KiB, MiB, GiB, TiB, PiB, EiB, deg, grad, arcmin, arcsec, kat, Hz, Bq, Ci, Gy, Sv, R, P, St, rpm, clo, bps, lx, Lb, lm
```
We also support most world currencies, with their ISO 3-letter code, e.g. `USD`, `EUR`, etc.
**Compound units:**
If you want to define compound units, Arturo actually supports that natively:
```arturo
squareMeters: `m2
kilometersPerHours: `km/h
newtonDefinition: `kg.m/s2 ; yes, that's actually a N(ewton)
```
:quantity
Now, as we've seen, Arturo's Unit values are quite powerful. So, how can we express a Quantity using units?
Very simple: just add a number (a Rational literal works too) just in front of a unit:
```arturo
twoMeters: 2`m ; yes, we've just expressed the notion of "2 meters"
; as a native Arturo value
```
And we can obviously use them in operations as every other value:
```arturo
print 3`m + 4`yd ; 6.6576 m
```
And, yes, no need to worry about compatibility: Arturo actually understands dimensional analysis! ;-)
:color
Colors can be easily defined using the `#xxxxxx` syntax, where *xxxxxx* is either the RGB value of the color in hex, or its common-name alias, like `#red`, `#green` or `#blue`:
```arturo
color1: #red
color2: #0077BB
print color1 + color2
```
:date
Dates in Arturo are a distinct type of value. If you want to create one, you'll have to use one of the corresponding functions. For example, the function now returns a `:date` object, representing the current point in time. And it can be handled pretty much like you would handle a `:dictionary`.
```arturo
print now
; would print 2020-10-26T10:27:14+01:00
print now\year
; would print 2020
```
:database
Database values cannot be constructed literally. However, using the function open, you can create a database value and then use it to query the database in question and much more.
```arturo
db: open.sqlite "my.db"
print query db "SELECT * FROM users"
print type db ; would print: :database
```
:socket
Another not-literally constructible (but still powerful) value type is the Socket.
To use Socket values properly, just have a look into the Sockets library module.
If you want to create one, just have a look at the quick example below, using listen:
```arturo
; start a server listening on port 18966
server: listen 18966 ; and, yes, that's a socket!
```
:binary
Binary values are used to represent *binary* data, that is: an array of bytes. You cannot define them directly, however, you can certainly convert other data to binary.
```arturo
print to :binary "Hello world!"
; would print 4865 6C6C 6F20 776F 726C 6421
```
:bytecode
Bytecode values cannot be constructed literally. However, you can create them indirectly, e.g. using the function to.
```arturo
; let's create some Arturo bytecode from scratch
bcode: to :bytecode [
loop 1..10 'x [
print x
]
]
; and execute it!
do bcode
; we can also inspect it
inspect bcode
; [ :bytecode
; ================================
; DATA
; ================================
; 0: [ :block
; print :word
; x :word
; ]
; 1: x :literal
;
; ================================
; CODE
; ================================
; push0
; eol #4
; push1
; consti10
; consti1
; range
; loop
; end
; ]
```
:error
Error values represent runtime errors in Arturo. They are typically created automatically when something goes wrong, but can also be constructed manually for error handling purposes.
While you cannot create error values with literal syntax, they can be generated using the throw function or caught during error handling:
```arturo
; Errors are typically caught when operations fail
result: try [
; some operation that might fail
]
if error? result [
print ["An error occurred:" result]
]
```
Error values contain information about what went wrong and can be inspected to handle different error conditions appropriately.
:any
The `:any` type is a special meta-type used primarily in type specifications and function signatures. It represents any possible value type and is used to indicate that a function parameter or return value can be of any type.
```arturo
; :any is used in type specifications
; to indicate a parameter accepts any type
myFunc: function [x :any][
print type x
]
myFunc 42 ; works with integer
myFunc "hello" ; works with string
myFunc [1 2 3] ; works with block
```
The keyword `any` is also used in `case` statements as a catch-all pattern:
```arturo
x: 5
case x [
1 -> print "x is one"
2 -> print "x is two"
any -> print "x is something else"
]
; x is something else
```
You won't typically create `:any` values directly, but you'll see it used in function documentation, type checking contexts, and as a pattern matcher to indicate maximum flexibility in what values are accepted.
Important concepts
Here we are going to analyze a few aspects that make Arturo rather unique; or that - in any case - you should study a bit more in order to become a real... Arturo guru, in no time.
So, let's get started...
Precedence and Evaluation
The easiest way to explain precedence rules in Arturo is pretty much like it happened with our introduction: there are no precedence rules whatsoever.
So, in an expression like `2 * 3 + 4`, if you'd normally expect to get a result of `10`, you would be wrong: the result is `14`.
But in order to understand why, you'd have to understand how evaluation in Arturo works.
The right-to-left rule
The main expression evaluation order of Arturo is *right-to-left*. But with a tiny asterisk: Your code *will* be evaluated from left to right, it is the expressions passed to your function calls that will be evaluated from right-to-left.
Let's take a very simple example:
```arturo
print add 1 2
print "Done"
```
As you would expect, the first function to be executed is the first print function and then the second one. Nothing new here.
Now let's take the first print. How is it working?
Let's see:
- First, the value `2` is pushed onto the stack
- Then, we push the value `1`
- Then, we execute the function add: it pops two values from the stack, adds them up, and pushes the result (`3`) back onto the stack
- Finally, we execute the function print: it pops the top value from the stack (`3`) and prints it.
Then, execution would move on and... `print "Done."`
What you have to understand here is that evaluation within an expression will *always* be done from right to left, irrespective of what you might know from other languages or math operator precedence. In Arturo, you have to learn no precedence rules at all. You'll just have to remember to always calculate from right to left.
Re-visiting our previous, seemingly paradoxical, example:
```arturo
2 * 3 + 4
```
> [!IMPORTANT] Remember: our `+` and `*` operators are nothing but simple *infix* aliases to the functions add and mul respectively -- nothing more!
This is as if we had written (moving the operators in front):
```arturo
* 2 + 3 4
```
which practically means: FIRST add 3 and 4 and THEN take the result and multiply it with 2.
If this is not what you intended, then the right way in Arturo would be, either:
```arturo
4 + 2 * 3
```
or (giving precedence to the multiplication, artificially, using parentheses):
```arturo
(2 * 3) + 4
```
**Another example:**
Let's say we want to concatenate a number and a string into a new string.
```arturo
to :string 3 ++ " <-- this is our number"
```
The above example wouldn't work, because first it tries to concatenate `3` with a string (`" <-- this is our number"`) and *then* performs `to :string`.
While what we actually want is to *first* convert our number to a string and *then* concatenate the two strings.
The correct code in that case would be:
```arturo
(to :string 3) ++ " <-- this is our number"
```
Scope and rules
Contrary to what you might expect, Arturo doesn't feature a traditional concept of *scope*. There are no real *local* or *global* variables, no *local* or *global* functions, no *local* or *global* blocks, no *local* or *global* anything.
Generally, if a variable has been previously declared at the moment and location of its usage, then it is available. Otherwise, it is not.
But let's see a couple of concrete cases to make this clearer.
Blocks
Arturo doesn't have a block scope.
In a few words, this means:
- A variable declared inside a block is available outside of it
- A variable previously declared outside of a block is available inside
- The changes to an existing variable, inside a block, persist after the block
```arturo
x: 1 ; here, we declare a variable x
; and set it to 1
do [
x: 2 ; here, we re-assign the value of x
; to 2
print x ; prints 2
y: 3 ; here, we declare a variable y
; and set it to 3
]
print x ; prints 2 (the value of x has been changed)
print y ; prints 3 (the value of y is still available)
```
Iterators
Iterators (such as loop, map, etc) always work with a block as well. But in a special way.
Basically, the logic is identical to that of blocks, but with a slight difference:
- the *injected* variables (e.g. the iteration arguments), are available only inside the block, but not after the iteration is over
- any previous value is "protected" and restored if needed
```arturo
x: 3
loop.with:'i ["one" "two" "three"] 'x [
print i ; prints 0, 1, 2,...
print x ; prints "one", "two", "three",...
]
print x ; prints 3 (the value of x has been restored)
print i ; ERROR: variable not found
; (i is not available anymore)
```
Functions
Functions are totally different. Why? Because they do have their own scope.
The general idea is:
- A variable declared inside a function is available only inside the function
- A variable previously declared outside of a function is available inside
- The changes to an existing variable, inside a function, do not persist after the function
If we want to *export* a specific symbol to the outer scope, that is, make it available outside the function, we can use the `.export:` attribute.
If we want to export *all* of the symbols - thus, practically making the function *scope-less*, we may use the `.inline` attribute.
In-place variable modification
In Arturo, every time you pass a parameter to a function, you can rest assured that the value of that parameter won't change (unless it's a string, block or dictionary and you - consciously - decided to use set on it, in which case it does alter its inner structure).
So, basically, when you do this...
```arturo
a: [1 5 2 4 3]
sort a
```
...all you do is to take an array, sort it, and push the sorted array onto the stack. Variable `a` simply does not change.
So, what would you do if you wanted to get the array back, but sorted?
The simple - and most obvious - way would be to re-assign the returned result from sort:
```arturo
a: [1 5 2 4 3]
a: sort a
```
And now, yes, `a` does contain the sorted version of the initial array.
But what if you want to perform the modification in-place, which is normally faster and without the need for intermediate variables? Literals come to the rescue!
Using literals
As we've already said, "literals" (`'i 'am 'a 'literal`) are nothing but string representations of a word, that is... the word itself. For that reason, they may come in very handy when you want to modify a variable in-place.
Let's revisit the above example and what the syntax of sort is:
```arturo
sort collection :literal :dictionary :block
```
As we can see, sort takes one parameter (*collection*) which is either a `:dictionary` or `:block` OR a `:literal`.
Why pass a literal? Simply because this turns in-place modification on! Let's have a look:
```arturo
a: [1 5 2 4 3]
sort 'a ; yep, now a *has* been sorted in-place!
```
And this is *very powerful*: in Arturo, most of the built-in functions in the library come with this feature included. Practically, whenever you see a function taking a literal first parameter, that means you can use it for in-place modifying a variable (yes, even add works like that!).
> ⚠️ **Word of caution:**
> Values in Arturo are always passed by reference - unless they are constant/readonly values. So if you want to assign one variable to another and then modify one of them in-place, make sure you use new; otherwise, both values will change!
>
> ```arturo
> a: 1
> b: a
> inc 'a ; both a and b are now 2
>
> c: 1
> d: new c ; we copy the value of c into d
> inc 'c ; now c is 2 and d is 1, as expected
> ```
Syntactic sugar
As you have hopefully seen so far, Arturo is rather simple, with fairly simple rules and that's pretty much it.
However, we also have some "syntactic sugar": a fancy way of referring to syntactic constructs, so that something more complicated will look better, or easier-to-write, or more readable.
Here you'll learn about some useful examples of *syntactic sugar* supported in Arturo.
Right-arrow operator: `->`
The function of the right arrow operator is rather straightforward: basically, it wraps the following *terminal* value inside a block.
Let's take a simple example.
```arturo
x: -> 2
```
This is 100% equivalent to:
```arturo
x: [2]
```
You can also use the right-arrow operator to make many common constructs far more readable.
For example:
```arturo
if x=2 -> print "x was 2!"
```
is the same as writing:
```arturo
if x=2 [ print "x was 2!" ]
```
As you can see, it can be pretty handy. Just remember that `->` can wrap only one *terminal* value.
For example:
```arturo
x: -> 2 3
```
This doesn't result in `x: [2 3]` but in `x: [2] 3`
Another interesting way of making use of the power of the *right-arrow operator*:
```arturo
loop 1..10 'x -> print x
```
which is the same as writing (only much more elegant):
```arturo
loop 1..10 'x [ print x ]
```
Fat right-arrow operator: `=>`
The fat right-arrow operator is like a super-charged *simple* right arrow operator (`->`) as described above.
If `->` was used to wrap the following terminal into a block, the `=>` operator does even more.
Let's take this simple example:
```arturo
x: $ => add
```
This is equivalent to writing:
```arturo
x: $[x,y][add x y]
```
Basically, it reads the following word, and if it's a function, pushes all its needed arguments as anonymous variables.
The same could work with a block argument, where `&` can be used as a placeholder for the needed anonymous variables:
```arturo
x: $ => [add & &]
```
(The first `&` will pop the first argument, and the second the next one - and so on...)
---
As you can already imagine, this is perfect for easily defining functions or action blocks that take exactly one parameter.
For example, to print an array of the even numbers between 1 and 10:
```arturo
print select 1..10 'x [even? x]
```
This could be easily written as (using the `->` operator):
```arturo
print select 1..10 'x -> even? x
```
But pushing the limits more, we can also use the `=>` operator:
```arturo
print select 1..10 => even?
```
That's surely much more readable, isn't it?
Pipe operator: `|`
The *pipe* operator is an easy way of reversing the default *prefix* notation of function calls and simulating what in OOP languages is called *function chain*.
Let's take this simple example:
```arturo
1..10 | print
```
This is equivalent to:
```arturo
print 1..10
```
Or a bit more elaborate example (using *pipes* and the `->`/`=>` operators):
```arturo
1..10 | map => [2 * &]
| select 'x -> even? x
| print
```
which would be like writing:
```arturo
print select map 1..10 'x [2*x] 'x [even? x]
```
Exclamation-mark operator: `!`
Explaining the *exclamation-mark* can be a bit tricky, but if you want the short version:
it wraps everything that follows in a do block (more or less).
Or the shorter version:
- Have you just created a new custom-type object? (e.g. `to :myObject []`)?
- Have you imported an external package? (e.g. `import 'somePackage`)?
Then just put `!` at the end of the statement (e.g. `import 'somePackage!`) and everything will work as you expect.
**The long explanation:**
Arturo, when parsing a block of code, has to know which symbols correspond to function calls and how many arguments they take. The exact same is valid for object methods.
When we create a new object (e.g. `p: to :person ["John"]`), if we attempt to use `p\someMethod` from the exact same block where this `p` value was initialized, there is no possible way to know beforehand that e.g. `someMethod` is a method. We'll know that only *after* `to :person ["John"]` has been executed. But then, it's already too late. So, how do we make sure that Arturo knows about the object before we attempt to call inner methods? By putting a "stopper" after the object creation, and that stopper is our beloved... `!`.
> [!NOTE] Technically we could achieve the same thing without the `!` sugar:
> ```arturo
> p: to :person ["John"]
> do [
> p\sayHello
> ]
> ```
> That would work too, for all practical purposes. But: `!` is looking good. And it's also far more performant, based on the way it's implemented internally! ;-)
Double-colon operator: `::`
The *double-colon* operator does something very simple: it wraps everything in a block - until the end of... the current block:
```arturo
do [
print ::
"This is a number:"
123
]
```
Is equivalent to:
```arturo
do [
print ["This is a number:" 123]
]
```
----
Conclusion
If you made it here, then I can assure you: you've already learned more than you need in order to be fully proficient in Arturo.
Just head to the [Library Reference](../library/) and have a look at the built-in functions (with explanations and example code) and see what's already available for you or - if you want to see the language in action - just browse through the [Examples](../examples): there are many (many!) *working* examples, to get more than just an idea.
**Welcome on board! :)**
## Example program
This section is inspired by [Learn X in Y minutes](https://learnxinyminutes.com/) and its goal is to present the most basic features of Arturo, in a concise way, so that you can get started fast.
So... **With X = Arturo and Y = ~15 minutes**, here you are:
---
```arturo
; this is a comment
; this is another comment
;---------------------------------
; VARIABLES & VALUES
;---------------------------------
; numbers
a1: 2
a2: 3.14
a3: to :complex [1 2.0] ; 1.0+2.0i
; strings
c1: "this is a string"
c2: {
this is a multiline string
that is indentation-agnostic
}
c3: {:
this is
a verbatim
multiline string
which will remain exactly
as the original
:}
; characters
ch: 'c'
; blocks/arrays
d: [1 2 3]
; dictionaries
e: #[
name: "John"
surname: "Doe"
age: 34
likes: [pizza spaghetti]
]
; yes, functions are values too
f: function [x][
2 * x
]
; colors - right, you can directly define them as well!
g1: #red
g2: #0077BF
; dates
h: now ; 2021-05-03T17:10:48+02:00
; versions
currentVersion: 3.2.10-beta ; SemVer compatible :)
; logical values
i1: true
i2: false
i3: maybe
; units
meters: `m
kilograms: `kg
; quantities
height: 3`yd
width: 4`m
;---------------------------------
; BASIC OPERATORS
;---------------------------------
; simple arithmetic
1 + 1 ; => 2
8 - 1 ; => 7
4.2 - 1.1 ; => 3.1
10 * 2 ; => 20
35 / 4 ; => 8
35 // 4 ; => 8.75
2 ^ 5 ; => 32
5 % 3 ; => 2
; bitwise operators
and 3 5 ; => 1
or 3 5 ; => 7
xor 3 5 ; => 6
; pre-defined constants
pi ; => 3.141592653589793
epsilon ; => 2.718281828459045
null ; => null
true ; => true
false ; => false
;---------------------------------
; COMPARISON OPERATORS
;---------------------------------
; equality
1 = 1 ; => true
2 = 1 ; => false
; inequality
1 <> 1 ; => false
2 <> 1 ; => true
; more comparisons
1 < 10 ; => true
1 =< 10 ; => true
10 =< 10 ; => true
1 > 10 ; => false
1 >= 10 ; => false
11 >= 10 ; => true
;---------------------------------
; CONDITIONALS
;---------------------------------
; logical operators
and? true true ; => true
and? true false ; => false
or? true false ; => true
or? false false ; => false
and? [1=2][2<3] ; => false
; (the second block will not be evaluated)
; simple if statements
if 2 > 1 [ print "yes!"] ; yes!
if 3 <> 2 -> print "true!" ; true!
; switch statements
switch 2 > 3 -> print "2 is greater than 3"
-> print "2 is not greater than 3" ; 2 is not greater than 3
a: (2 > 3)?["yes"]["no"] ; a: "no"
a: (2 > 3)? -> "yes" -> "no" ; a: "no" (exactly the same as above)
; case statements
key: "one"
case key [ ; the main block is always evaluated!
"one" -> print "key is one!"
"two" -> print "key is two!"
any -> print "key is none of the above"
]
; when statements
when [ ; the main block is always evaluated!
prime? 4 -> print "yes, 4 is prime - wait, what?!"
prime? 5 -> print "yes, 5 is prime"
prime? 7 -> print "yes, 6 is prime"
true -> print "none of the above was true"
]
; yes, 5 is prime
when.any [ ; cascade-style checking (without breaking)
prime? 4 -> print "yes, 4 is prime - wait, what?!"
prime? 5 -> print "yes, 5 is prime"
prime? 7 -> print "yes, 7 is prime"
]
; yes, 5 is prime
; yes, 7 is prime
x: 2
when.has: x [ ; prepends passed parameter to each block/condition
[=0] -> print "x is zero!"
[<1] -> print "x is less than 1"
[<4] -> print "x is less than 4"
true -> print "x is >= 4"
]
; x is less than 4
;---------------------------------
; LOOPS
;---------------------------------
; with `loop`
arr: [1 4 5 3]
loop arr 'x [
print ["x =" x]
]
; x = 1
; x = 4
; x = 5
; x = 3
; with loop and custom index
loop.with:'i arr 'x [
print ["item at position" i "=>" x]
]
; item at position 0 => 1
; item at position 1 => 4
; item at position 2 => 5
; item at position 3 => 3
; using ranges
loop 1..3 'x -> ; since it's a single statement
print x ; there's no need for [block] notation
; we can wrap it up using the `->` syntactic sugar
loop 'a'..'c' 'ch ->
print ch
; a
; b
; c
; picking multiple items
loop 1..10 [x y] ->
print ["x =" x ", y =" y]
; x = 1 , y = 2
; x = 3 , y = 4
; x = 5 , y = 6
; x = 7 , y = 8
; x = 9 , y = 10
; looping through a dictionary
dict: #[name: "John", surname: "Doe", age: 34]
loop dict [key value][
print [key "->" value]
]
; name -> John
; surname -> Doe
; age -> 34
; while loops
i: 0
while [i<3][
print ["i =" i]
inc 'i
]
; i = 0
; i = 1
; i = 2
;---------------------------------
; STRINGS
;---------------------------------
; case
a: "tHis Is a stRinG"
print upper a ; THIS IS A STRING
print lower a ; this is a string
print capitalize a ; THis Is a stRinG
; concatenation
a: "Hello " ++ "World!" ; a: "Hello World!"
; strings as an array
split "hello" ; => [h e l l o]
split.words "hello world" ; => [hello world]
print first "hello" ; h
print last "hello" ; o
; conversion
to :string 123 ; => "123"
to :integer "123" ; => 123
; joining strings together
join ["hello" "world"] ; => "helloworld"
join.with:"-" ["hello" "world"] ; => "hello-world"
; string interpolation
x: 2
print ~"x = |x|" ; x = 2
; interpolation with `print`
print ["x =" x] ; x = 2
; (`print` works by calculating the given block
; and joining the different values as strings
; with a single space between them)
; templates
print render.template {
<||= switch x=2 [ ||>
Yes, x = 2
<||][||>
No, x is not 2
<||]||>
} ; Yes, x = 2
; matching
prefix? "hello" "he" ; => true
suffix? "hello" "he" ; => false
contains? "hello" "ll" ; => true
contains? "hello" "he" ; => true
contains? "hello" "x" ; => false
in? "ll" "hello" ; => true
in? "x" "hello" ; => false
;---------------------------------
; BLOCKS
;---------------------------------
; calculate a block
arr: [1 1+1 1+1+1]
@arr ; => [1 2 3]
; execute a block
sth: [print "Hello world"] ; this is perfectly valid,
; could contain *anything*
; and will not be executed...
do sth ; Hello world
; (...until we tell it to)
; array indexing
arr: ["zero" "one" "two" "three"]
print first arr ; zero
print arr\0 ; zero
print last arr ; three
print arr\3 ; three
x: 2
print get arr x ; two
print arr\[x] ; two
; setting an array element
arr\0: "nada"
set arr 2 "dos"
print arr ; nada one dos three
z: 2
arr\[z]: "dos" ; would have the same effect
; adding elements to an array
arr: []
'arr ++ "one"
'arr ++ "two"
print arr ; one two
; remove elements from an array
arr: ["one" "two" "three" "four"]
'arr -- "two" ; arr: ["one" "three" "four"]
remove 'arr .index 0 ; arr: ["three" "four"]
; getting the size of an array
arr: ["one" 2 "three" 4]
print size arr ; 4
; getting a slice of an array
print slice ["one" "two" "three" "four"] 0 1 ; one two
; check if array contains a specific element
print contains? arr "one" ; true
print contains? arr "five" ; false
; sorting array
arr: [1 5 3 2 4]
sort arr ; => [1 2 3 4 5]
sort.descending arr ; => [5 4 3 2 1]
; mapping values
map 1..10 [x][2*x] ; => [2 4 6 8 10 12 14 16 18 20]
map 1..10 'x -> 2*x ; same as above
map 1..10 => [2 * &] ; same as above
map 1..10 => [2*] ; same as above
; selecting/filtering array values
select 1..10 [x][odd? x] ; => [1 3 5 7 9]
select 1..10 => odd? ; same as above
filter 1..10 => odd? ; => [2 4 6 8 10]
; (now, we leave out all odd numbers -
; while select keeps them)
; misc operations
arr: ["one" 2 "three" 4]
reverse arr ; => [4 "three" 2 "one"]
shuffle arr ; => [2 4 "three" "one"]
unique [1 2 3 2 3 1] ; => [1 2 3]
permutate [1 2 3] ; => [[1 2 3] [1 3 2] [3 1 2] [2 1 3] [2 3 1] [3 2 1]]
take 1..10 3 ; => [1 2 3]
repeat [1 2] 3 ; => [1 2 1 2 1 2]
;---------------------------------
; FUNCTIONS
;---------------------------------
; declaring a function
f: function [x][ 2*x ]
f: function [x]-> 2*x ; same as above
f: $[x]->2*x ; same as above (only using the `$` alias
; for the `function`... function)
; calling a function
f 10 ; => 20
; returning a value
g: function [x][
if x < 2 -> return 0
res: 0
loop 0..x 'z [
res: res + z
]
return res
]
;---------------------------------
; CUSTOM TYPES
;---------------------------------
; defining a custom type
define :person [
; define a new custom type "Person"
; with fields: name, surname, age
init: method [name surname age][
\name: capitalize name
\surname: surname
\age: age
]
; custom print function
string: method [][
render "NAME: |\name|, SURNAME: |\surname|, AGE: |\age|"
]
; custom comparison operator
compare: sortable 'age
]
; create a method for our custom type
sayHello: function [this :person][
print ["Hello" this\name]
]
; create new objects of our custom type
a: to :person ["John" "Doe" 34]! ; let's create 2 "Person"s
b: to :person ["jane" "Doe" 33]! ; and another one
; call pseudo-inner method
sayHello a ; Hello John
sayHello b ; Hello Jane
; access object fields
print ["The first person's name is:" a\name] ; The first person's name is: John
print ["The second person's name is:" b\name] ; The second person's name is: Jane
; changing object fields
a\name: "Bob"
sayHello a ; Hello Bob
; verifying object type
print type a ; :person
print is? :person a ; true
; printing objects
print a ; NAME: Bob, SURNAME: Doe, AGE: 34
; sorting user objects (using custom comparator)
print sort @[a b] ; Jane..., Bob...
print sort.descending @[a b] ; Bob..., Jane...
```
## Standard library
### Arithmetic
Basic arithmetic operations (addition, subtraction, multiplication, etc) for integers and floating-point numbers
----
The Arithmetic module provides basic mathematical operations that work seamlessly across different numeric types - integers, floating-point numbers, complex numbers, and rationals.
#### Key Concepts
- Operations work with multiple numeric types
- Support for in-place modifications
- Complex and rational number operations
- Automatic type promotion when needed
- All operators available as infix symbols
#### Basic Usage
##### Basic Operations
```arturo
; addition
print 2 + 3 ; 5
print add 2 3 ; 5
; subtraction
print 5 - 3 ; 2
print sub 5 3 ; 2
; multiplication
print 4 * 3 ; 12
print mul 4 3 ; 12
; division
print 10 / 3 ; 3 (integer division)
print 10 // 3 ; 3.333333333333333 (floating division)
print div 10 3 ; 3
print fdiv 10 3 ; 3.333333333333333
```
##### Working with Different Types
```arturo
; integer + floating
print 2 + 3.81 ; 5.81
; with complex numbers
z: to :complex [3 4] ; 3.0+4.0i
print z + 2 ; 5.0+4.0i
print z * 3 ; 9.0+12.0i
; with rationals
a: 1:2 ; 1/2
b: 3:4 ; 3/4
print a + b ; 5/4
```
##### In-place Modifications
```arturo
x: 5
; increment
inc 'x ; x is now 6
print x ; 6
; decrement
dec 'x ; x is now 5
print x ; 5
; other operations
add 'x 3 ; x is now 8
mul 'x 2 ; x is now 16
print x ; 16
```
> [!NOTE] Using literals (e.g., `'x`) performs operations in-place, modifying the original value.
#### Common Patterns
##### Division and Remainder
```arturo
; integer division with remainder
[quotient remainder]: divmod 17 5
print ["17 ÷ 5 =" quotient "remainder" remainder]
; 17 ÷ 5 = 3 remainder 2
; floating division
print fdiv 17 5 ; 3.4
```
##### Working with Quantities
```arturo
distance: 100`m ; 100 meters
time: 5`s ; 5 seconds
speed: fdiv distance time
print speed ; 20 m/s
```
##### Type Conversions & Promotions
```arturo
; integer → floating
a: 5 + 3.41 ; 8.41 (floating)
b: 2 * 3.5 ; 7.0 (floating)
; integer → rational
x: 3 + 1:2 ; 7/2 (rational)
y: 2 3:4 ; 3/2 (rational)
; integer → complex
z: 2 + to :complex [1 1]
; 3.0+1.0i (complex)
; quantity +/- amount
q: 3`m + 10 ; 3 meters (quantity)
r: 3`m - 2 ; 1 meter (quantity)
; quantity * times
s: 3`km * 3 ; 9 kilometers (quantity)
t: 3 * 3`km ; 9 kilometers (quantity)
; quantity * quantity
u: 2`m * 3`m ; 6 sq.meters (quantity)
```
> [!NOTE] When operating with different numeric types, Arturo automatically promotes to the most precise type needed.
----
#### `add` (alias: `+` - infix: true)
add given values and return result
##### Arguments
- `valueA` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:color,:object)
- `valueB` (:integer,:floating,:complex,:rational,:quantity,:color,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:color,:object,:nothing
##### Examples
```
print add 1 2 ; 3
print 1 + 3 ; 4
```
```
a: 4
add 'a 1 ; a: 5
```
#### `dec`
decrease given value by 1
##### Arguments
- `value` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
##### Examples
```
print dec 5 ; 4
```
```
a: 4
dec 'a ; a: 3
```
#### `div` (alias: `/` - infix: true)
perform integer division between given values and return result
##### Arguments
- `valueA` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
- `valueB` (:integer,:floating,:complex,:rational,:quantity,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
##### Examples
```
print div 5 2 ; 2
print 9 / 3 ; 3
```
```
a: 6
div 'a 3 ; a: 2
```
#### `divmod` (alias: `/%` - infix: true)
perform integer division between given values and return tuple with quotient and remainder
##### Arguments
- `valueA` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity)
- `valueB` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:block,:nothing
##### Examples
```
print divmod 15 5 ; 3 0
print 14 /% 3 ; 4 2
```
```
[q,r]: 10 /% 3 ; q: 3, r: 1
```
```
a: 6
divmod 'a 4 ; a: [1, 2]
```
#### `fdiv` (alias: `//` - infix: true)
divide given values and return result
##### Arguments
- `valueA` (:integer,:floating,:rational,:literal,:pathliteral,:quantity,:object)
- `valueB` (:integer,:floating,:rational,:quantity)
##### Returns
:floating,:rational,:quantity,:object,:nothing
##### Examples
```
print fdiv 5 2 ; 2.5
print 5 // 2 ; 2.5
```
```
a: 6
fdiv 'a 3 ; a: 2.0
```
#### `inc`
increase given value by 1
##### Arguments
- `value` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
##### Examples
```
print inc 5 ; 6
```
```
a: 4
inc 'a ; a: 5
```
#### `mod` (alias: `%` - infix: true)
calculate the modulo of given values and return result
##### Arguments
- `valueA` (:integer,:floating,:rational,:literal,:pathliteral,:quantity,:object)
- `valueB` (:integer,:floating,:rational,:quantity)
##### Returns
:integer,:floating,:rational,:quantity,:object,:nothing
##### Examples
```
print mod 5 2 ; 1
print 9 % 3 ; 0
```
```
a: 8
mod 'a 3 ; a: 2
```
#### `mul` (alias: `*` - infix: true)
calculate the product of given values and return result
##### Arguments
- `valueA` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
- `valueB` (:integer,:floating,:complex,:rational,:quantity,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
##### Examples
```
print mul 1 2 ; 2
print 2 * 3 ; 6
```
```
a: 5
mul 'a 2 ; a: 10
```
#### `neg`
reverse sign of given value and return it
##### Arguments
- `value` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
##### Examples
```
print neg 1 ; -1
```
```
a: 5
neg 'a ; a: -5
```
#### `pow` (alias: `^` - infix: true)
calculate the power of given values and return result
##### Arguments
- `valueA` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:object)
- `valueB` (:integer,:floating)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:object,:nothing
##### Examples
```
print pow 2 3 ; 8
print 3 ^ 2 ; 9
```
```
a: 5
pow 'a 2 ; a: 25
```
#### `sub` (alias: `-` - infix: true)
subtract given values and return result
##### Arguments
- `valueA` (:integer,:floating,:complex,:rational,:literal,:pathliteral,:quantity,:color,:object)
- `valueB` (:integer,:floating,:complex,:rational,:quantity,:color,:object)
##### Returns
:integer,:floating,:complex,:rational,:quantity,:color,:object,:nothing
##### Examples
```
print sub 2 1 ; 1
print 5 - 3 ; 2
```
```
a: 7
sub 'a 2 ; a: 5
```
### Bitwise
Bit manipulation methods & bitwise operators (AND, OR, XOR, etc) for integer values
----
The Bitwise module provides functions for bit-level operations on integer values, including basic boolean operations and bit shifting.
#### Key Concepts
- Bitwise boolean operations (AND, OR, XOR, etc.)
- Bit shifting operations
- Works with integer values
- Results are always integers
#### Basic Usage
##### Boolean Operations
```arturo
x: 5 ; binary: 101
y: 3 ; binary: 011
and x y ; => 1 (001)
or x y ; => 7 (111)
xor x y ; => 6 (110)
; complement
not x ; => -6 (complement of 101)
```
##### Advanced Operations
```arturo
a: 12 ; binary: 1100
b: 9 ; binary: 1001
nand a b ; => -9
nor a b ; => -14
xnor a b ; => -6
```
##### Bit Shifting
```arturo
num: 8 ; binary: 1000
; left shift (multiply by 2^n)
print shl num 2 ; 32 (100000)
; right shift (divide by 2^n)
print shr num 1 ; 4 (100)
```
> [!NOTE] Shift operations are equivalent to multiplication or division by powers of 2.
#### Common Patterns
##### Checking Individual Bits
```arturo
value: 42 ; binary: 101010
mask: shl 1 3 ; binary: 001000
if and value mask ->
print "Bit 3 is set"
```
##### Setting and Clearing Bits
```arturo
number: 10 ; binary: 1010
pos: 2
; set bit
number: or number shl 1 pos
print ["After setting:" number] ; After setting: 14 (1110)
; clear bit
number: and number not shl 1 pos
print ["After clearing:" number] ; After clearing: 10 (1010)
```
----
#### `and`
calculate the binary AND for the given values
##### Arguments
- `valueA` (:integer,:literal,:pathliteral,:binary)
- `valueB` (:integer,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print and 2 3 ; 2
```
```
a: 2
and 'a 3 ; a: 2
```
#### `nand`
calculate the binary NAND for the given values
##### Arguments
- `valueA` (:integer,:literal,:pathliteral,:binary)
- `valueB` (:integer,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print nand 2 3 ; -3
```
```
a: 2
nand 'a 3 ; a: -3
```
#### `nor`
calculate the binary NOR for the given values
##### Arguments
- `valueA` (:integer,:literal,:pathliteral,:binary)
- `valueB` (:integer,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print nor 2 3 ; -4
```
```
a: 2
nor 'a 3 ; a: -4
```
#### `not`
calculate the binary complement of the given value
##### Arguments
- `value` (:integer,:literal,:pathliteral,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print not 123 ; -124
```
```
a: 123
not 'a ; a: -124
```
#### `or`
calculate the binary OR for the given values
##### Arguments
- `valueA` (:integer,:literal,:pathliteral,:binary)
- `valueB` (:integer,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print or 2 3 ; 3
```
```
a: 2
or 'a 3 ; a: 3
```
#### `shl`
shift-left first value bits by second value
##### Arguments
- `value` (:integer,:literal,:pathliteral)
- `bits` (:integer)
##### Options
- `safe` (:logical): check for overflows
##### Returns
:integer,:nothing
##### Examples
```
print shl 2 3 ; 16
```
```
a: 2
shl 'a 3 ; a: 16
```
#### `shr`
shift-right first value bits by second value
##### Arguments
- `value` (:integer,:literal,:pathliteral)
- `bits` (:integer)
##### Returns
:integer,:nothing
##### Examples
```
print shr 16 3 ; 2
```
```
a: 16
shr 'a 3 ; a: 2
```
#### `xnor`
calculate the binary XNOR for the given values
##### Arguments
- `valueA` (:integer,:literal,:pathliteral,:binary)
- `valueB` (:integer,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print xnor 2 3 ; -2
```
```
a: 2
xnor 'a 3 ; a: -2
```
#### `xor`
calculate the binary XOR for the given values
##### Arguments
- `valueA` (:integer,:literal,:pathliteral,:binary)
- `valueB` (:integer,:binary)
##### Returns
:integer,:binary,:nothing
##### Examples
```
print xor 2 3 ; 1
```
```
a: 2
xor 'a 3 ; a: 1
```
### Collections
Functions and helpers for manipulating and dealing with different types of collections (blocks, dictionaries, and strings)
----
The Collections module provides a unified interface for working with different types of collections: blocks, dictionaries, and strings. Most operations work seamlessly across all collection types, making it easy to manipulate data regardless of its structure.
#### Key Concepts
- Unified operations across blocks, dictionaries, and strings
- Support for both mutable and immutable operations
- Efficient array/block manipulation
- Ordered dictionary operations
- Lazy evaluation with ranges
- Flexible combination and permutation generation
#### Basic Usage
##### Creating Collections
```arturo
; blocks (arrays)
numbers: [1 2 3 4 5]
mixed: ["hello" 42 true]
; dictionaries (ordered hash tables)
user: #[
name: "John"
age: 30
city: "London"
]
; ranges (lazy collections)
evens: 2..10
; use `@` (or `array`) to "evaluate" a range
print @evens ; 2 3 4 5 6 7 8 9 10
```
> [!NOTE] Dictionaries in Arturo maintain insertion order, unlike hash tables in many other languages.
##### Basic Operations
```arturo
lst: [1 2 3]
; adding/removing elements
'lst ++ 4 ; append
'lst -- 2 ; remove value
'lst ++ [5 6] ; extend
print lst ; 1 3 4 5 6
; accessing elements
print first lst ; 1
print last lst ; 6
; accessing the element at index: 2
; (= the third element in our list)
print lst\2 ; 4
```
> [!IMPORTANT] Using the literal form (e.g., `'lst`) modifies the collection in place, while using the value directly returns a new collection.
##### Collection Indexing
```arturo
; basic array indexing
colors: ["red" "green" "blue"]
print colors\0 ; red (first element)
print colors\2 ; blue (last element)
; dynamic indexing with expressions
pos: 1
print colors\[pos] ; green
; dictionary field access
user: #[
name: "John"
surname: "Doe"
age: 30
]
print user\name ; John
; dynamic dictionary field access
field: 'surname ; using a literal
print user\[field] ; Doe
```
> [!NOTE] Indexing with `\` works uniformly across all collection types. Use a block after `\` when you need to evaluate an expression to get the index or field name.
##### Collection Information
```arturo
data: [1 2 2 3 3 3]
size data ; => 6
empty? data ; => false
contains? data 2 ; => true
index data 3 ; => 2
```
#### Common Patterns
##### Collection Transformation
```arturo
; flatten nested structure
nested: [[1 2] [3 4] [5 6]]
flat: flatten nested
; [1 2 3 4 5 6]
; unique elements
duplicates: [1 2 2 3 3 3]
print unique duplicates ; 1 2 3
; reversing
print reverse [1 2 3] ; 3 2 1
```
##### Working with Dictionaries
```arturo
user: #[
name: "John"
age: 30
]
; accessing data
keys user ; => ["name" "age"]
values user ; => ["John" 30]
; extending
additional: #[
city: "London"
job: "Developer"
]
complete: extend user additional
print complete
; [name:John age:30 city:London job:Developer]
```
##### Working with Strings
```arturo
text: "Hello 世界" ; unicode string
; strings are like character arrays
print text\0 ; H
print text\4 ; o
print text\5 ; [space]
print text\6 ; 世
; get size (in characters, not bytes)
print size text ; 8
; iterate through characters
loop text 'c ->
print ["char:" c]
; char: H
; char: e
; char: l
; char: l
; char: o
; char:
; char: 世
; char: 界
```
> [!NOTE] Strings in Arturo are always Unicode-aware. When indexing or iterating, you're working with actual characters, not bytes.
##### Combinations & Permutations
```arturo
items: [1 2 3]
; specific size combinations
combine.by:2 items
; => [[1 2] [1 3] [2 3]]
; permutations
permutate items
; => [[1 2 3] [1 3 2] [2 1 3] [2 3 1] [3 1 2] [3 2 1]]
```
> [!TIP] Use the `.repeated` attribute with `combine` or `permutate` when you want to allow elements to be used multiple times.
##### Efficient Range Operations
```arturo
; create a range of numbers
nums: 1..1000
; work with it without generating all values
first nums ; => 1
last nums ; => 1000
nums\42 ; => 42
```
> [!NOTE] Ranges are lazy - they don't generate all values until needed, making them very memory-efficient for large sequences.
##### Advanced Examples
###### Working with Nested Data
```arturo
users: #[
active: @[
#[name: "John" score: 42 tags: ["admin" "dev"]]
#[name: "Alice" score: 28 tags: ["dev"]]
#[name: "Bob" score: 35 tags: ["admin"]]
]
inactive: @[
#[name: "Eve" score: 15 tags: ["guest"]]
]
]
; find all admins with scores > 30
admins: select users\active 'user ->
and? [contains? user\tags "admin"]
[user\score > 40]
print map admins 'usr ->
usr\name
; John
; get unique tags across all users
allTags: unique flatten map users\active 'usr -> usr\tags
; admin dev
```
###### Managing a Priority Queue
```arturo
tasks: []
; add tasks with priorities
'tasks ++ #[priority: 3 task: "Low priority"]
'tasks ++ #[priority: 1 task: "Urgent!"]
'tasks ++ #[priority: 2 task: "Important"]
; sort by priority
sorted: arrange tasks 'item -> item\priority
loop sorted 'item ->
print [item\priority ":" item\task]
; 1 : Urgent!
; 2 : Important
; 3 : Low priority
```
----
#### `append` (alias: `++` - infix: true)
append value to given collection
##### Arguments
- `collection` (:char,:string,:literal,:pathliteral,:binary,:object,:block)
- `value` (:any)
##### Returns
:string,:binary,:object,:block,:nothing
##### Examples
```
append "hell" "o" ; => "hello"
append [1 2 3] 4 ; => [1 2 3 4]
append [1 2 3] [4 5] ; => [1 2 3 4 5]
```
```
print "hell" ++ "o!" ; hello!
print [1 2 3] ++ [4 5] ; [1 2 3 4 5]
```
```
a: "hell"
append 'a "o"
print a ; hello
```
```
b: [1 2 3]
'b ++ 4
print b ; [1 2 3 4]
```
#### `array` (alias: `@` - infix: false)
create array from given block, by reducing/calculating all internal values
##### Arguments
- `source` (:any)
##### Options
- `of` (:integer,:block): initialize an empty n-dimensional array with given dimensions
##### Returns
:block
##### Examples
```
none: @[] ; none: []
a: @[1 2 3] ; a: [1 2 3]
b: 5
c: @[b b+1 b+2] ; c: [5 6 7]
d: @[
3+1
print "we are in the block"
123
print "yep"
]
; we are in the block
; yep
; => [4 123]
```
```
; initializing empty array with initial value
x: array.of: 2 "done"
inspect.muted x
; [ :block
; done :string
; done :string
; ]
```
```
; initializing empty n-dimensional array with initial value
x: array.of: [3 4] 0 ; initialize a 3x4 2D array
; with zeros
; => [[0 0 0 0] [0 0 0 0] [0 0 0 0]]
```
#### `chop`
remove last item from given collection
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
##### Options
- `times` (:integer): remove multiple items
##### Returns
:string,:block,:nothing
##### Examples
```
chop "hellox" ; => "hello"
chop chop "hellox" ; => "hell"
```
```
str: "some text"
chop.times:5 str ; => some
chop.times: neg 5 str ; => text
```
```
arr: @1..10
chop.times:3 'arr
arr ; => [1 2 3 4 5 6 7]
```
```
chop [1 2 3] ; => [1 2]
```
```
chop.times:1 [1 2 3] ; => [1 2]
chop.times:2 [1 2 3] ; => [1]
chop.times:3 [1 2 3] ; => []
chop.times:4 [1 2 3] ; => []
```
```
chop.times: neg 1 [1 2 3] ; => [2 3]
chop.times: neg 2 [1 2 3] ; => [3]
```
#### `combine`
get all possible combinations of the elements in given collection
##### Arguments
- `collection` (:block)
##### Options
- `by` (:integer): define size of each set
- `repeated` (:logical): allow for combinations with repeated elements
- `count` (:logical): just count the number of combinations
##### Returns
:integer,:block
##### Examples
```
combine [A B C]
; => [[A B C]]
combine.repeated [A B C]
; => [[A A A] [A A B] [A A C] [A B B] [A B C] [A C C] [B B B] [B B C] [B C C] [C C C]]
```
```
combine.by:2 [A B C]
; => [[A B] [A C] [B C]]
combine.repeated.by:2 [A B C]
; => [[A A] [A B] [A C] [B B] [B C] [C C]]
combine.repeated.by: 3 [A B]
; => [[A A A] [A A B] [A B B] [B B B]]
```
```
combine.count [A B C]
; => 1
combine.count.repeated.by:2 [A B C]
; => 6
```
#### `contains?`
check if collection contains given value
##### Arguments
- `collection` (:string,:dictionary,:object,:block,:range)
- `value` (:any)
##### Options
- `at` (:integer): check at given location within collection
- `deep` (:logical): search for a value recursively
##### Returns
:logical
##### Examples
```
arr: [1 2 3 4]
contains? arr 5 ; => false
contains? arr 2 ; => true
```
```
user: #[
name: "John"
surname: "Doe"
]
contains? dict "John" ; => true
contains? dict "Paul" ; => false
contains? keys dict "name" ; => true
```
```
contains? "hello" "x" ; => false
contains? "hello" `h` ; => true
```
```
contains?.at:1 "hello" "el" ; => true
contains?.at:4 "hello" `o` ; => true
```
```
print contains?.at:2 ["one" "two" "three"] "two"
; false
print contains?.at:1 ["one" "two" "three"] "two"
; true
```
```
print contains?.deep [1 2 4 [3 4 [5 6] 7] 8 [9 10]] 6
; true
```
```
user: #[
name: "John" surname: "Doe"
mom: #[ name: "Jane" surname: "Doe" ]
]
print contains?.deep user "Jane"
; true
```
#### `couple`
combine elements of given collections into an array of tuples
##### Arguments
- `collectionA` (:block)
- `collectionB` (:block)
##### Returns
:block
##### Examples
```
couple ["one" "two" "three"] [1 2 3]
; => [[1 "one"] [2 "two"] [3 "three"]]
```
#### `decouple`
separate a collection of tuples into a tuple of collections
##### Arguments
- `collection` (:literal,:pathliteral,:block)
##### Returns
:block
##### Examples
```
c: couple ["one" "two" "three"] [1 2 3]
; c: [[1 "one"] [2 "two"] [3 "three"]]
decouple c
; => ["one" "two" "three"] [1 2 3]
```
#### `dictionary` (alias: `#` - infix: false)
create dictionary from given block or file, by evaluating and retrieving all defined symbols
##### Arguments
- `source` (:string,:block)
##### Options
- `with` (:block): embed given symbols
- `raw` (:logical): create dictionary from raw block
- `lower` (:logical): automatically convert all keys to lowercase
##### Returns
:dictionary
##### Examples
```
none: #[] ; none: []
a: #[
name: "John"
age: 34
]
; a: [name: "John", age: 34]
d: #[
name: "John"
print "we are in the block"
age: 34
print "yep"
]
; we are in the block
; yep
; d: [name: "John", age: 34]
```
```
inspect fromBlock: #.raw [a b c d]
; [ :dictionary
; a : b :word
; c : d :word
; ]
```
```
e: #.lower [
Name: "John"
suRnaMe: "Doe"
AGE: 35
]
; e: [name:John, surname:Doe, age:35]
```
```
entity: "EU"
location: dictionary.with: [entity][
country: "Spain"
]
print location\entity ; => EU
```
#### `drop`
remove first item from given collection
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
##### Options
- `times` (:integer): remove multiple items
##### Returns
:string,:block,:nothing
##### Examples
```
drop "xhello" ; => "hello"
drop drop "xhello" ; => "ello"
```
```
str: "some text"
drop.times:5 str ; => text
drop.times: neg 5 str ; => some
```
```
arr: @1..10
drop.times:3 'arr
arr ; => [4 5 6 7 8 9 10]
```
```
drop [1 2 3] ; => [2 3]
```
```
drop.times:1 [1 2 3] ; => [2 3]
drop.times:2 [1 2 3] ; => [3]
drop.times:3 [1 2 3] ; => []
drop.times:4 [1 2 3] ; => []
```
```
drop.times: neg 1 [1 2 3] ; => [1 2]
drop.times: neg 2 [1 2 3] ; => [1]
```
#### `empty`
remove all elements from given collection
##### Arguments
- `collection` (:literal,:pathliteral)
##### Returns
:nothing
##### Examples
```
a: [1 2 3]
empty 'a ; a: []
```
```
str: "some text"
empty 'str ; str: ""
```
#### `empty?`
check if given collection is empty
##### Arguments
- `collection` (:null,:string,:dictionary,:block)
##### Returns
:logical
##### Examples
```
empty? "" ; => true
empty? [] ; => true
empty? #[] ; => true
empty? [1 "two" 3] ; => false
```
#### `extend`
merge given dictionary into parent
##### Arguments
- `parent` (:literal,:pathliteral,:dictionary)
- `additional` (:dictionary)
##### Returns
:dictionary
##### Examples
```
person: #[ name: "john" surname: "doe" ]
print extend person #[ age: 35 ]
; [name:john surname:doe age:35]
```
#### `first`
return the first item of the given collection
##### Arguments
- `collection` (:string,:block,:range)
##### Options
- `n` (:integer): get first *n* items
##### Returns
:null,:any
##### Examples
```
print first "this is some text" ; t
print first ["one" "two" "three"] ; one
```
```
print first.n:2 ["one" "two" "three"] ; one two
```
#### `flatten`
flatten given collection by recursively eliminating nested blocks
##### Arguments
- `collection` (:literal,:pathliteral,:block)
##### Options
- `once` (:logical): do not perform recursive flattening
##### Returns
:block
##### Examples
```
arr: [[1 2 3] [4 5 6]]
print flatten arr
; 1 2 3 4 5 6
```
```
arr: [[1 2 3] [4 5 6]]
flatten 'arr
; arr: [1 2 3 4 5 6]
```
```
flatten [1 [2 3] [4 [5 6]]]
; => [1 2 3 4 5 6]
```
```
flatten.once [1 [2 3] [4 [5 6]]]
; => [1 2 3 4 [5 6]]
```
#### `get`
get collection's item by given index
##### Arguments
- `collection` (:complex,:string,:error,:errorkind,:date,:binary,:dictionary,:object,:store,:block,:range,:bytecode)
- `index` (:any)
##### Options
- `field` (:logical): get field value, overriding type magic methods
##### Returns
:any
##### Examples
```
user: #[
name: "John"
surname: "Doe"
]
print user\name ; John
print get user 'surname ; Doe
print user\surname ; Doe
```
```
arr: ["zero" "one" "two"]
print arr\1 ; one
print get arr 2 ; two
y: 2
print arr\[y] ; two
```
```
str: "Hello world!"
print str\0 ; H
print get str 1 ; e
z: 0
print str\[z+1] ; e
print str\[0..4] ; Hello
```
```
a: to :complex [1 2]
print a\real ; 1.0
print a\imaginary ; 2.0
print a\1 ; 2.0
```
```
define :person [
get: method [what][
(key? this what)? -> get.field this what ; if the key exists, return the value
-> "DEFAULT" ; otherwise, do something else
]
]
```
#### `in?` (alias: `∈` - infix: true)
check if value exists in given collection
##### Arguments
- `value` (:any)
- `collection` (:string,:dictionary,:object,:block,:range)
##### Options
- `at` (:integer): check at given location within collection
- `deep` (:logical): search for a value recursively
##### Returns
:logical
##### Examples
```
arr: [1 2 3 4]
in? 5 arr ; => false
in? 2 arr ; => true
```
```
user: #[
name: "John"
surname: "Doe"
]
in? "John" dict ; => true
in? "Paul" dict ; => false
in? "name" keys dict ; => true
```
```
in? "x" "hello" ; => false
in? `h` "hello" ; => true
```
```
in?.at:1 "el" "hello" ; => true
in?.at:4 `o` "hello" ; => true
```
```
print in?.at:2 "two" ["one" "two" "three"]
; false
print in?.at:1 "two" ["one" "two" "three"]
; true
```
```
print in?.deep 6 [1 2 4 [3 4 [5 6] 7] 8 [9 10]]
; true
```
```
user: #[
name: "John" surname: "Doe"
mom: #[ name: "Jane" surname: "Doe" ]
]
print in?.deep "Jane" user
; true
```
#### `index`
return first index of value in given collection
##### Arguments
- `collection` (:string,:dictionary,:block,:range)
- `value` (:any)
##### Returns
:null,:integer,:string
##### Examples
```
ind: index "hello" "e"
print ind ; 1
```
```
print index [1 2 3] 3 ; 2
```
```
type index "hello" "x"
; :null
```
#### `insert`
insert value in collection at given index
##### Arguments
- `collection` (:string,:literal,:pathliteral,:dictionary,:block)
- `index` (:integer,:string)
- `value` (:any)
##### Returns
:string,:dictionary,:block,:nothing
##### Examples
```
insert [1 2 3 4] 0 "zero"
; => ["zero" 1 2 3 4]
print insert "heo" 2 "ll"
; hello
```
```
dict: #[
name: John
]
insert 'dict 'name "Jane"
; dict: [name: "Jane"]
```
#### `key?`
check if collection contains given key
##### Arguments
- `collection` (:dictionary,:object)
- `key` (:any)
##### Returns
:logical
##### Examples
```
user: #[
name: "John"
surname: "Doe"
]
key? user 'age ; => false
if key? user 'name [
print ["Hello" user\name]
]
; Hello John
```
#### `keys`
get list of keys for given collection
##### Arguments
- `dictionary` (:dictionary,:object)
##### Returns
:block
##### Examples
```
user: #[
name: "John"
surname: "Doe"
]
keys user
=> ["name" "surname"]
```
#### `last`
return the last item of the given collection
##### Arguments
- `collection` (:string,:block,:range)
##### Options
- `n` (:integer): get last *n* items
##### Returns
:null,:any
##### Examples
```
print last "this is some text" ; t
print last ["one" "two" "three"] ; three
```
```
print last.n:2 ["one" "two" "three"] ; two three
```
#### `max`
get maximum element in given collection
##### Arguments
- `collection` (:block,:range)
##### Options
- `index` (:logical): retrieve index of maximum element
##### Returns
:null,:any
##### Examples
```
print max [4 2 8 5 1 9] ; 9
```
#### `min`
get minimum element in given collection
##### Arguments
- `collection` (:block,:range)
##### Options
- `index` (:logical): retrieve index of minimum element
##### Returns
:null,:any
##### Examples
```
print min [4 2 8 5 1 9] ; 1
```
#### `one?`
check if given number or collection size is one
##### Arguments
- `number` (:null,:integer,:floating,:string,:dictionary,:block,:range)
##### Returns
:logical
##### Examples
```
one? 5 ; => false
one? 4-3 ; => true
```
```
one? 1.0 ; => true
one? 0.0 ; => false
```
```
items: ["apple"]
one? items ; => true
items: [1 2 3]
one? items ; => false
```
```
one? ø ; => false
```
#### `permutate`
get all possible permutations of the elements in given collection
##### Arguments
- `collection` (:block)
##### Options
- `by` (:integer): define size of each set
- `repeated` (:logical): allow for permutations with repeated elements
- `count` (:logical): just count the number of permutations
##### Returns
:block
##### Examples
```
permutate [A B C]
; => [[A B C] [A C B] [B A C] [B C A] [C A B] [C B A]]
permutate.repeated [A B C]
; => [[A A A] [A A B] [A A C] [A B A] [A B B] [A B C] [A C A] [A C B] [A C C] [B A A] [B A B] [B A C] [B B A] [B B B] [B B C] [B C A] [B C B] [B C C] [C A A] [C A B] [C A C] [C B A] [C B B] [C B C] [C C A] [C C B] [C C C]]
```
```
permutate.by:2 [A B C]
; => [[A B] [A C] [B A] [B C] [C A] [C B]]
permutate.repeated.by:2 [A B C]
; => [[A A] [A B] [A C] [B A] [B B] [B C] [C A] [C B] [C C]]
permutate.repeated.by:3 [A B]
; => [[A A A] [A A B] [A B A] [A B B] [B A A] [B A B] [B B A] [B B B]]
```
```
permutate.count [A B C]
; => 6
permutate.count.repeated.by:2 [A B C]
; => 9
```
#### `pop`
remove and return the last item from given collection
##### Arguments
- `collection` (:literal,:pathliteral)
##### Options
- `n` (:integer): remove multiple items. (Must be greater than 0.)
##### Returns
:any
##### Examples
```
a: [0 1 2 3 4 5]
b: pop 'a
inspect a
; [ :block
; 0 :integer
; 1 :integer
; 2 :integer
; 3 :integer
; 4 :integer
; ]
inspect b ; 5 :integer
b: pop.n: 2 'a
inspect a
; [ :block
; 0 :integer
; 1 :integer
; 2 :integer
; ]
inspect b
; [ :block
; 3 :integer
; 4 :integer
; ]
```
```
a: "Arturoo"
b: pop 'a
inspect a ; Arturo :string
inspect b ; o :char
b: pop.n: 3 'a
inspect a ; Art :string
inspect b ; uro :string
```
#### `prepend`
prepend value to given collection
##### Arguments
- `collection` (:char,:string,:literal,:pathliteral,:binary,:block)
- `value` (:any)
##### Returns
:string,:binary,:block,:nothing
##### Examples
```
prepend "uro" "Art" ; => "Arturo"
prepend [2 3 4] 1 ; => [1 2 3 4]
prepend [3 4 5] [1 2] ; => [1 2 3 4 5]
```
```
a: "pend"
prepend 'a "pre"
print a ; prepend
```
#### `range` (alias: `..` - infix: true)
get list of values in given range (inclusive)
##### Arguments
- `from` (:integer,:char)
- `to` (:integer,:floating,:char)
##### Options
- `step` (:integer): use step between range values
##### Returns
:range
##### Examples
```
; range of :integers
range 0 5 ; 0..5
0..5 ; 0..5
@0..5 ; [0 1 2 3 4 5]
```
```
; range of :chars
'a'..'e' ; 'a'..'e'
@'a'..'e' ; [a b c d e]
```
```
; range with steps
@range.step: 2 1 5 ; [1 3 5]
```
```
; iterate a range
0..5 | loop 'i -> print ~"|i|. hello"
; 0. hello
; 1. hello
; 2. hello
; 3. hello
; 4. hello
; 5. hello
```
```
; check bounds
in? 5 0..10 ; => true
```
#### `remove` (alias: `--` - infix: true)
remove value from given collection
##### Arguments
- `collection` (:string,:literal,:pathliteral,:dictionary,:object,:block)
- `value` (:any)
##### Options
- `key` (:logical): remove dictionary key
- `once` (:logical): remove only first occurrence
- `index` (:logical): remove specific index
- `prefix` (:logical): remove first matching prefix from string
- `suffix` (:logical): remove first matching suffix from string
- `instance` (:logical): remove an instance of a block, instead of its elements.
##### Returns
:string,:dictionary,:block,:nothing
##### Examples
```
remove "hello" "l" ; => "heo"
print "hello" -- "l" ; heo
remove [1 2 3 4] 4 ; => [1 2 3]
```
```
str: "mystring"
remove 'str "str"
print str ; mying
```
```
remove.key #[name: "John" surname: "Doe"] "surname" ; => #[name: "John"]
```
```
print remove.once "hello" "l"
; helo
; Remove each element of given block from collection once
remove.once [1 2 [1 2] 3 4 1 2 [1 2] 3 4] [1 2]
; [[1 2] 3 4 1 2 [1 2] 3 4]
```
```
remove.index: 2 "Ruby" "u" ; => Rby
remove.index: 2 "Ruby" "a" ; => Ruby
```
```
remove.prefix "--empty --flag" "--" ; => "empty --flag"
remove.suffix "test.txt file.txt" ".txt" ; => "test.txt file"
```
```
remove.instance [1 [6 2] 5 3 [6 2] 4 5 6] [6 2] ; => [1 5 3 4 5 6]
remove.instance.once [1 [6 2] 5 3 [6 2] 4 5 6] [6 2] ; => [1 5 3 [6 2] 4 5 6]
```
#### `repeat`
repeat value the given number of times and return new one
##### Arguments
- `value` (:literal,:pathliteral,:any)
- `times` (:integer)
##### Returns
:string,:block
##### Examples
```
print repeat "hello" 3
; hellohellohello
```
```
repeat [1 2 3] 3
; => [1 2 3 1 2 3 1 2 3]
```
```
repeat 5 3
; => [5 5 5]
```
```
repeat [[1 2 3]] 3
; => [[1 2 3] [1 2 3] [1 2 3]]
```
#### `reverse`
reverse given collection
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block,:range)
##### Options
- `exact` (:logical): make sure the reverse range contains the same elements
##### Returns
:string,:block,:nothing
##### Examples
```
print reverse [1 2 3 4] ; 4 3 2 1
print reverse "Hello World" ; dlroW olleH
```
```
str: "my string"
reverse 'str
print str ; gnirts ym
```
#### `rotate`
rotate collection elements by given offset
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
- `offset` (:integer)
##### Options
- `left` (:logical): left rotation
##### Returns
:string,:block,:nothing
##### Examples
```
rotate [a b c d e] 1 ; => [e a b c d]
rotate.left [a b c d e] 1 ; => [b c d e a]
rotate 1..6 4 ; => [3 4 5 6 1 2]
```
#### `sample`
get a random element from given collection
##### Arguments
- `collection` (:block,:range)
##### Returns
:null,:any
##### Examples
```
sample [1 2 3] ; (return a random number from 1 to 3)
print sample ["apple" "appricot" "banana"]
; apple
```
#### `set`
set collection's item at index to given value
##### Arguments
- `collection` (:string,:binary,:dictionary,:object,:store,:block,:bytecode)
- `index` (:any)
- `value` (:any)
##### Options
- `field` (:logical): set field value, overriding type magic methods
##### Returns
:nothing
##### Examples
```
myDict: #[
name: "John"
age: 34
]
set myDict 'name "Michael" ; => [name: "Michael", age: 34]
```
```
arr: [1 2 3 4]
set arr 0 "one" ; => ["one" 2 3 4]
arr\1: "dos" ; => ["one" "dos" 3 4]
x: 2
arr\[x]: "tres" ; => ["one" "dos" "tres" 4]
```
```
str: "hello"
str\0: `x`
print str
; xello
```
```
define :person [
set: method [what, value][
; do some processing...
set.field this what value
; and actually set the value internally
]
]
```
#### `shuffle`
randomize the order of elements in given collection
##### Arguments
- `collection` (:literal,:pathliteral,:block)
##### Returns
:block,:nothing
##### Examples
```
shuffle [1 2 3 4 5 6] ; => [1 5 6 2 3 4 ]
```
```
arr: [2 5 9]
shuffle 'arr
print arr ; 5 9 2
```
#### `size`
get size/length of given collection
##### Arguments
- `collection` (:null,:string,:binary,:dictionary,:object,:block,:range)
##### Returns
:integer,:floating
##### Examples
```
arr: ["one" "two" "three"]
print size arr ; 3
```
```
dict: #[name: "John", surname: "Doe"]
print size dict ; 2
```
```
str: "some text"
print size str ; 9
print size "你好!" ; 3
```
#### `slice`
extract a sub-collection between given indices
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
- `from` (:integer)
- `to` (:integer)
##### Returns
:string,:block
##### Examples
```
slice "Hello" 0 3 ; => "Hell"
```
```
print slice 1..10 3 4 ; 4 5
```
#### `sort`
sort given collection in ascending order
##### Arguments
- `collection` (:literal,:pathliteral,:dictionary,:block)
##### Options
- `as` (:literal): localized by ISO 639-1 language code
- `sensitive` (:logical): case-sensitive sorting
- `descending` (:logical): sort in descending order
- `values` (:logical): sort dictionary by values
- `by` (:string,:literal): sort array of dictionaries by given key
##### Returns
:block,:nothing
##### Examples
```
a: [3 1 6]
print sort a ; 1 3 6
```
```
print sort.descending a ; 6 3 1
```
```
b: ["one" "two" "three"]
sort 'b
print b ; one three two
```
```
; Creating a Priority Queue
tasks: []
; add tasks with priorities
'tasks ++ #[priority: 3 task: "Low priority"]
'tasks ++ #[priority: 1 task: "Urgent!"]
'tasks ++ #[priority: 2 task: "Important"]
; sort by priority
sorted: sort.by: 'priority tasks
loop sorted 'item ->
print [item\priority ":" item\task]
; 1 : Urgent!
; 2 : Important
; 3 : Low priority
```
```
spanishWords: ["uno","dos","tres","Uno","perversión","ábaco","abismo", "aberración"]
sort.as: 'es spanishWords
; => ["ábaco" "aberración" "abismo" "dos" "perversión" "tres" "uno" "Uno"]
```
```
sort.sensitive ["c" "C" "CoffeeScript" "nim" "Arturo" "coffeescript" "arturo" "Nim"]
; => ["Arturo" "C" "CoffeeScript" "Nim" "arturo" "c" "coffeescript" "nim"]
```
```
sort.values #[ name: "John" surname: "Doe" age: 35 income: 5000]
; => #[age: 35 income: 5000 surname: "Doe" name: "John" ]
```
#### `sorted?`
check if given collection is already sorted
##### Arguments
- `collection` (:block)
##### Options
- `descending` (:logical): check for sorting in ascending order
##### Returns
:logical
##### Examples
```
sorted? [1 2 3 4 5] ; => true
sorted? [4 3 2 1 5] ; => false
sorted? [5 4 3 2 1] ; => false
```
```
sorted?.descending [5 4 3 2 1] ; => true
sorted?.descending [4 3 2 1 5] ; => false
sorted?.descending [1 2 3 4 5] ; => false
```
#### `split`
split collection into parts based on criteria
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
##### Options
- `words` (:logical): split string by whitespace
- `lines` (:logical): split string by lines
- `by` (:char,:string,:regex,:block): split using given separator
- `at` (:integer): split collection at given position
- `every` (:integer): split collection every *n* elements
- `path` (:logical): split path components in string
##### Returns
:block,:nothing
##### Examples
```
split "hello" ; => [`h` `e` `l` `l` `o`]
```
```
split.words "hello world" ; => ["hello" "world"]
split.by: "," "hello,world" ; => ["hello" "world"]
split.lines "hello\nworld" ; => ["hello" "world"]
split.path "/usr/bin" ; => ["usr" "bin"]
; windows only:
split.path "\\usr\\bin" ; => ["usr" "bin"]
```
```
split.every: 2 "helloworld"
; => ["he" "ll" "ow" "or" "ld"]
```
```
split.at: 4 "helloworld"
; => ["hell" "oworld"]
```
```
arr: 1..9
split.at:3 'arr
; => [ [1 2 3 4] [5 6 7 8 9] ]
```
#### `squeeze`
reduce adjacent duplicate elements in given collection
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
##### Returns
:string,:block,:nothing
##### Examples
```
print squeeze [1 1 2 3 4 2 3 4 4 5 5 6 7]
; 1 2 3 4 2 3 4 5 6 7
```
```
arr: [4 2 1 1 3 6 6]
squeeze 'arr ; a: [4 2 1 3 6]
```
```
print squeeze "hello world"
; helo world
```
#### `take`
keep first N elements from given collection
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block,:range)
- `number` (:integer)
##### Returns
:string,:block,:nothing
##### Examples
```
str: "some text"
take str 4 ; => some
take str neg 4 ; => text
take 1..3 2 ; => [1 2]
```
```
arr: @1..10
take 'arr 3
arr ; => arr: [1 2 3]
```
```
take [1 2 3] 3 ; => [1 2 3]
take [1 2 3] 4 ; => [1 2 3]
```
#### `tally`
find number of occurrences of each value within given block and return as dictionary
##### Arguments
- `collection` (:string,:block)
##### Returns
:dictionary
##### Examples
```
tally "helloWorld"
; => [h:1 e:1 l:3 o:2 W:1 r:1 d:1]
```
```
tally [1 2 4 1 3 5 6 2 6 3 5 7 2 4 2 4 5 6 2 1 1 1]
; => [1:5 2:5 4:3 3:2 5:3 6:3 7:1]
```
#### `unique`
get given collection without duplicates
##### Arguments
- `collection` (:string,:literal,:pathliteral,:block)
##### Options
- `id` (:logical): generate unique id using given prefix
##### Returns
:block,:nothing
##### Examples
```
arr: [1 2 4 1 3 2]
print unique arr ; 1 2 4 3
```
```
arr: [1 2 4 1 3 2]
unique 'arr
print arr ; 1 2 4 3
```
```
unique.id "user-" ; => user-67915b7a409e222b2f9a6bed
```
#### `values`
get list of values for given collection
##### Arguments
- `dictionary` (:dictionary,:object,:block,:range)
##### Returns
:block
##### Examples
```
user: #[
name: "John"
surname: "Doe"
]
values user ; => ["John" "Doe"]
```
#### `zero?`
check if given number or collection size is zero
##### Arguments
- `number` (:null,:integer,:floating,:string,:dictionary,:block,:range)
##### Returns
:logical
##### Examples
```
zero? 5-5 ; => true
zero? 4 ; => false
```
```
zero? 1.0 ; => false
zero? 0.0 ; => true
```
```
items: [1 2 3]
zero? items ; => false
items: []
zero? items ; => true
```
```
zero? ø ; => true
```
### Colors
Functions and helpers for manipulating color values
----
The Colors module provides comprehensive color handling capabilities. It includes support for RGB colors, color manipulations, and a rich set of predefined color names.
#### Key Concepts
- RGB color representation
- Color manipulation (blending, saturation, etc.)
- Support for alpha channel
- Over 350 predefined color names
- Color space conversions (RGB, HSL, HSV)
#### Basic Usage
##### Creating Colors
```arturo
; using hex notation
color1: #f00 ; short RGB
color2: #ff0000 ; full RGB
color3: #ff0000ff ; RGB with alpha
; using predefined colors
red: #red
azure: #azure
deepPurple: #deepPurple
; extracting components
extract.red #ff0000 ; => 255
extract.green #00ff00 ; => 255
extract.blue #0000ff ; => 255
extract.alpha #ff0000ff ; => 255
```
##### Color Operations
```arturo
; lighten/darken
dark: darken #red 0.3 ; 30% darker (= #B20000)
light: lighten #emerald 0.2 ; 20% lighter (= #60F090)
; saturation
more: saturate #green 0.4 ; 40% more saturated (= #008000)
less: desaturate #green 0.4 ; 40% less saturated (= #1A661A)
; blending
mixed: blend #red #blue ; 50-50 mix (= #800080)
customMix: blend.balance:0.7 #red #blue ; 70-30 mix (= #4D00B3)
; invert colors
opposite: invert #white ; #black
```
##### Color Space Conversions
```arturo
col: #magenta ; #FF00FF
; get HSL representation
hsl: extract.hsl col ; #[hue:300 saturation:1.0 luminosity:0.5]
; get HSV representation
hsv: extract.hsv col ; #[hue:300 saturation:1.0 value:1.0]
; create the same color
; starting from its HSV representation
newColor: to :color .hsv [300, 1.0 1.0] ; #FF00FF (yep, #magenta!)
```
##### Color Palettes
```arturo
baseColor: #4169e1 ; royal blue
; generate different palettes
print palette.triad baseColor
; #4169E1 #E14169 #69E141
print palette.tetrad baseColor
; #4169E1 #E141B9 #E1B941 #41E169
print palette.split baseColor
; #4169E1 #D941E1 #A9E141
print palette.analogous baseColor
; #41C9E1 #41A9E1 #4189E1 #4169E1 #4149E1 #5941E1
```
#### Predefined Colors
> [!NOTE] Colors can be referenced using their names in various formats. For example, `deep sea blue` can be written as `#deepSeaBlue`, `#deepsea` or even just `#deep`.
Here are some of the most commonly used colors organized by hue:
##### Reds
- `#red`, `#crimson`, `#darkRed`, `#fireEngineRed`, `#cherryRed`
- `#ruby`, `#burgundy`, `#bloodRed`, `#lavaRed`
##### Blues
- `#blue`, `#navy`, `#royalBlue`, `#skyBlue`, `#azureBlue`
- `#cobaltBlue`, `#cornflowerBlue`, `#denimBlue`, `#deepSeaBlue`
##### Greens
- `#green`, `#emerald`, `#forestGreen`, `#limeGreen`, `#seaGreen`
- `#oliveGreen`, `#sageGreen`, `#mintGreen`, `#jade`
##### Purples
- `#purple`, `#violet`, `#plum`, `#lavender`, `#mauve`
- `#orchid`, `#royalPurple`, `#deepPurple`, `#amethyst`
##### Yellows & Oranges
- `#yellow`, `#gold`, `#amber`, `#mustard`, `#canary`
- `#orange`, `#tangerine`, `#coral`, `#peach`
##### Neutrals
- `#white`, `#black`, `#gray`, `#silver`
- `#beige`, `#tan`, `#brown`, `#taupe`
> [!TIP] The complete list of colors can be found in the [Arturo repository](https://github.com/arturo-lang/arturo/blob/master/src/vm/values/custom/vcolor.nim#L41-L618), although it would be most likely safe to say that any [W3C color name recognized](https://www.w3schools.com/tags/ref_colornames.asp) is also recognized by Arturo too.
#### Common Patterns
##### Working with Alpha
```arturo
; full opacity
solid: #ff0000ff ; red, 100% opaque
; semi-transparent
trans: #ff000080 ; red, 50% transparent
```
----
#### `blend`
blend given colors and get result
##### Arguments
- `colorA` (:literal,:pathliteral,:color)
- `colorB` (:color)
##### Options
- `balance` (:floating): use different mix of color (0.0-1.0, default:0.5)
##### Returns
:color
##### Examples
```
blend #red #CCCCCC ; => #E66666
```
```
blend .balance: 0.75 #red #CCCCCC
; => #D99999
```
#### `darken`
darken color by given percentage (0.0-1.0)
##### Arguments
- `color` (:literal,:pathliteral,:color)
- `percent` (:floating)
##### Returns
:color
##### Examples
```
darken #red 0.2 ; => #CC0000
darken #red 0.5 ; => #7F0000
darken #9944CC 0.3 ; => #6B308F
```
#### `desaturate`
desaturate color by given percentage (0.0-1.0)
##### Arguments
- `color` (:literal,:pathliteral,:color)
- `percent` (:floating)
##### Returns
:color
##### Examples
```
desaturate #red 0.2 ; => #E61919
desaturate #red 0.5 ; => #BF4040
desaturate #9944CC 0.3 ; => #9558B8
```
#### `grayscale`
convert color to grayscale
##### Arguments
- `color` (:literal,:pathliteral,:color)
##### Returns
:color
##### Examples
```
grayscale #red ; => #808080
grayscale #green ; => #404040
grayscale #FF44CC ; => #A2A2A2
```
#### `invert`
get complement for given color
##### Arguments
- `color` (:literal,:pathliteral,:color)
##### Returns
:color
##### Examples
```
print #orange ; #FFA500
invert #orange ; => #0059FF
```
#### `lighten`
lighten color by given percentage (0.0-1.0)
##### Arguments
- `color` (:literal,:pathliteral,:color)
- `percent` (:floating)
##### Returns
:color
##### Examples
```
print #lightblue ; #ADD8E6
lighten #lightblue 0.2 ; => #D0FFFF
lighten #lightblue 0.5 ; => #FFFFFF
lighten #9944CC 0.3 ; => #C758FF
```
#### `palette`
create palette using given base color
##### Arguments
- `color` (:color)
##### Options
- `triad` (:logical): generate a triad palette
- `tetrad` (:logical): generate a tetrad palette
- `split` (:logical): generate a split complement palette
- `analogous` (:logical): generate an analogous palette
- `monochrome` (:logical): generate a monochromatic palette
- `random` (:logical): generate random palette based on color triads
- `size` (:integer): specify the size of the generated palette
##### Returns
:block
##### Examples
```
palette.triad #red ; => [#FF0000 #00FF00 #0000FF]
palette.tetrad #red ; => [#FF0000 #80FF00 #00FFFF #7F00FF]
```
```
palette.split #red ; => [#FF0000 #CCFF00 #0066FF]
```
```
palette.monochrome #red
; => [#FF0000 #D40000 #AA0000 #7F0000 #550000 #2A0000]
palette.monochrome.size:10 #red
; => [#FF0000 #E50000 #CC0000 #B20000 #990000 #7F0000 #660000 #4C0000 #330000 #190000]
```
```
palette.analogous #red
; => [#FF0099 #FF0066 #FF0033 #FF0000 #FF3300 #FF6600]
palette.analogous.size:10 #red
; => [#FF00FF #FF00CC #FF0099 #FF0066 #FF0033 #FF0000 #FF3300 #FF6600 #FF9900 #FFCC00]
```
```
palette.random #red
; => [#FF0000 #00EC00 #0000D2 #00F000 #0000FF #00FF00]
palette.random.size:10 #red
; => [#FF0000 #00FF00 #0000FF #00FE00 #F30000 #00FD00 #0000ED #EC0000 #00F800 #0000D8]
```
#### `saturate`
saturate color by given percentage (0.0-1.0)
##### Arguments
- `color` (:literal,:pathliteral,:color)
- `percent` (:floating)
##### Returns
:color
##### Examples
```
print #lightblue ; #ADD8E6
saturate #lightblue 0.2 ; => #A7DBEC
saturate #lightblue 0.5 ; => #9FDFF4
saturate #9944CC 0.3 ; => #A030E0
```
#### `spin`
spin color around the hue wheel by given amount
##### Arguments
- `color` (:literal,:pathliteral,:color)
- `amount` (:integer)
##### Returns
:color
##### Examples
```
spin #red 90 ; => #80FF00
spin #red 180 ; => #00FFFF
spin #123456 45 ; => #231256
spin #123456 360 ; => #123456
```
### Comparison
Comparison operations for any kind of value
----
The Comparison module provides functions for comparing values of any type. Beyond basic equality checks, it includes ordering operations and advanced comparison features.
#### Key Concepts
- Works with all value types
- Consistent behavior across different types
- Support for both equality and ordering
- Range checking with `between?`
#### Basic Usage
##### Simple Comparisons
```arturo
; equality
print 2 = 2 ; true
print "abc" = "abc" ; true
print 2 = "2" ; false
; inequality
print 2 <> 3 ; true
print "abc" <> "def" ; true
print 2.0 <> 2 ; false
```
##### Ordering
```arturo
; less/greater than
print 2 < 3 ; true
print 3 > 2 ; true
; less/greater or equal
print 2 =< 2 ; true
print 3 >= 2 ; true
```
> [!NOTE] The ordering operators work with numbers, strings, dates, and any type that defines ordering.
##### Range Checking
```arturo
; check if value is in range (inclusive)
5 <=> 1 10 ; => true
'm' <=> 'a' 'z' ; => true
; or more explicitly
between? 5 1 10 ; => true
```
> [!TIP] Another way to check if a value is within a given range would be `contains?` - or its reversed equivalent - `in?`.
#### Common Patterns
##### Custom Sorting
The `compare` function returns -1, 0, or 1 and is useful for custom sorting:
```arturo
a: "hello"
b: "world"
result: compare a b ; -1
print ["A comes" (result < 0)? -> "before" -> "after" "B"]
; A comes before B
```
##### Identity vs Equality
```arturo
x: 1`N
y: 1`kg.m/s2 ; actually, that's the definition of 1 Newton!
; equality (same value)
print x = y ; true
; identity (exactly the same?)
print same? x y ; false
```
----
#### `between?` (alias: `<=>` - infix: true)
check if given value is between the given values (inclusive)
##### Arguments
- `value` (:any)
- `rangeFrom` (:any)
- `rangeTo` (:any)
##### Returns
:logical
##### Examples
```
between? 1 2 3 ; => false
between? 2 0 3 ; => true
between? 3 2 3 ; => true
between? 3 3 2 ; => true
1 <=> 2 3 ; => false
1 <=> 3 2 ; => false
2 <=> 0 3 ; => true
2 <=> 3 0 ; => true
3 <=> 2 3 ; => true
```
#### `compare`
compare given values and return -1, 0, or 1 based on the result
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:integer
##### Examples
```
compare 1 2 ; => -1
compare 3 3 ; => 0
compare 4 3 ; => 1
```
#### `equal?` (alias: `=` - infix: true)
check if valueA = valueB (equality)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
equal? 5 2 ; => false
equal? 5 6-1 ; => true
print 3=3 ; true
```
#### `greater?` (alias: `>` - infix: true)
check if valueA > valueB (greater than)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
greater? 5 2 ; => true
greater? 5 6-1 ; => false
print 3>2 ; true
```
#### `greaterOrEqual?` (alias: `>=` - infix: true)
check if valueA >= valueB (greater than or equal)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
greaterOrEqual? 5 2 ; => true
greaterOrEqual? 5 4-1 ; => false
print 2>=2 ; true
```
#### `less?` (alias: `<` - infix: true)
check if valueA < valueB (less than)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
less? 5 2 ; => false
less? 5 6+1 ; => true
print 2<3 ; true
```
#### `lessOrEqual?` (alias: `=<` - infix: true)
check if valueA =< valueB (less than or equal)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
lessOrEqual? 5 2 ; => false
lessOrEqual? 5 6-1 ; => true
print 2=<3 ; true
```
#### `notEqual?` (alias: `<>` - infix: true)
check if valueA <> valueB (not equal)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
notEqual? 5 2 ; => true
notEqual? 5 6-1 ; => false
print 2<>3 ; true
```
#### `same?`
check if given values are exactly the same (identity)
##### Arguments
- `valueA` (:any)
- `valueB` (:any)
##### Returns
:logical
##### Examples
```
same? 1 2 ; => false
same? 3 3 ; => true
same? 3 3.0 ; => false
```
### Core
Basic functions and constants that make up the very core of the language
----
The Core module provides the fundamental building blocks of Arturo: functions for control flow, variable assignment, function definition, and basic program structure.
#### Key Concepts
- Variable and symbol management
- Control flow and conditionals
- Function and method definitions
- Scope management and modules
- Basic constants (null, any)
#### Basic Usage
##### Variable Assignment
```arturo
; basic assignment
x: 5 ; assign value to symbol
let 'x 5 ; alternative syntax
; multiple assignments
[a,b,c]: 1,2,3 ; assign multiple values
```
##### Conditionals
Arturo provides several ways to handle conditional execution:
```arturo
; simple if statement
if x=2 [
print "x is two"
]
; using the arrow operator for single statements
if x=2 ->
print "x is two"
; switch statement (if-else)
switch x=2 -> print "x is two"
-> print "x is not two"
; the exact same thing, using `?`
(x=2)? -> print "x is two"
-> print "x is not two"
; case statement (value matching)
case value [
1 -> print "one"
2 -> print "two"
"abc" -> print "found abc"
any -> print "something else" ; default case
]
; multiple conditions
when [
x=1 -> print "x is one"
x>10 -> print "x is greater than ten"
x<0 -> print "x is negative"
true -> print "none of the above" ; default case
]
; check all conditions without breaking
when.any [
prime? x -> print "x is prime"
even? x -> print "x is even"
x>100 -> print "x is large"
]
; with shared condition target
when.has: x [
[>10] -> print "greater than 10"
[<0] -> print "negative"
[=5] -> print "equals 5"
]
```
> [!NOTE] The `->` arrow operator can be used to wrap a single expression in a block, making code more readable.
##### Function Definition
```arturo
; basic function
sum: function [a b][
a + b
]
; with the $ shorthand
multiply: $[x y][
x * y
]
; using arrow syntax for simple functions
double: $[x]-> x * 2
```
##### Modules
Modules are a way of isolating pieces of code so that we can expose only the functions we need, while still safeguarding parts of the internal implementation.
```arturo
; create new module
math: module [
pwr: function [x][
x * x
]
calculate: method.public [z][
\pwr z
]
]
export math!
; `calculate` has been exported
print calculate 10 ; 100
; but `pwr` wouldn't be available here...
```
#### Common Patterns
##### Safe Operations
```arturo
; coalesce operator
value: null
result: value ?? "default" ; use default if null
; safe variable checking
if set? 'x [ ; check if x exists
print x
]
counter: 0
; variable modification
'counter + 1 ; in-place increment
```
##### Loop Control
```arturo
; break from loop
done?: false
while [true][
if done? -> break
doSomething
]
; continue to next iteration
loop 1..10 'x [
if odd? x -> continue
print x
]
```
----
#### `alias`
assign symbol to given function
##### Arguments
- `symbol` (:string,:symbol,:symbolliteral,:block)
- `function` (:string,:word,:literal)
##### Options
- `infix` (:logical): use infix precedence
##### Returns
:nothing
##### Examples
```
addThem: function [x, y][
x + y
]
alias '--> 'addThem!
print --> 2 3
; 5
```
```
multiplyThem: function [x, y][ x * y ]
alias.infix {<=>} 'multiplyThem!
print 2 <=> 3
; 6
```
#### `any`
the ANY constant
##### Examples
```
```
#### `break`
break out of current block or loop
##### Returns
:nothing
##### Examples
```
loop 1..5 'x [
print ["x:" x]
if x=3 -> break
print "after check"
]
print "after loop"
; x: 1
; after check
; x: 2
; after check
; x: 3
; after loop
```
#### `call`
call function with given list of parameters
##### Arguments
- `function` (:string,:word,:literal,:pathliteral,:function,:method)
- `params` (:block)
##### Options
- `external` (:string): path to external library
- `expect` (:type): expect given return type
##### Returns
:any
##### Examples
```
multiply: function [x y][
x * y
]
call 'multiply [3 5] ; => 15
```
```
call $[x][x+2] [5] ; 7
```
```
; Calling external (C code) functions
; compile with:
; clang -c -w mylib.c
; clang -shared -o libmylib.dylib mylib.o
;
; NOTE:
; * If you're using GCC, just replace `clang` by `gcc`
; * If you're not on MacOS, replace your `dylib` by the right extension
; normally they can be `.so` or `.dll` in other Operational Systems.
; #include
;
; void sayHello(char* name){
; printf("Hello %s!\n", name);
; }
;
; int doubleNum(int num){
; return num * 2;
;}
; call an external function directly
call.external: "mylib" 'sayHello ["John"]
; map an external function to a native one
doubleNum: function [num][
ensure -> integer? num
call .external: "mylib"
.expect: :integer
'doubleNum @[num]
]
loop 1..3 'x [
print ["The double of" x "is" doubleNum x]
]
```
#### `case`
match given argument against different values and execute corresponding block
##### Arguments
- `argument` (:any)
- `matches` (:dictionary,:block)
##### Returns
:logical
##### Examples
```
x: 2
; the main block is always evaluated!
case x [
1 -> print "x is one!"
2 -> print "x is two!"
any -> print "x is none of the above"
]
; x is two!
```
```
key: "one"
case key [
"one" 1, ; we can also return
"two" 2 ; simple constant values directly
]
; => 2
```
```
case "hello" #[
hello: "hola"
adios: "goodbye"
]
; => "hola"
```
#### `coalesce` (alias: `??` - infix: true)
if first value is null or false, return second value; otherwise return the first one
##### Arguments
- `value` (:any)
- `alternative` (:any)
##### Returns
:any
##### Examples
```
; Note that 'attr returns null if it has no attribute
print coalesce attr "myAttr" "attr not found"
print (attr "myAttr") ?? "attr not found"
print (myData) ?? defaultData
```
#### `continue`
immediately continue with next iteration
##### Returns
:nothing
##### Examples
```
loop 1..5 'x [
print ["x:" x]
if x=3 -> continue
print "after check"
]
print "after loop"
; x: 1
; after check
; x: 2
; after check
; x: 3
; x: 4
; after check
; x: 5
; after check
; after loop
```
#### `discard`
discard given value, without pushing it onto the stack
##### Arguments
- `value` (:any)
##### Returns
:nothing
##### Examples
```
validInteger?: function [str][
not? throws? [
discard to :integer str
; we don't really need the value here -
; we just want to see if the operation throws an error
]
]
print validInteger? "123"
; true
```
#### `do`
evaluate and execute given code
##### Arguments
- `code` (:string,:block,:bytecode)
##### Options
- `times` (:integer): repeat block execution given number of times
##### Returns
:any
##### Examples
```
do "print 123" ; 123
```
```
do [
x: 3
print ["x =>" x] ; x => 3
]
```
```
print do "https://raw.githubusercontent.com/arturo-lang/arturo/master/examples/projecteuler/euler1.art"
; 233168
```
```
do.times: 3 [
print "Hello!"
]
; Hello!
; Hello!
; Hello!
```
```
; Importing modules
; let's say you have a 'module.art' with this code:
;
; pi: 3.14
;
; hello: $[name :string] [
; print ["Hello" name]
;]
do relative "module.art"
print pi
; 3.14
do [
hello "John Doe"
; Hello John Doe
]
; Note: always use imported functions inside a 'do block
; since they need to be evaluated beforehand.
; On the other hand, simple variables can be used without
; issues, as 'pi in this example
```
#### `dup` (alias: `<=` - infix: false)
duplicate the top of the stack and convert non-returning call to a do-return call
##### Arguments
- `value` (:any)
##### Returns
:any
##### Examples
```
; a label normally consumes its inputs
; and returns nothing
; using dup before a call, the non-returning function
; becomes a returning one
a: b: <= 3
print a ; 3
print b ; 3
```
#### `ensure`
assert given condition is true, or exit
##### Arguments
- `condition` (:block)
##### Options
- `that` (:string): prints a custom message when ensure fails
##### Returns
:nothing
##### Examples
```
num: input "give me a positive number"
ensure [num > 0]
print "good, the number is positive indeed. let's continue..."
```
```
ensure.that: "Wrong calc" -> 0 = 1 + 1
; >> Assertion | "Wrong calc": [0 = 1 + 1]
; error |
```
#### `export`
export given container children to current scope
##### Arguments
- `module` (:dictionary,:object,:module)
##### Options
- `all` (:logical): export everything, regardless of whether it's been marked as public (makes sense only for modules)
##### Returns
:nothing
##### Examples
```
greeting: module [
greet: method.public [user :string][
print ~"Hello, |user|!"
]
]
export greeting!
greet "Anonymous" ; Hello, Anonymous!
```
```
; You can't use private methods
greeting: module [
greet: method [user :string][
print ~"Bye, bye, |user|!"
]
]
export greeting!
greet "Anonymous"
; Cannot resolve requested value
;
; Identifier not found:
; greet
;
; ┃ File: example.art
; ┃ Line: 9
; ┃
; ┃ 7 ║ ]
; ┃ 8 ║
; ┃ 9 ║► export greeting!
; ┃ 10 ║
; ┃ 11 ║ greet "Anonymous"
;
; Hint: Perhaps you meant... greeting ?
; or... repeat ?
; or... greater? ?
```
```
; You can export private functions using the `.all` attribute
greeting: module [
greet: method [user :string][
print ~"Bye, bye, |user|!"
]
]
export.all greeting!
greet "Anonymous" ; Bye, bye, Anonymous!
```
#### `express`
convert given value to Arturo code
##### Arguments
- `value` (:any)
##### Options
- `pretty` (:logical): prettify generated code
- `unwrapped` (:logical): omit external block notation
- `safe` (:logical): use safe strings
##### Returns
:string
##### Examples
```
example: "Hello, world"
example ; => Hello, world
express example ; => "Hello, world"
```
```
d: #[name: "John"]
d\surname: "Doe"
express d
; => #[name: "John" surname: "Doe" ]
```
```
express.pretty #[name: "John" surname: "Doe"]
; => #[
; name: "John"
; surname: "Doe"
; ]
```
#### `function` (alias: `$` - infix: false)
create function with given arguments and body
##### Arguments
- `arguments` (:literal,:block)
- `body` (:block)
##### Options
- `import` (:block): import/embed given list of symbols from current environment
- `export` (:block): export given symbols to parent
- `memoize` (:logical): store results of function calls
- `inline` (:logical): execute function without scope
##### Returns
:function
##### Examples
```
f: function [x][ x + 2 ]
print f 10 ; 12
f: $[x][x+2]
print f 10 ; 12
```
```
multiply: function [x,y][
x * y
]
print multiply 3 5 ; 15
```
```
; forcing typed parameters
addThem: function [
x :integer
y :integer :floating
][
x + y
]
```
```
; adding complete documentation for user function
; using data comments within the body
addThem: function [
x :integer :floating
y :integer :floating
][
;; description: « takes two numbers and adds them up
;; options: [
;; mul: :integer « also multiply by given number
;; ]
;; returns: :integer :floating
;; example: {
;; addThem 10 20
;; addThem.mult:3 10 20
;; }
mult?: attr 'mult
switch not? null? mult?
-> return mult? * x + y
-> return x + y
]
info'addThem
; |--------------------------------------------------------------------------------
; | addThem :function 0x10EF0E528
; |--------------------------------------------------------------------------------
; | takes two numbers and adds them up
; |--------------------------------------------------------------------------------
; | usage addThem x :integer :floating
; | y :integer :floating
; |
; | options .mult :integer -> also multiply by given number
; |
; | returns :integer :floating
; |--------------------------------------------------------------------------------
```
```
publicF: function .export:['x] [z][
print ["z =>" z]
x: 5
]
publicF 10
; z => 10
print x
; 5
```
```
; memoization
fib: $[x].memoize[
switch x<2 -> 1
-> (fib x-1) + (fib x-2)
]
loop 1..25 [x][
print ["Fibonacci of" x "=" fib x]
]
```
#### `if`
perform action, if given condition is not false or null
##### Arguments
- `condition` (:any)
- `action` (:block,:bytecode)
##### Returns
:nothing
##### Examples
```
x: 2
if x=2 -> print "yes, that's right!"
; yes, that's right!
```
#### `import`
import given package
##### Arguments
- `package` (:string,:literal,:block)
##### Options
- `version` (:version): specify package version
- `min` (:logical): get any version >= the specified one
- `branch` (:string,:literal): use specific branch for repository url (default: main)
- `latest` (:logical): always check for the latest version available
- `lean` (:logical): return as a dictionary, instead of importing in main namespace
- `only` (:block): import only selected symbols, if available
- `verbose` (:logical): output extra information
##### Returns
:dictionary,:block,:nothing
##### Examples
```
import "dummy" ; import the package 'dummy'
do ::
print dummyFunc 10 ; and use it :)
```
```
import.version:0.0.3 "dummy" ; import a specific version
import.min.version:0.0.3 "dummy" ; import at least the give version;
; if there is a newer one, it will pull this one
```
```
import.latest "dummy" ; whether we already have the package or not
; always try to pull the latest version
```
```
import "https://github.com/arturo-lang/dummy-package"
; we may also import user repositories directly
import.branch:"main" "https://github.com/arturo-lang/dummy-package"
; even specifying the branch to pull
```
```
import "somefile.art" ; importing a local file is possible
import "somepackage" ; the same works if we have a folder that
; is actually structured like a package
```
```
d: import.lean "dummy" ; importing a package as a dictionary
; for better namespace isolation
do [
print d\dummyFunc 10 ; works fine :)
]
```
#### `let` (alias: `:` - infix: true)
set symbol to given value
##### Arguments
- `symbol` (:string,:word,:literal,:block)
- `value` (:any)
##### Returns
:nothing
##### Examples
```
let 'x 10 ; x: 10
print x ; 10
```
```
; variable assignments
"a": 2 ; a: 2
{_someValue}: 3
print var {_someValue} ; 3
```
```
; multiple assignments
[a b]: [1 2]
print a ; 1
print b ; 2
```
```
; multiple assignment to single value
[a b c]: 5
print a ; 5
print b ; 5
print c ; 5
```
```
; unpacking slices and multiple assignment
[a [b] d c]: [1 2 3 4 5]
print a ; 1
print b ; [2 3]
print c ; 4
print d ; 5
```
```
; tuple unpacking
divmod: function [x,y][
@[x/y x%y]
]
[d,m]: divmod 10 3 ; d: 3, m: 1
```
#### `method`
create type method with given arguments and body
##### Arguments
- `arguments` (:literal,:block)
- `body` (:block)
##### Options
- `distinct` (:logical): shouldn't be treated as a magic method
- `public` (:logical): make method public (relevant only in modules!)
##### Returns
:method
##### Examples
```
define :cat [
init: method [nick :string age :integer][
this\nick: join.with: " " @["Mr." capitalize nick]
this\age: age
]
; Function overloading
add: method [years :integer][
this\age: age + this\age
]
meow: method [][
print [~"|this\nick|:" "'meow!'"]
]
]
a: to :cat [15 15]
; >> Assertion | [is? :string nick]
; error |
snowflake: to :cat ["snowflake" 3]
snowflake\meow
; Mr. Snowflake: 'meow!'
; use `do -> snowflake\meow` instead
; when running the above code from a file
add snowflake 3
snowflake\age
; => 6
snowflake\add 3
print snowflake\age
; => 9
; use `do [snowflake\add 3]` instead
; when running the above code from a file
```
#### `module`
create new module with given contents
##### Arguments
- `contents` (:dictionary,:block)
##### Options
- `with` (:block): use given initialization parameters
##### Returns
:module
##### Examples
```
ui: module [
namedRule: method [title :string width :integer][
title: ~" |title| "
pad.center.with: '=' title width
]
section: method.public [title :string content :string width :integer][
~{
|\namedRule title width|
|content|
|\namedRule title width|
}
]
]
export ui!
print section "Hello" "World" 50
; ===================== Hello ======================
; World
; ===================== Hello ======================
print set? 'ui ; true
print set? 'namedRule ; false
print set? 'section ; true
```
```
ui: [
init: method [symbol :char][
\symbol: symbol
]
namedRule: method [title :string width :integer][
title: ~" |title| "
pad.center.with: \symbol title width
]
section: method.public [title :string content :string width :integer][
~{
|\namedRule title width|
|content|
|\namedRule title width|
}
]
]
export module.with: ['~'] ui!
print section "Example" "This is an example" 40
; ~~~~~~~~~~~~~~~ Example ~~~~~~~~~~~~~~~~
; This is an example
; ~~~~~~~~~~~~~~~ Example ~~~~~~~~~~~~~~~~
```
#### `new`
create new value by cloning given one
##### Arguments
- `value` (:any)
##### Returns
:any
##### Examples
```
c: "Hello"
d: new c ; make a copy of the older string
; changing one string in-place
; will change only the string in question
'd ++ "World"
print d ; HelloWorld
print c ; Hello
```
#### `null`
the NULL constant
##### Examples
```
```
#### `parse`
parse given string as an Arturo value
##### Arguments
- `code` (:string,:block)
##### Options
- `data` (:logical): parse input as Arturo data block (unstable!)
##### Returns
:any
##### Examples
```
parse "123" ; 123 (:integer)
parse "3.14" ; 3.14 (:floating)
parse "true" ; true (:logical)
parse "[1 2 3]" ; [1 2 3] (:block)
```
#### `return`
return given value from current function
##### Arguments
- `value` (:any)
##### Returns
:nothing
##### Examples
```
f: function [x][
loop 1..x 'y [
if y=5 [ return y*2 ]
]
return x*2
]
print f 3 ; 6
print f 6 ; 10
```
#### `set?`
check if given variable is defined
##### Arguments
- `symbol` (:string,:literal)
##### Returns
:logical
##### Examples
```
boom: 12
print set? 'boom ; true
print set? 'zoom ; false
```
#### `switch` (alias: `?` - infix: true)
if condition is not false or null perform given action, otherwise perform alternative action
##### Arguments
- `condition` (:any)
- `action` (:block)
- `alternative` (:block)
##### Returns
:any
##### Examples
```
x: 2
switch x=2 -> print "yes, that's right!"
-> print "nope, that's not right!"
; yes, that's right!
```
#### `unless`
perform action, if given condition is false or null
##### Arguments
- `condition` (:any)
- `action` (:block,:bytecode)
##### Returns
:nothing
##### Examples
```
x: 2
unless x=1 -> print "yep, x is not 1!"
; yep, x is not 1!
```
#### `unset`
undefine given symbol, if already defined
##### Arguments
- `symbol` (:string,:literal)
##### Returns
:nothing
##### Examples
```
a: 2
print a
; 2
unset 'a
print a
; will throw an error
```
#### `unstack`
pop top N values from stack
##### Arguments
- `number` (:integer)
##### Returns
:any
##### Examples
```
1 2 3
a: unstack 1 ; a: 3
1 2 3
b: unstack 2 ; b: [3 2]
```
```
; You can also discard the values using `discard`
1 2 3
discard unstack 1 ; popped 3 from the stack
```
#### `until`
execute action until the given condition is not false or null
##### Arguments
- `action` (:block,:bytecode)
- `condition` (:block,:bytecode)
##### Returns
:nothing
##### Examples
```
i: 0
until [
print ["i =>" i]
i: i + 1
][i = 10]
; i => 0
; i => 1
; i => 2
; i => 3
; i => 4
; i => 5
; i => 6
; i => 7
; i => 8
; i => 9
```
#### `using`
execute block with a pre-defined given `this` value
##### Arguments
- `this` (:any)
- `body` (:block)
##### Returns
:nothing
##### Examples
```
p: #[name: "John" surname: "Doe" age: 38]
using p [
print \name ; access our
print \age ; fields directly
\surname: "Smith" ; or change their value
]
; John
; 38
```
#### `var`
get symbol value by given name
##### Arguments
- `symbol` (:string,:word,:literal,:pathliteral)
##### Returns
:any
##### Examples
```
a: 2
print var 'a ; 2
f: function [x][x+2]
print f 10 ; 12
g: var 'f
print g 10 ; 12
```
#### `when`
check conditions one by one and execute corresponding block accordingly
##### Arguments
- `conditions` (:block)
##### Options
- `any` (:logical): check all conditions, without breaking, regardless of success
- `has` (:any): prepend given value to each of the conditions
##### Returns
:logical
##### Examples
```
; the main block is always evaluated!
when [
prime? 4 -> print "yes, 4 is prime - wait, what?!"
prime? 5 -> print "yes, 5 is prime"
prime? 7 -> print "yes, 6 is prime"
true -> print "none of the above was true"
]
; yes, 5 is prime
```
```
when.any [
prime? 4 -> print "yes, 4 is prime - wait, what?!"
prime? 5 -> print "yes, 5 is prime"
prime? 7 -> print "yes, 7 is prime"
]
; yes, 5 is prime
; yes, 7 is prime
```
```
x: 2
when.has: x [
[=0] -> print "x is zero!"
[<1] -> print "x is less than 1"
[<4] -> print "x is less than 4"
true -> print "x is >= 4"
]
; x is less than 4
```
```
f: function [x][
print ["called F with:" x]
return odd? x
]
; short-circuiting:
; conditions are not evaluated unless needed
when [
[f 10]-> print "F 10"
[f 11]-> print "F 11"
[f 12]-> print "F 12"
]
; called F with: 10
; called F with: 11
; F 11
```
#### `while`
execute action while the given condition is is not false or null
##### Arguments
- `condition` (:null,:block,:bytecode)
- `action` (:block,:bytecode)
##### Returns
:nothing
##### Examples
```
i: 0
while [i<10][
print ["i =>" i]
i: i + 1
]
; i => 0
; i => 1
; i => 2
; i => 3
; i => 4
; i => 5
; i => 6
; i => 7
; i => 8
; i => 9
while ø [
print "something" ; infinitely
]
```
#### `window`
the NULL constant
##### Examples
```
```
#### `with`
create closure-style block by embedding given words
##### Arguments
- `embed` (:string,:word,:literal,:dictionary,:block)
- `body` (:block)
##### Returns
:block
##### Examples
```
f: function [x][
with [x][
"the multiple of" x "is" 2*x
]
]
multiplier: f 10
print multiplier
; the multiple of 10 is 20
```
### Crypto
Cryptography- or encoding-related functions
----
# Crypto
The Crypto module provides basic cryptographic functions and encoding utilities. It includes support for hashing, CRC calculation, and various encoding/decoding operations.
#### Key Concepts
- Hash calculation (MD5, SHA1)
- CRC32 polynomial calculation
- Base64 encoding/decoding
- URL encoding/decoding
- Character encoding conversion
#### Basic Usage
##### Hashing
```arturo
; calculate MD5 digest (default)
print digest "hello world" ; 5eb63bbbe01eeed093cb22bb8f5acdc3
; using SHA1
print digest.sha "hello world" ; 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
; CRC32 calculation
print crc "hello world" ; 0d4a1185
```
> [!IMPORTANT] The Crypto module provides basic cryptographic functions. For serious cryptographic needs, consider using specialized libraries.
##### Base64 Encoding/Decoding
```arturo
; encoding
encoded: encode "Hello World!" ; SGVsbG8gV29ybGQh
print encoded
; decoding
decoded: decode encoded ; Hello World!
print decoded
```
##### URL Encoding/Decoding
```arturo
; encode URL
url: "https://example.com/path with spaces?q=test+1"
encoded: encode.url url
print encoded
; https%3A%2F%2Fexample.com%2Fpath%20with%20spaces%3Fq%3Dtest%2B1
; decode URL
decoded: decode.url encoded
print decoded
; https://example.com/path with spaces?q=test+1
; encode only spaces
spaceEncoded: encode.url.spaces "hello world"
; hello%20world
; encode everything including slashes
fullEncoded: encode.url.slashes "/path/to/resource"
; %2Fpath%2Fto%2Fresource
```
##### Character Encoding Conversion
```arturo
; convert between character encodings
text: "Hello världen" ; text with non-ASCII characters
converted: encode .from:"UTF-8" .to: "ISO-8859-1" text
```
#### Common Patterns
##### Password Hashing
```arturo
hashPassword: function [password][
; combine password with... salt and hash
salt: "somesalt"
combined: join @[password salt]
digest.sha combined
]
; usage
password: "mypassword123"
hashed: hashPassword password
print ["Hashed password:" hashed]
; Hashed password: 81ea5410f1cb78c81cbb6dbd678782f80f9150f5
```
##### Safe URL Building
```arturo
buildUrl: function [baseUrl parameters][
query: map parameters [key value][
key ++ "=" ++ encode.url value
]
join.with:"?" @[
baseUrl
join.with:"&" query
]
]
; usage
url: buildUrl "https://api.example.com/search" #[
"q": "search term"
"lang": "en-US"
"page": "1"
]
print url
; https://api.example.com/search?q=search%20term&lang=en-US&page=1
```
> [!TIP] When working with URLs, always encode user inputs to prevent injection attacks and ensure proper URL formatting.
----
#### `crc`
calculate the CRC32 polynomial of given string
##### Arguments
- `value` (:string,:literal,:pathliteral)
##### Returns
:string,:nothing
##### Examples
```
print crc "The quick brown fox jumps over the lazy dog"
; 414FA339
```
#### `decode`
decode given value (default: base-64)
##### Arguments
- `value` (:string,:literal,:pathliteral)
##### Options
- `url` (:logical): decode URL based on RFC3986
##### Returns
:string,:nothing
##### Examples
```
print decode "TnVtcXVhbSBmdWdpZW5zIHJlc3BleGVyaXM="
; Numquam fugiens respexeris
```
```
print decode.url "http%3A%2F%2Ffoo+bar%2F"
; http://foo bar/
```
#### `digest`
get digest for given value (default: MD5)
##### Arguments
- `value` (:string,:literal,:pathliteral)
##### Options
- `sha` (:logical): use SHA1
##### Returns
:string,:nothing
##### Examples
```
print digest "Hello world"
; 3e25960a79dbc69b674cd4ec67a72c62
```
```
print digest.sha "Hello world"
; 7b502c3a1f48c8609ae212cdfb639dee39673f5e
```
#### `encode`
encode given value (default: base-64)
##### Arguments
- `value` (:string,:literal,:pathliteral)
##### Options
- `url` (:logical): encode URL based on RFC3986
- `spaces` (:logical): also encode spaces
- `slashes` (:logical): also encode slashes
- `from` (:string): source character encoding (default: CP1252)
- `to` (:string): target character encoding (default: UTF-8)
##### Returns
:string,:nothing
##### Examples
```
print encode "Numquam fugiens respexeris"
; TnVtcXVhbSBmdWdpZW5zIHJlc3BleGVyaXM=
```
```
print encode.url "http://foo bar/"
; http%3A%2F%2Ffoo+bar%2F
```
#### `hash`
get hash for given value
##### Arguments
- `value` (:any)
##### Options
- `string` (:logical): get as a string
##### Returns
:integer,:string
##### Examples
```
print hash "hello" ; 613153351
print hash [1 2 3] ; 645676735036410
print hash 123 ; 123
a: [1 2 3]
b: [1 2 3]
print (hash a)=(hash b) ; true
```
### Databases
Functions for creating and query databases
----
The Databases module offers straightforward database operations with built-in SQLite support. It provides a simple yet powerful interface for managing databases directly from your Arturo code.
#### Key Concepts
- Native SQLite support
- Simple database connection management
- Parametrized queries
- Query results as blocks of rows
#### Basic Usage
##### Opening & Closing Connections
```arturo
; create/open database
db: open.sqlite "mydata.db"
; when done
close db
```
##### Simple Queries
```arturo
query db {!sql
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
)
}
query db "INSERT INTO users (name, age) VALUES ('John', 25)"
; get results
users: query db "SELECT * FROM users"
print users ; [1 John 25]
```
> [!TIP] If you are using a text editor that supports this syntax (e.g. VSCode), using `!sql` in front of `{..}`-enclosed blocks will enable proper SQL highlighting. Totally non-compulsory, but still very handy!
##### Parametrized Queries
```arturo
; safer way to insert data with parameters
age: 30
name: "Alice"
query.with: @[name age] db "INSERT INTO users (name, age) VALUES (?,?)"
; parametrized select
minAge: 20
results: query.with: @[minAge] db "SELECT * FROM users WHERE age > ?"
loop results 'user ->
print ["User:" user\1 "Age:" user\2]
; User: Alice Age: 30
```
> [!IMPORTANT] Always use parametrized queries when dealing with user input to prevent SQL injection attacks.
#### Common Patterns
##### Transaction Handling
```arturo
; do multiple operations
query db [
"INSERT INTO users (name, age) VALUES ('Bob', 35)"
"UPDATE users SET age = 31 WHERE name = 'Alice'"
]
> [!NOTE] This method of performing multiple operations is the equivalent of using `BEGIN TRANSACTION` blocks in SQL, although in much more... practical and Arturo-friendly way! ;-)
```
##### Getting Last Insert ID
```arturo
; insert and get the ID
query.id.with: ["Carol" 28] db {!sql
INSERT INTO users (name, age) VALUES (?,?)
}
```
----
#### `close`
close given database
##### Arguments
- `database` (:database)
##### Returns
:nothing
##### Examples
```
db: open "my.db" ; opens an SQLite database named 'my.db'
print query db "SELECT * FROM users"
close db ; and close it
```
#### `open`
opens a new database connection and returns database
##### Arguments
- `name` (:string)
##### Options
- `sqlite` (:logical): support for SQLite databases
- `mysql` (:logical): support for MySQL databases
##### Returns
:database
##### Examples
```
db: open "my.db" ; opens an SQLite database named 'my.db'
```
#### `query`
execute command or block of commands in given database and get returned rows
##### Arguments
- `database` (:database)
- `commands` (:string,:block)
##### Options
- `id` (:logical): return last INSERT id
- `with` (:block): use arguments for parametrized statement
##### Returns
:null,:integer,:block
##### Examples
```
db: open "my.db" ; opens an SQLite database named 'my.db'
; perform a simple query
print query db "SELECT * FROM users"
; perform an INSERT query and get back the record's ID
username: "johndoe"
lastInsertId: query.id db ~{!sql INSERT INTO users (name) VALUES ('|username|')}
; perform a safe query with given parameters
print query db .with: ["johndoe"] {!sql SELECT * FROM users WHERE name = ?}
```
#### `store`
create or load a persistent store on disk
##### Arguments
- `path` (:string,:literal)
##### Options
- `deferred` (:logical): save to disk only on program termination
- `global` (:logical): save as global store
- `native` (:logical): force native/Arturo format
- `json` (:logical): force Json format
- `db` (:logical): force database/SQlite format
##### Returns
:range
##### Examples
```
; create a new store with the name `mystore`
; it will be automatically live-stored in a file in the same folder
; using the native Arturo format
data: store "mystore"
; store some data
data\name: "John"
data\surname: "Doe"
data\age: 36
; and let's retrieve our data
data
; => [name:"John" surname:"Doe" age:36]
```
```
; create a new "global" configuration store
; that will be saved automatically in ~/.arturo/stores
globalStore: store.global "configuration"
; we are now ready to add or retrieve some persistent data!
```
```
; create a new JSON store with the name `mystore`
; it will be automatically live-stored in a file in the same folder
; with the name `mystore.json`
data: store.json "mystore"
; store some data
da\people: []
; data can be as complicated as in any normal dictionary
da\people: da\people ++ #[name: "John" surname: "Doe"]
; check some specific store value
da\people\0\name
; => "John"
```
```
; create a new deferred store with the name `mystore`
; it will be automatically saved in a file in the same folder
; using the native Arturo format
defStore: store.deferred "mystore"
; let's save some data
defStore\name: "John"
defStore\surname: "Doe"
; and print it
print defStore
; [name:John surname:Doe]
; in this case, all data is available at any given moment
; but will not be saved to disk for each and every operation;
; instead, it will be saved in its totality just before
; the program terminates!
```
### Dates
Functions for manipulating dates
----
The Dates module provides functionality for working with dates and times. Dates are handled as dictionary-like values, making it easy to access and work with individual components.
#### Key Concepts
- Dates are dictionary-like values with accessible components
- Easy date arithmetic with `before` and `after`
- Various time unit granularities (from nanoseconds to years)
- Convenient date checks (weekdays, past/future, leaps)
#### Basic Usage
##### Creating Dates
```arturo
; get current date/time
current: now
print current ; 2024-12-13T14:30:45+01:00
; accessing components
print current\year ; 2024
print current\month ; 12
print current\day] ; 13
print current\hour] ; 14
print current\minute] ; 30
print current\second] ; 45
```
##### Date Arithmetic
```arturo
date: now
; moving forward in time
nextWeek: after.days:7 date
nextMonth: after.months:1 date
nextYear: after.years:1 date
; moving backward in time
lastWeek: before.days:7 date
lastMonth: before.months:1 date
lastYear: before.years:1 date
; combine different units
meeting: after .hours:2 .minutes:30 date
```
##### Date Checks
```arturo
today: now
; time comparison
future? after.days:1 today ; => true
past? before.days:1 today ; => true
today? today ; => true
; weekday checks
monday? today ; well... depends
friday? today ; on the
sunday? today ; actual date! :)
; year checks
print leap? 2024 ; true
print leap? today\year ; true (if still 2024!)
```
#### Common Patterns
##### Working with Time Intervals
```arturo
start: now
deadline: after.days:10 start
; calculate intermediate dates
loop 0..10 'day [
checkpoint: after.days:day start
print ["Day" day ":" checkpoint\day]
]
; Day 0 : 13
; Day 1 : 14
; Day 2 : 15
; Day 3 : 16
; Day 4 : 17
; Day 5 : 18
; Day 6 : 19
; Day 7 : 20
; Day 8 : 21
; Day 9 : 22
; Day 10 : 23
```
##### Date Formatting and Parsing
Converting dates to strings and parsing strings into dates is done using format patterns:
```arturo
dt: now
; format date to string
to :string .format:"yyyy-MM-dd HH:mm:ss" dt
; => 2024-12-13 16:55:38
; parse string to date
meeting: to :date .format:"yyyy-MM-dd" "2024-03-15"
; 2024-03-15T00:00:00+01:00
```
> [!NOTE] When parsing dates from strings, make sure your format pattern matches exactly the structure of your input string.
###### Format Patterns
| Pattern | Description | Example |
|---------|-------------|---------|
| d | Day of month (1 or 2 digits) | 1, 21 |
| dd | Day of month (2 digits) | 01, 21 |
| ddd | Abbreviated weekday | Sat, Mon |
| dddd | Full weekday | Saturday, Monday |
| M | Month (1 or 2 digits) | 9, 12 |
| MM | Month (2 digits) | 09, 12 |
| MMM | Abbreviated month | Sep, Dec |
| MMMM | Full month | September, December |
| yy | Year (2 digits) | 12 |
| yyyy | Year (4+ digits, padded) | 2012, 0024 |
| H | Hour 0-23 (1 or 2 digits) | 5, 17 |
| HH | Hour 0-23 (2 digits) | 05, 17 |
| h | Hour 1-12 (1 or 2 digits) | 5, 11 |
| hh | Hour 1-12 (2 digits) | 05, 11 |
| m | Minute (1 or 2 digits) | 1, 30 |
| mm | Minute (2 digits) | 01, 30 |
| s | Second (1 or 2 digits) | 1, 45 |
| ss | Second (2 digits) | 01, 45 |
| tt | AM/PM indicator | AM, PM |
| z | UTC offset (basic) | +7, -5 |
| zzz | UTC offset with minutes | +07:00, -05:00 |
| fff | Milliseconds | 001 |
Common Format Examples:
```arturo
date: now
; different format examples
print to :string .format:"MM/dd/yyyy" date ; 12/13/2024
print to :string .format:"d MMM yyyy" date ; 13 Dec 2024
print to :string .format:"MMMM d, yyyy" date ; December 13, 2024
print to :string .format:"HH:mm:ss.fff" date ; 14:30:45.123
print to :string .format:"h:mm tt" date ; 2:30 PM
```
> [!TIP] For common use cases, you might want to create helper functions with your preferred format patterns:
> ```arturo
> formatDate: function [dt][
> to :string .format:"yyyy-MM-dd" dt
> ]
> ```
----
#### `after`
get date after given one using interval
##### Arguments
- `date` (:literal,:pathliteral,:date)
##### Options
- `nanoseconds` (:integer): add given number of nanoseconds
- `milliseconds` (:integer): add given number of milliseconds
- `seconds` (:integer): add given number of seconds
- `minutes` (:integer): add given number of minutes
- `hours` (:integer): add given number of hours
- `days` (:integer): add given number of days
- `weeks` (:integer): add given number of weeks
- `months` (:integer): add given number of months
- `years` (:integer): add given number of years
##### Returns
:date
##### Examples
```
print now
; 2021-03-22T11:25:30+01:00
print after.weeks:2 now
; 2021-04-05T11:25:42+02:00
```
#### `before`
get date before given one using interval
##### Arguments
- `date` (:literal,:pathliteral,:date)
##### Options
- `nanoseconds` (:integer): subtract given number of nanoseconds
- `milliseconds` (:integer): subtract given number of milliseconds
- `seconds` (:integer): subtract given number of seconds
- `minutes` (:integer): subtract given number of minutes
- `hours` (:integer): subtract given number of hours
- `days` (:integer): subtract given number of days
- `weeks` (:integer): subtract given number of weeks
- `months` (:integer): subtract given number of months
- `years` (:integer): subtract given number of years
##### Returns
:date
##### Examples
```
print now
; 2021-03-22T11:27:00+01:00
print before.weeks:2 now
; 2021-03-08T11:27:14+01:00
print before.years:1 now
; 2020-03-22T11:27:23+01:00
```
#### `friday?`
check if given date is a Friday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print friday? now ; false
```
#### `future?`
check if given date is in the future
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
futureDate: after.weeks:2 now
print future? now ; false
print future? futureDate ; true
```
#### `leap?`
check if given year is a leap year
##### Arguments
- `year` (:integer,:date)
##### Returns
:logical
##### Examples
```
print leap? now ; false
print map 2019..2021 => leap?
; false true false
```
#### `monday?`
check if given date is a Monday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print sunday? now ; false
```
#### `now`
get date/time now
##### Returns
:date
##### Examples
```
print now ; 2020-10-23T14:16:13+02:00
time: now
inspect time
; [ :date
; hour : 14 :integer
; minute : 16 :integer
; second : 55 :integer
; nanosecond : 82373000 :integer
; day : 23 :integer
; Day : Friday :string
; month : 10 :integer
; Month : October :string
; year : 2020 :integer
; utc : -7200 :integer
; ]
print now\year ; 2020
```
#### `past?`
check if given date is in the past
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
pastDate: before.weeks:2 now
futureDate: after.weeks:1 now
print past? futureDate ; false
print past? pastDate ; true
print past? now ; true ("now" has already become past...)
```
#### `saturday?`
check if given date is a Saturday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print saturday? now ; false
```
#### `sunday?`
check if given date is a Sunday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print sunday? now ; false
```
#### `thursday?`
check if given date is a Thursday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print thursday? now ; false
```
#### `today?`
check if given date is today
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print today? now ; true
print today? after.hours: 24 now ; false
```
#### `tuesday?`
check if given date is a Tuesday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print tuesday? now ; true
```
#### `wednesday?`
check if given date is a Wednesday
##### Arguments
- `date` (:date)
##### Returns
:logical
##### Examples
```
print wednesday? now ; false
```
### Exceptions
Exceptions and error handling
----
The Exceptions module provides error handling functionality and predefined error types. It enables robust error management and graceful failure handling in your applications.
> [!IMPORTANT] The error handling system in Arturo is still evolving. The functionality described in this module should be considered transitional and may change in future versions as the error handling system matures.
#### Key Concepts
- Error throwing and catching
- Predefined error types
- Error assertions
- Error testing capabilities
#### Basic Usage
##### Error Handling
```arturo
; basic try-catch pattern
if error? err: <= try [
; some risky operation
result: 10 / 0
][
print "something went wrong!"
print err
]
```
##### Throwing Errors
```arturo
; throw generic error
throw "Something went wrong"
; throw with specific error type
throw.as:valueError "Invalid input provided"
; throw with custom message
throw "User not found: %id=123"
```
##### Error Testing
```arturo
; test if operation throws an error
if throws? [
10 / 0
] -> print "Operation has thrown an error"
```
#### Predefined Error Types
```arturo
; available error types
nameError ; when symbol not found
typeError ; when type mismatch
valueError ; when value is invalid
arithmeticError ; for math operations
indexError ; for invalid indices
syntaxError ; for parsing issues
systemError ; for OS-related errors
runtimeError ; for general runtime issues
```
----
#### `arithmeticError`
an arithmetic error
##### Examples
```
```
#### `assertionError`
an assertion error
##### Examples
```
```
#### `conversionError`
a conversion error
##### Examples
```
```
#### `indexError`
an index error
##### Examples
```
```
#### `libraryError`
a library error
##### Examples
```
```
#### `nameError`
a name error
##### Examples
```
```
#### `packageError`
a package error
##### Examples
```
```
#### `runtimeError`
a generic runtime error
##### Examples
```
```
#### `syntaxError`
a syntax error
##### Examples
```
```
#### `systemError`
a system error
##### Examples
```
```
#### `throw`
throw an error with given message
##### Arguments
- `message` (:string,:errorkind)
##### Options
- `as` (:errorkind): consider the error as one of given subtype
##### Returns
:nothing
##### Examples
```
err: try -> throw "Page not found"
err\kind
; => Generic Error
err\message
; => Page not found
; or you can alternatively use custom errorKind
pageNotFound: to :errorKind "404: Page not Found"
err: try -> throw.as: pageNotFound "Seems that the page does not exist"
err\kind
; => 404: Page not Found
err\message
; => Seems that the page does not exist
; Or even use the :errorKind's label as the message itself
err: try -> throw pageNotFound
err\kind
; => 404: Page not Found
err\message
; => 404: Page not Found
```
#### `throws?`
perform action, and return true if errors were thrown
##### Arguments
- `action` (:block,:bytecode)
##### Returns
:logical
##### Examples
```
throws? [
1 + 2
]
; => false
throws? -> 1/0
; => true
```
#### `try`
perform action and catch possible errors
##### Arguments
- `action` (:block,:bytecode)
##### Options
- `verbose` (:logical): print all error messages as usual
##### Returns
:null,:error
##### Examples
```
err: try [
; let's try something dangerous
print 10 / 0
]
type err
; => :error
; Tips: mixing errors and returned values
f: $[][ throw "some error" ]
g: $[][ return "hi" ]
(genericError = err: <= try -> val: f)?
-> print err
-> print val
; => Generic Error: some error
(genericError = err: <= try -> val: g)?
-> print err
-> print val
; => hi
```
#### `typeError`
a type error
##### Examples
```
```
#### `uiError`
a UI error
##### Examples
```
```
#### `valueError`
a value error
##### Examples
```
```
#### `vmError`
a VM error
##### Examples
```
```
### Files
Functions for reading, writing, and manipulating files
----
The Files module provides powerful functions for file operations, with intelligent handling of different data sources and formats. Its flexibility allows seamless interaction with local files, URLs, and direct content.
#### Key Concepts
- Smart source detection (URLs, files, direct content)
- Support for multiple file formats (JSON, CSV, XML, etc.)
- File system operations (copy, move, delete)
- Directory handling and path manipulation
- Automatic format detection and parsing
#### Basic Usage
##### Reading Content
`read` intelligently handles different types of sources:
```arturo
; reading from different sources
content: read "hello.txt" ; read local file
content: read "https://api.com/data" ; download from URL
content: read "some direct content" ; use string directly
; force treating string as file path
content: read.file "some text.txt" ; error if file doesn't exist
```
##### Writing Content
```arturo
; basic writing
write "some content" "output.txt"
; using the infix operator
"some content" >> "output.txt"
; append to existing file
write.append "more content" "output.txt"
```
##### Format Parsing & Generation
```arturo
; reading & parsing JSON from any source
data: read.json "data.json" ; from local file
data: read.json "https://api.com/data" ; from URL
data: read.json "{\"key\":\"value\"}" ; from string
; writing data as JSON
write.json data "output.json" ; to file
jsonStr: write.json data ø ; to string
; other supported formats
content: read.csv "data.csv" ; parse CSV
content: read.xml "data.xml" ; parse XML
content: read.html "page.html" ; parse HTML
content: read.markdown "doc.md" ; convert to HTML
content: read.toml "config.toml" ; parse TOML
```
> [!TIP] The format functions (like `.json`, `.csv`) work the same way regardless of source - local file, URL, or direct content.
##### File System Operations
```arturo
; check existence
print exists? "file.txt" ; => true/false
print file? "file.txt" ; => true/false
print directory? "folder" ; => true/false
; file operations
copy "source.txt" "dest.txt"
move "old.txt" "new.txt"
delete "unwanted.txt"
; directory operations
copy.directory "src" "dest"
delete.directory "olddir"
```
#### Common Patterns
##### Reading Files Safely
```arturo
; handle potential missing files
if exists? "config.json" [
settings: read.json "config.json"
]
; force file reading (error if not found)
if throws? [
data: read.file "important.txt"
]-> print "File not found!"
```
##### Bulk Operations
```arturo
; list files in directory
files: list "documents"
files: list.recursive "documents" ; include subdirectories
; process multiple files
loop files 'file [
if "txt" = extract.extension file ->
print ["Found text file:" file]
]
```
----
#### `copy`
copy file at path to given destination
##### Arguments
- `file` (:string)
- `destination` (:string)
##### Options
- `directory` (:logical): path is a directory
##### Returns
:nothing
##### Examples
```
copy "testscript.art" normalize.tilde "~/Desktop/testscript.art"
; copied file
```
```
copy "testfolder" normalize.tilde "~/Desktop/testfolder"
; copied whole folder
```
#### `delete`
delete file at given path
##### Arguments
- `file` (:string)
##### Options
- `directory` (:logical): path is a directory
##### Returns
:nothing
##### Examples
```
delete "testscript.art"
; file deleted
```
#### `directory?`
check if given path exists and corresponds to a directory
##### Arguments
- `path` (:string)
##### Returns
:logical
##### Examples
```
if directory? "src" [
print "directory exists!"
]
```
#### `exists?`
check if file/directory at given path exists
##### Arguments
- `path` (:string)
##### Returns
:logical
##### Examples
```
if exists? "somefile.txt" [
print "path exists!"
]
```
#### `file?`
check if given path exists and corresponds to a file
##### Arguments
- `path` (:string)
##### Returns
:logical
##### Examples
```
if file? "somefile.txt" [
print "file exists!"
]
```
#### `hidden?`
check if file/folder at given path is hidden
##### Arguments
- `file` (:string)
##### Returns
:logical
##### Examples
```
hidden? "README.md" ; => false
hidden? ".git" ; => true
```
#### `move`
move file at path to given destination
##### Arguments
- `file` (:string)
- `destination` (:string)
##### Options
- `directory` (:logical): path is a directory
##### Returns
:nothing
##### Examples
```
move "testscript.art" normalize.tilde "~/Desktop/testscript.art"
; moved file
```
```
move "testfolder" normalize.tilde "~/Desktop/testfolder"
; moved whole folder
```
#### `permissions`
check permissions of given file
##### Arguments
- `file` (:string)
##### Options
- `set` (:dictionary): set using given file permissions
##### Returns
:null,:dictionary
##### Examples
```
inspect permissions "bin/arturo"
; [ :dictionary
; user : [ :dictionary
; read : true :boolean
; write : true :boolean
; execute : true :boolean
; ]
; group : [ :dictionary
; read : true :boolean
; write : false :boolean
; execute : true :boolean
; ]
; others : [ :dictionary
; read : true :boolean
; write : false :boolean
; execute : true :boolean
; ]
; ]
```
```
permissions.set:#[others:#[write:true]] "bin/arturo"
; gave write permission to 'others'
```
#### `read` (alias: `<<` - infix: false)
read file from given path
##### Arguments
- `file` (:string)
##### Options
- `lines` (:logical): read file lines into block
- `json` (:logical): read Json into value
- `csv` (:logical): read CSV file into a block of rows
- `delimiter` (:char): read CSV file with a specific delimiter
- `withHeaders` (:logical): read CSV headers
- `html` (:logical): read HTML into node dictionary
- `xml` (:logical): read XML into node dictionary
- `markdown` (:logical): read Markdown and convert to HTML
- `toml` (:logical): read TOML into value
- `bytecode` (:logical): read file as Arturo bytecode
- `binary` (:logical): read as binary
- `file` (:logical): read as file (throws an error if not valid)
##### Returns
:string,:binary,:block
##### Examples
```
; reading a simple local file
str: read "somefile.txt"
```
```
; also works with remote urls
page: read "http://www.somewebsite.com/page.html"
```
```
; we can also "read" JSON data as an object
data: read.json "mydata.json"
```
```
; or even convert Markdown to HTML on-the-fly
html: read.markdown "## Hello" ; "Hello
"
```
#### `rename`
rename file at path using given new path name
##### Arguments
- `file` (:string)
- `name` (:string)
##### Options
- `directory` (:logical): path is a directory
##### Returns
:nothing
##### Examples
```
rename "README.md" "READIT.md"
; file renamed
```
#### `symlink`
create symbolic link of file to given destination
##### Arguments
- `file` (:string)
- `destination` (:string)
##### Options
- `hard` (:logical): create a hard link
##### Returns
:nothing
##### Examples
```
symlink relative "arturo/README.md"
"/Users/drkameleon/Desktop/gotoREADME.md"
; creates a symbolic link to our readme file
; in our desktop
```
```
symlink.hard relative "arturo/README.md"
"/Users/drkameleon/Desktop/gotoREADME.md"
; hard-links (effectively copies) our readme file
; to our desktop
```
#### `symlink?`
check if given path exists and corresponds to a symlink
##### Arguments
- `path` (:string)
##### Returns
:logical
##### Examples
```
if symlink? "somefile" [
print "symlink exists!"
]
```
#### `timestamp`
get file timestamps
##### Arguments
- `file` (:string)
##### Returns
:null,:dictionary
##### Examples
```
timestamp "README.md"
; => [created:2022-09-21T12:35:04+02:00 accessed:2022-09-21T12:35:04+02:00 modified:2022-09-21T12:35:04+02:00]
timestamp "some-file-that-does-not-exist.txt"
; => null
```
#### `unzip`
unzip given archive to destination
##### Arguments
- `destination` (:string)
- `original` (:string)
##### Returns
:nothing
##### Examples
```
unzip "folder" "archive.zip"
```
#### `volume`
get file size for given path
##### Arguments
- `file` (:string)
##### Returns
:quantity
##### Examples
```
volume "README.md"
; => 13704B
; (size in bytes)
```
#### `write` (alias: `>>` - infix: true)
write content to file at given path
##### Arguments
- `content` (:any)
- `file` (:null,:string)
##### Options
- `append` (:logical): append to given file
- `directory` (:logical): create directory at path
- `json` (:logical): write value as Json
- `compact` (:logical): produce compact, non-prettified Json code
- `binary` (:logical): write as binary
##### Returns
:nothing
##### Examples
```
; write some string data to given file path
write "Hello world!" "somefile.txt"
```
```
; we can also write any type of data as JSON
write.json myData "data.json"
```
```
; append to an existing file
write.append "Yes, Hello again!" "somefile.txt"
```
#### `zip`
zip given files to file at destination
##### Arguments
- `destination` (:string)
- `files` (:block)
##### Returns
:nothing
##### Examples
```
zip "dest.zip" ["file1.txt" "img.png"]
```
### Io
Functions and utilities for using the terminal and standard input/output
----
The Io module provides functionality for terminal input/output operations, cursor manipulation, and console formatting. It offers both basic printing capabilities and advanced terminal controls.
#### Key Concepts
- Terminal input/output operations
- Colored text output
- Cursor manipulation
- Terminal information retrieval
- Multi-line input handling
#### Basic Usage
##### Output Operations
```arturo
; basic printing (with newline)
print "Hello world"
print ["Multiple" "values" "joined"] ; Multiple values joined
; printing without newline
prints "Loading..."
print "." ; Loading....
; print items on separate lines
print.lines ["one" "two" "three"]
; one
; two
; three
```
##### Input Operations
```arturo
; basic input with prompt
name: input "What's your name? "
; single character input
ch: input ø ; returns single character without echo
; REPL-style input with history
cmd: input.repl ">> "
```
##### Colored Output
```arturo
; using color function
print color #red "Error!"
print color.bold #blue "Important"
print color.underline #green "Success"
; keep color active
prints color.keep #red "This "
prints "and this "
print "all red"
; combining styles
print color.bold.underline #blue "Highlighted"
```
##### Cursor Control
```arturo
; hide/show cursor
cursor false ; hide cursor
cursor true ; show cursor
; move cursor to specific position
goto 10 5 ; move to x:10, y:5
print "X"
goto ø 10 ; move to current x, line 10
print "Y"
goto 5 ø ; move to column 5, current line
print "Z"
; clear screen
clear
```
#### Common Patterns
##### Progress Indicators
```arturo
; simple progress indicator
loop 1..5 'i [
prints "."
pause 500 ; pause for 500ms
]
print ""
; animated spinner
spinner: ["⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏"]
loop 1..20 'i [
prints "\b" ; go back one character
prints spinner\[i % size spinner]
pause 100
]
print ""
```
##### Interactive Menus
```arturo
clearMenu: function [][
clear
cursor false
]
showMenu: function [options][
selected: 0
while [true][
clearMenu
loop options 'opt ->
print [" " opt]
goto 0 selected
prints "→ "
key: input ø
case key [
'w' -> if selected > 0 [dec 'selected]
's' -> if selected < (size options)-1 [inc 'selected]
'\r' [
cursor true
return selected
]
]
]
]
; usage
choice: showMenu ["Start" "Settings" "Exit"]
print ["Selection:" choice]
```
##### Status Updates
```arturo
; colorful status messages
printStatus: function [kind message][
case kind [
"info" -> print [color #blue "ℹ" message]
"success" -> print [color #green "✓" message]
"warning" -> print [color #yellow "⚠" message]
"error" -> print [color #red "✗" message]
]
]
; usage
printStatus "info" "Loading configuration..."
printStatus "success" "Configuration loaded"
printStatus "warning" "Disk space low"
printStatus "error" "Connection failed"
```
> [!TIP] When working with colors, remember that not all terminals support all color features. You might want to check terminal capabilities first.
##### Terminal Information
```arturo
; get terminal information
print ["Width:" terminal\width]
print ["Height:" terminal\height]
```
----
#### `clear`
clear terminal
##### Returns
:nothing
##### Examples
```
clear ; (clears the screen)
```
#### `color`
get colored version of given string
##### Arguments
- `color` (:color)
- `string` (:string)
##### Options
- `bold` (:logical): bold font
- `underline` (:logical): show underlined
- `keep` (:logical): don't reset color at string end
##### Returns
:string
##### Examples
```
print color #green "Hello!" ; Hello! (in green)
print color #red.bold "Some text" ; Some text (in red/bold)
```
#### `cursor`
turn cursor visibility on/off
##### Arguments
- `visible` (:logical)
##### Returns
:nothing
##### Examples
```
cursor false ; (hides the cursor)
cursor true ; (shows the cursor)
```
#### `goto`
move cursor to given coordinates
##### Arguments
- `x` (:null,:integer)
- `y` (:null,:integer)
##### Returns
:nothing
##### Examples
```
goto 10 15 ; (move cursor to column 10, line 15)
goto 10 ø ; (move cursor to column 10, same line)
```
#### `input`
print prompt and get user input. If the prompt is ø, get a single character
##### Arguments
- `prompt` (:null,:string)
##### Options
- `repl` (:logical): get input as if in a REPL
- `history` (:string): set path for saving history
- `complete` (:block): use given array for auto-completions
- `hint` (:dictionary): use given dictionary for typing hints
##### Returns
:char,:string
##### Examples
```
name: input "What is your name? "
; (user enters his name: Bob)
print ["Hello" name "!"]
; Hello Bob!
```
```
; creating a simple REPL
while [true][
inp: input.repl
.history: "myhistory.txt"
.complete:["Hello there", "Hello world!"]
.hint:#[he: "perhaps you want to say hello?"]
"## "
print ["got:" inp]
]
; will show a REPL-like interface, with arrow navigation enabled
; show previous entries with arrow-up, store entries in
; a recoverable file and also use autocompletions and hints
; based on give reference
```
```
character: input ø
; (User types a key, for example "A")
print character
; A
```
#### `print`
print given value to screen with newline
##### Arguments
- `value` (:any)
##### Options
- `lines` (:logical): print each value in block in a new line
##### Returns
:nothing
##### Examples
```
print "Hello world!" ; Hello world!
```
#### `prints`
print given value to screen
##### Arguments
- `value` (:any)
##### Returns
:nothing
##### Examples
```
prints "Hello "
prints "world"
print "!"
; Hello world!
```
#### `terminal`
get info about terminal
##### Returns
:dictionary
##### Examples
```
print terminal ; [width:107 height:34]
terminal\width ; => 107
```
### Iterators
Functional helpers for easier block iteration (loops, filtering, mapping, etc)
----
The Iterators module provides functional programming tools for working with collections. From simple loops to complex transformations, it offers a consistent way to process collections with elegant, expressive code.
#### Key Concepts
- Collection iteration with various strategies
- Functional transformations (map, filter, fold)
- Collection analysis (every?, some?, enumerate)
- Consistent behavior across all collection types
- Support for block-based predicate conditions
#### Basic Usage
##### Looping Through Collections
```arturo
numbers: [1 2 3 4 5]
; basic iteration
loop numbers 'n ->
print ["Number:" n]
; Number: 1
; Number: 2
; Number: 3
; Number: 4
; Number: 5
; with index
loop.with:'i numbers 'n ->
print ["Item" i ":" n]
; Item 0 : 1
; Item 1 : 2
; Item 2 : 3
; Item 3 : 4
; Item 4 : 5
; dictionary iteration
user: #[name: "John" age: 30]
loop user [key value]->
print [key "->" value]
; name -> John
; age -> 30
```
> [!NOTE] Iterator functions work uniformly with all collection types:
> - Blocks: `loop [1 2 3] 'x [...]`
> - Dictionaries: `loop #[a:1 b:2] [k v] [...]`
> - Strings: `loop "hello" 'c [...]`
> - Ranges: `loop 1..5 'x [...]`
> - Numbers: `loop 3 'i [...]` (equivalent to `1..3`)
##### Transforming Collections
```arturo
numbers: 1..5
; transform each element
doubled: map numbers 'x -> x * 2
print doubled ; 2 4 6 8 10
; using the => shorthand for simple transformations
squared: map numbers => [& ^ 2]
print squared ; 1 4 9 16 25
; chaining transformations
result: map numbers 'x ->
(to :string x) ++ "!"
; ["1!" "2!" "3!" "4!" "5!"]
```
##### Filtering Elements
```arturo
numbers: 1..10
; keep elements matching condition
evens: select numbers 'n -> even? n
print evens ; 2 4 6 8 10
; remove elements matching condition
noEvens: filter numbers 'n -> even? n
print noEvens ; 1 3 5 7 9
; shorthand for simple predicates
odds: select numbers => odd?
print odds ; 1 3 5 7 9
```
#### Common Patterns
##### Testing Collections
```arturo
numbers: [2 4 6 8]
; check if all elements match
every? numbers => even? ; => true
; check if any element matches
some? numbers => [& > 10] ; => false
; count matching elements
enumerate numbers 'x -> x > 5 ; => 3
```
##### Collecting and Grouping
```arturo
data: ["apple" "banana" "apricot" "cherry"]
; group by first letter
byLetter: gather data 'word -> first word
print byLetter
; [a:[apple apricot] b:[banana] c:[cherry]]
; collect elements while condition is true
ascending: collect [1 2 3 2 4 5] 'x ->
x < 4
print ascending ; 1 2 3 2
```
##### Advanced Transformations
```arturo
; fold (reduce) a collection
sum: fold 1..5 [acc val]->
acc + val
; 15
; with seed value
sumFrom100: fold.seed:100 1..5 [acc val]->
acc + val
; 115
; arrange (sort) with custom predicate
users: @[
#[name: "John" score: 42]
#[name: "Alice" score: 28]
#[name: "Bob" score: 35]
]
sorted: arrange users 'user -> user\score
print.lines map sorted 'u -> u\name
; Alice
; Bob
; John
```
> [!TIP] The arrow operator (`=>`) is particularly useful with iterators for creating concise, readable code. For example: `map nums => [& * 2]` instead of `map nums 'x -> x * 2`
##### Working with Nested Data
```arturo
; cluster similar items
temps: [22 22 23 25 25 25 24 24]
clusters: cluster temps 'temp -> temp
; [[22 22] [23] [25 25 25] [24 24]]
; chunk using predicate
data: 1..6
chunks: chunk data => [& < 3]
[1 2] [3 4 5 6]
; finding matches with collect
numbers: [1 2 3 2 1 4 5 4]
duplicates: collect.after numbers 'x ->
not? contains? first.n:3 numbers x
; 4 5 4
```
##### Pipe-based Transformations
```arturo
; Sample data: list of orders
orders: @[
#[id: 1 items: ["book" "pen"] total: 25.50 status: "pending"]
#[id: 2 items: ["laptop"] total: 999.99 status: "completed"]
#[id: 3 items: ["phone" "case" "charger"] total: 699.00 status: "pending"]
#[id: 4 items: ["tablet"] total: 299.99 status: "cancelled"]
]
; Process orders using pipes for better readability
result: orders
| select 'order -> order\status = "pending" ; get pending orders
| map 'order -> #[ ; transform structure
orderId: order\id
itemCount: size order\items
cost: order\total
]
| arrange 'order -> order\cost ; sort by cost
| map 'order -> ~{
Order #|order\orderId|: |order\itemCount|
items @ $|order\cost|
}
print.lines result
; Order #1: 2
; items @ $25.5
; Order #3: 3
; items @ $699.0
```
> [!TIP] Using pipes (|) can make complex data transformations more readable by breaking them into clear, sequential steps.
----
#### `arrange`
sort items in collection using value returned from given action, in ascending order
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `descending` (:logical): sort in descending order
##### Returns
:block,:nothing
##### Examples
```
arrange ["the" "brown" "fox" "jumped" "over" "the" "lazy" "dog"] => size
; => ["the" "fox" "the" "dog" "over" "lazy" "brown" "jumped"]
```
```
arrange.descending 1..10 'x -> size factors.prime x
; => [8 4 6 9 10 2 3 5 7 1]
```
#### `chunk`
chunk together consecutive items in collection that abide by given condition
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `value` (:logical): also include condition values
##### Returns
:block,:nothing
##### Examples
```
chunk [1 1 2 2 3 22 3 5 5 7 9 2 5] => even?
; => [[1 1] [2 2] [3] [22] [3 5 5 7 9] [2] [5]]
```
```
chunk.value [1 1 2 2 3 22 3 5 5 7 9 2 5] 'x [ odd? x ]
; => [[true [1 1]] [false [2 2]] [true [3]] [false [22]] [true [3 5 5 7 9]] [false [2]] [true [5]]]
```
```
chunk.with:'i ["one" "two" "three" "four" "five" "six"] [] -> i < 4
; => [["one" "two" "three" "four"] ["five" "six"]]
```
```
chunk [1 7 5 4 3 6 8 2] [x y]-> even? x+y
; => [[1 7] [5 4 3 6] [8 2]]
```
#### `cluster`
group together items in collection that abide by given condition
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `value` (:logical): also include condition values
##### Returns
:block,:nothing
##### Examples
```
cluster 1..10 => odd?
; => [[1 3 5 7 9] [2 4 6 8 10]]
cluster 1..10 'x -> prime? x
; => [[1 4 6 8 9 10] [2 3 5 7]]
```
```
cluster 1..10 [x y] -> 10 < x+y
; => [[1 2 3 4] [5 6 7 8 9 10]]
```
```
cluster.value 1..10 'x -> prime? x
; => [[false [1 4 6 8 9 10]] [true [2 3 5 7]]]
```
```
#.raw flatten.once cluster.value 1..10 'x [
(prime? x)? -> "prime"
-> "composite"
]
; => [composite:[1 4 6 8 9 10] prime:[2 3 5 7]]
```
```
cluster.with: 'i ["one" "two" "three" "four" "five" "six"] [] -> even? i
; => [["one" "three" "five"] ["two" "four" "six"]]
```
#### `collect`
collect items from given collection condition while is true
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `after` (:logical): start collecting after given condition becomes true
##### Returns
:block,:nothing
##### Examples
```
collect [1 3 5 4 6 7] => odd?
; => [1 3 5]
collect [1 2 3 4 3 2 1 2 3] 'x -> x < 4
; => [1 2 3]
```
```
collect.after [4 6 3 5 2 0 1] => odd?
; => [3 5 2 0 1]
collect.after 1..10 'x -> x > 4
; => [5 6 7 8 9 10]
```
#### `enumerate`
calculate the number of given collection's items that satisfy condition
##### Arguments
- `collection` (:integer,:string,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
##### Returns
:integer
##### Examples
```
enumerate 1..10000000 => odd?
; => 5000000
```
```
enumerate.with:'i ["one" "two" "three" "four"] 'x -> i < 3
; => 3
```
#### `every?`
check if every item in collection satisfies given condition
##### Arguments
- `collection` (:integer,:string,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
##### Returns
:logical
##### Examples
```
if every? [2 4 6 8] 'x [even? x]
-> print "every number is an even integer"
; every number is an even integer
```
```
print every? 1..10 'x -> x < 11
; true
```
```
print every? 1..10 [x y]-> 20 > x+y
; true
```
```
print every? [2 3 5 7 11 14] 'x [prime? x]
; false
```
```
print every?.with:'i ["one" "two" "three"] 'x -> 4 > (size x)-i
; true
```
#### `filter`
get collection's items by omitting those that do not satisfy given condition
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `first` (:logical,:integer): only filter first element/s
- `last` (:logical,:integer): only filter last element/s
##### Returns
:block,:nothing,:any
##### Examples
```
print filter 1..10 [x][
even? x
]
; 1 3 5 7 9
```
```
arr: 1..10
filter 'arr 'x -> even? x
print arr
; 1 3 5 7 9
```
```
filter [1 1 2 3 5 8 13 21] [x y]-> odd? x+y
; => [1 1 13 21]
```
```
filter.with:'i ["zero" "one" "two" "three" "four" "five"] []-> even? i
; => ["one" "three" "five"]
```
```
filter.first 1..10 => odd?
=> [2 3 4 5 6 7 8 9 10]
filter.first:3 1..10 => odd?
=> [2 4 6 7 8 9 10]
```
```
filter.last 1..10 => odd?
=> [1 2 3 4 5 6 7 8 10]
filter.last:3 1..10 => odd?
=> [1 2 3 4 6 8 10]
```
#### `fold`
reduce collection from the left using given action, returning the final accumulator
##### Arguments
- `collection` (:integer,:string,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `seed` (:any): use specific seed value
- `right` (:logical): perform right folding
##### Returns
:null,:block,:nothing
##### Examples
```
fold 1..10 [x,y]-> x + y
; => 55 (1+2+3+4..)
fold 1..10 .seed:1 [x,y][ x * y ]
; => 3628800 (10!)
```
```
fold 1..3 [x,y]-> x - y
; => -6
fold.right 1..3 [x,y]-> x - y
; => 2
```
```
fold.seed:"0" to [:string] 1..5 [x,y] ->
"(" ++ x ++ "+" ++ y ++ ")"
; => (((((0+1)+2)+3)+4)+5)
fold.right.seed:"0" to [:string] 1..5 [x,y] ->
"(" ++ x ++ "+" ++ y ++ ")"
; => (1+(2+(3+(4+(5+0)))))
```
```
fold 1..10 [x y z] [
print [x y z]
x + z - y
]
; 0 1 2
; 1 3 4
; 2 5 6
; 3 7 8
; 4 9 10
; => 5
```
```
fold.with:'i 1..5 [x y][
print [i x y]
i * x+y
]
; 0 0 1
; 1 0 2
; 2 2 3
; 3 10 4
; 4 42 5
; => 188
```
#### `gather`
group items in collection by value returned from given action, returning a dictionary
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
##### Returns
:dictionary,:nothing
##### Examples
```
print gather [1 2 3 4 5 6] 'x [
x % 2
]
; [1:[1 3 5] 0:[2 4 6]]
print gather ["New York" "Washington" "Minnesota" "Montana" "New Hampshire" "New Mexico"] 'x [
size x
]
; [8:[New York] 10:[Washington New Mexico] 9:[Minnesota] 7:[Montana] 13:[New Hampshire]]
```
```
gather.with:'i ["one" "two" "three" "four"] 'x -> i%2
; [0:[one three] 1:[two four]]
```
#### `loop`
iterate through collection, executing given block for each item
##### Arguments
- `collection` (:integer,:string,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `forever` (:logical): cycle through collection infinitely
##### Returns
:nothing
##### Examples
```
loop [1 2 3] 'x [
print x
]
; 1
; 2
; 3
```
```
loop 1..3 [x][
print ["x =>" x]
]
; x => 1
; x => 2
; x => 3
```
```
loop [A a B b C c] [x y][
print [x "=>" y]
]
; A => a
; B => b
; C => c
```
```
user: #[
name: "John"
surname: "Doe"
]
loop user [k v][
print [k "=>" v]
]
; name => John
; surname => Doe
```
```
loop.with:'i ["zero" "one" "two"] 'x [
print ["item at:" i "=>" x]
]
; 0 => zero
; 1 => one
; 2 => two
```
```
loop.forever [1 2 3] => print
; 1 2 3 1 2 3 1 2 3 ...
```
#### `map`
map items in collection to values returned from given action
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
##### Returns
:block,:nothing
##### Examples
```
print map 1..5 [x][
2*x
]
; 2 4 6 8 10
```
```
arr: 1..5
map 'arr 'x -> 2*x
print arr
; 2 4 6 8 10
```
```
map 1..6 [x y][
print ["mapping" x "and" y "->" x+y]
x+y
]
; mapping 1 and 2 -> 3
; mapping 3 and 4 -> 7
; mapping 5 and 6 -> 11
; => [3 7 11]
```
```
map.with:'i ["one" "two" "three" "four"] 'x [
(even? i)? -> upper x -> x
]
; => ["ONE" "two" "THREE" "four"]
```
#### `maximum`
get item in collection with maximum value returned from given action
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `value` (:logical): also include predicate values
##### Returns
:block,:nothing
##### Examples
```
maximum 1..10 'x -> size factors.prime x
; => 8
; 8 has the maximum number of
; prime factors: 2, 2, 2 (3)
```
```
maximum.value 1..10 'x -> size factors.prime x
; => [8 3]
```
#### `minimum`
get item in collection with minimum value returned from given action
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `action` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `value` (:logical): also include predicate values
##### Returns
:block,:nothing
##### Examples
```
minimum [4 17 20] 'x -> size factors.prime x
; => 17
; 17 has the minimum number of
; prime factors: 17 (1)
```
```
minimum.value [4 17 20] 'x -> size factors.prime x
; => [17 1]
```
#### `select`
get items in collection that satisfy given condition
##### Arguments
- `collection` (:integer,:string,:literal,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
- `first` (:logical,:integer): only return first element/s
- `last` (:logical,:integer): only return last element/s
- `n` (:integer): only return n-th element
##### Returns
:block,:nothing,:any
##### Examples
```
print select 1..10 [x][
even? x
]
; 2 4 6 8 10
```
```
arr: 1..10
select 'arr 'x -> even? x
print arr
; 2 4 6 8 10
```
```
select [1 1 2 3 5 8 13 21] [x y]-> odd? x+y
; => [2 3 5 8]
```
```
select.with:'i ["zero" "one" "two" "three" "four" "five"] []-> even? i
; => ["zero" "two" "four"]
```
```
select.first 1..10 => odd?
=> [1]
select.first:3 1..10 => odd?
=> [1 3 5]
```
```
select.last 1..10 => odd?
=> [9]
select.last:3 1..10 => odd?
=> [5 7 9]
```
#### `some?`
check if any of collection's items satisfy given condition
##### Arguments
- `collection` (:integer,:string,:dictionary,:object,:inline,:block,:range)
- `params` (:null,:literal,:block)
- `condition` (:block,:bytecode)
##### Options
- `with` (:literal): use given index
##### Returns
:logical
##### Examples
```
if some? [1 3 5 6 7] 'x [even? x]
-> print "at least one number is an even integer"
; at least one number is an even integer
```
```
print some? 1..10 'x -> x > 9
; true
```
```
print some? [4 6 8 10] 'x [prime? x]
; false
```
```
print some? 1..10 [x y]-> 15 < x+y
; true
```
```
print some? [2 4 6 9] 'x [prime? x]
; true
```
```
print some?.with:'i ["three" "two" "one" "four" "five"] 'x -> i >= size x
; true
```
### Logic
Logical operations (AND, OR, XOR, etc), helpers and constants for boolean values
----
The Logic module provides boolean operations and logical value manipulation. Beyond traditional true/false operations, it includes support for ternary logic with `maybe` and optimized evaluation strategies.
#### Key Concepts
- Three-valued logic: `true`, `false`, and `maybe`
- Standard boolean operations (AND, OR, XOR, etc.)
- Short-circuit evaluation for improved performance
#### Basic Usage
##### Basic Logical Values
```arturo
print true? true ; true
print false? false ; true
print true? maybe ; maybe
```
##### Logical Operations
```arturo
and? true true ; true
or? true false ; true
xor? true true ; false
; with maybe
and? true maybe ; maybe
or? true maybe ; true
```
##### Short-Circuit Evaluation
```arturo
; if first block is false,
; the second one won't be evaluated
if and? [1=2][print "never runs"] ->
print "not true"
; if first block is true,
; the second one won't be evaluated
if or? [1=1][print "never runs"] ->
print "was true"
; was true
```
> [!NOTE] Using blocks with `and?` and `or?` enables short-circuit evaluation. In a few words: blocks are only evaluated when needed.
#### Common Patterns
##### Testing Multiple Conditions
```arturo
conditions: @[true false true true]
; check if all conditions are true
all? conditions ; => false
; check if any condition is true
any? conditions ; => true
```
> [!TIP] Combining conditions in blocks with `and?` and `or?` (or more than one condition inside `all?` or `any?` blocks) is more efficient than checking them separately!
##### Advanced Logical Operations
```arturo
a: true
b: false
print nand? a b ; true = not (a and b)
print nor? a b ; false = not (a or b)
print xnor? a b ; false = not (a xor b)
```
----
#### `all?`
check if all values in given block are true
##### Arguments
- `conditions` (:block)
##### Returns
:logical
##### Examples
```
if all? @[2>1 "DONE"=upper "done" true]
-> print "yes, all are true"
; yes, all are true
```
```
print all? @[true false true true]
; false
```
```
all? []
; => true
```
#### `and?` (alias: `∧` - infix: true)
return the logical AND for the given values
##### Arguments
- `valueA` (:logical,:block)
- `valueB` (:logical,:block)
##### Returns
:logical
##### Examples
```
x: 2
y: 5
if and? x=2 y>5 [
print "yep, that's correct!"]
]
; yep, that's correct!
```
#### `any?`
check if any of the values in given block is true
##### Arguments
- `conditions` (:block)
##### Returns
:logical
##### Examples
```
if any? @[false 3=4 2>1]
-> print "yes, one (or more) of the values is true"
; yes, one (or more) of the values is true
```
```
print any? @[false false false]
; false
```
#### `false`
the FALSE logical constant
##### Examples
```
```
#### `false?`
returns true if given value is false; otherwise, it returns false
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print false? 1 = 2 ; true
print false? 1 <> 2 ; false
print false? odd? 2 ; true
print false? [1 2 3] ; false
```
#### `maybe`
the MAYBE logical constant
##### Examples
```
```
#### `nand?` (alias: `⊼` - infix: true)
return the logical NAND for the given values
##### Arguments
- `valueA` (:logical,:block)
- `valueB` (:logical,:block)
##### Returns
:logical
##### Examples
```
x: 2
y: 3
switch nand? x=2 y=3
-> print "yep, that's correct!"
-> print "nope, that's not correct
; nope, that's not correct
```
#### `nor?`
return the logical NOR for the given values
##### Arguments
- `valueA` (:logical,:block)
- `valueB` (:logical,:block)
##### Returns
:logical
##### Examples
```
x: 2
y: 3
switch nor? x>2 y=3
-> print "yep, that's correct!"
-> print "nope, that's not correct
; nope, that's not correct
```
#### `not?` (alias: `¬` - infix: false)
return the logical complement of the given value
##### Arguments
- `value` (:logical,:block)
##### Returns
:logical
##### Examples
```
ready: false
if not? ready [
print "we're still not ready!"
]
; we're still not ready!
```
#### `or?` (alias: `∨` - infix: true)
return the logical OR for the given values
##### Arguments
- `valueA` (:logical,:block)
- `valueB` (:logical,:block)
##### Returns
:logical
##### Examples
```
x: 2
y: 4
if or? x=2 y>5 [
print "yep, that's correct!"
]
; yep, that's correct!
```
#### `true`
the TRUE logical constant
##### Examples
```
```
#### `true?`
returns true if given value is true; otherwise, it returns false
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print true? 1 = 2 ; false
print true? 1 <> 2 ; true
print true? even? 2 ; true
print true? [1 2 3] ; false
```
#### `xnor?`
return the logical XNOR for the given values
##### Arguments
- `valueA` (:logical,:block)
- `valueB` (:logical,:block)
##### Returns
:logical
##### Examples
```
x: 2
y: 3
switch xnor? x=2 y=3
-> print "yep, that's correct!"
-> print "nope, that's not correct
; yep, that's correct!
```
#### `xor?` (alias: `⊻` - infix: true)
return the logical XOR for the given values
##### Arguments
- `valueA` (:logical,:block)
- `valueB` (:logical,:block)
##### Returns
:logical
##### Examples
```
x: 2
y: 3
switch xor? x=2 y=3
-> print "yep, that's correct!"
-> print "nope, that's not correct
; nope, that's not correct
```
### Net
Network-related functions and helpers
----
The Net module provides functionality for network operations, including HTTP requests, file downloads, mail sending, and web serving capabilities.
#### Key Concepts
- HTTP requests (GET, POST, PUT, PATCH, DELETE)
- File downloads
- Email sending
- Web server functionality
- Browser integration
#### Basic Usage
##### HTTP Requests
```arturo
; basic GET request
response: request "https://api.example.com/data" ø
print response\body
; POST with JSON data
data: #[name: "John" age: 30]
response: request.post.json "https://api.example.com/users" data
; custom headers
response: request "https://api.example.com/data" .headers: #[
authorization: "Bearer abc123"
accept: "application/json"
] ø
; other HTTP methods
response: request.put "https://api.example.com/users/1" data
response: request.patch "https://api.example.com/users/1" data
response: request.delete "https://api.example.com/users/1" ø
```
> [!IMPORTANT] When making HTTP requests, always handle potential network errors and timeouts appropriately.
##### File Downloads
```arturo
; download file
download "https://example.com/file.pdf"
; download with custom filename
download.as:"local.pdf" "https://example.com/file.pdf"
```
##### Sending Emails
```arturo
; basic email
mail "recipient@email.com" "Hello!" "This is the message body"
; with custom SMTP configuration
mail .using: #[
server: "smtp.company.com"
port: 587
username: "sender@company.com"
password: "secret"
] "recipient@email.com" "Meeting reminder" "Don't forget our meeting tomorrow!"
```
##### Opening URLs
```arturo
; open URL in default browser
browse "https://arturo-lang.io"
```
#### Common Patterns
##### Simple REST API Client
```arturo
define :apiClient [
init: constructor [baseUrl token]
headers: method [][
#[
authorization: join ["Bearer " \token]
content-type: "application/json"
]
]
get: method.distinct [endpoint][
request join @[\baseUrl endpoint] .headers: \headers ø
]
post: function [endpoint data][
request.post.json join @[\baseUrl endpoint] .headers: \headers data
]
]
; create a new API Client
apiClient: to :apiClient ["https://api.example.com" ""]!
; usage
response: apiClient\get "/users"
newUser: apiClient\post "/users" #[name: "John" email: "john@email.com"]
```
##### Mini Web Server
```arturo
; create a simple web server
; create a simple web server
serve.verbose [
GET "/" [
render.template {
Welcome!
The time is: <||= now ||>
}
]
GET "/post/(?.+)" $[id][
render.template {
This is post with id: <||= id ||>
}
]
GET "/styles/(?.+)" $[file][
; serve static files
read file
]
]
```
> [!TIP] The serve function can also open Chrome in app mode with `.chrome` for a more app-like experience.
----
#### `browse`
open given URL with default browser
##### Arguments
- `url` (:string)
##### Returns
:nothing
##### Examples
```
browse "https://arturo-lang.io"
; opens Arturo's official website in a new browser window
```
#### `download`
download file from url to disk
##### Arguments
- `url` (:string)
##### Options
- `as` (:string): set target file
##### Returns
:nothing
##### Examples
```
download "https://github.com/arturo-lang/arturo/raw/master/logo.png"
; (downloads file as "logo.png")
```
```
download.as:"arturoLogo.png"
"https://github.com/arturo-lang/arturo/raw/master/logo.png"
; (downloads file with a different name)
```
#### `mail`
send mail using given subject and message to selected recipient
##### Arguments
- `recipient` (:string)
- `subject` (:string)
- `message` (:string)
##### Options
- `using` (:dictionary): use given configuration
##### Returns
:nothing
##### Examples
```
mail .using: #[
server: "mymailserver.com"
username: "myusername"
password: "mypass123"
]
"recipient@somemail.com" "Hello from Arturo" "Arturo rocks!"
```
#### `request`
perform HTTP request to url with given data and get response
##### Arguments
- `url` (:string)
- `data` (:null,:string,:dictionary)
##### Options
- `get` (:logical): perform a GET request (default)
- `post` (:logical): perform a POST request
- `patch` (:logical): perform a PATCH request
- `put` (:logical): perform a PUT request
- `delete` (:logical): perform a DELETE request
- `json` (:logical): send data as Json
- `headers` (:dictionary): send custom HTTP headers
- `agent` (:string): use given user agent
- `timeout` (:integer): set a timeout
- `proxy` (:string): use given proxy url
- `certificate` (:string): use SSL certificate at given path
- `raw` (:logical): return raw response without processing
##### Returns
:null,:dictionary
##### Examples
```
print request "https://httpbin.org/get" #[some:"arg" another: 123]
; [version:1.1 body:{
; "args": {
; "another": "123",
; "some": "arg"
; },
; "headers": {
; "Content-Length": "0",
; "Host": "httpbin.org",
; "User-Agent": "Arturo HTTP Client / 0.9.75",
; "X-Amzn-Trace-Id": "Root=1-608fd4b2-6b8a34291cc2fbd17a678b0f"
; },
; "origin": "92.59.209.80",
; "url": "https://httpbin.org/get?some=arg&another=123"
; } headers:[server:gunicorn/19.9.0 content-length:341 access-control-allow-credentials:true content-type:application/json date:2021-05-03T10:47:14+02:00 access-control-allow-origin:* connection:keep-alive] status:200]
```
```
r: request "https://httpbin.org/get" #[some:"arg" another: 123]
body: read.json r\body
inspect body\headers
; [ :dictionary
; Content-Length : 0 :string
; Host : httpbin.org :string
; User-Agent : Arturo HTTP Client / 0.9.75 :string
; X-Amzn-Trace-Id : Root=1-608fd5f3-7e47203117863c111a3aef3b :string
; ]
```
```
print (request "https://httpbin.org/get" #[]) \ 'status
; 200
```
```
print request.post "https://httpbin.org/post" #[some:"arg" another: 123]
; ...same as above...
```
#### `serve`
start web server using given routes
##### Arguments
- `routes` (:function,:block)
##### Options
- `port` (:integer): use given port. Default: 18966
- `silent` (:logical): don't print info log
- `chrome` (:logical): open in Chrome windows as an app
##### Returns
:nothing
##### Examples
```
serve .port:18966 [
GET "/" [ "This is the homepage" ]
GET "/post" $[id][
send.html ~"This is the post with id: |id|"
]
POST "/getinfo" $[id][
send.json write.json ø #[
i: id
msg: "This is some info"
]
]
]
; run the app and go to localhost:18966 - that was it!
; the app will respond to GET requests to "/" or "/post?id=..."
; and also POST requests to "/getinfo" with an 'id' parameter
```
```
serve $[req][
inspect req
;[ :dictionary
; method : GET :string
; path : / :string
; uri : / :string
; body : :string
; query : [ :dictionary
; ]
; headers : [ :dictionary
; ...
; ]
; we have to return either a string
; or a dictionary like:
#[
body: "..."
status: 200
headers: #[
;...
]
]
]
```
### Numbers
Functions and helpers for more advanced math-related operations
----
The Numbers module extends Arturo's numerical capabilities beyond basic arithmetic, offering advanced mathematical functions, number theory operations, and trigonometric calculations.
#### Key Concepts
- Full support for complex numbers and mathematical constants
- Advanced mathematical functions (logarithms, exponentials)
- Comprehensive trigonometric operations
- Number theory functions (factors, primes)
- Random number generation
#### Basic Usage
##### Mathematical Constants
```arturo
pi ; => 3.141592653589793
epsilon ; => 2.718281828459045
tau ; => 6.283185307179586
```
##### Mathematical Functions
```arturo
; exponentials and logarithms
exp 1 ; => 2.718281828459045
ln 10 ; => 2.302585092994046
log 100 10 ; => 2.0
; rounding & absolute values
ceil 3.14 ; => 4
floor 3.14 ; => 3
round 3.14 ; => 3.0
abs neg 42 ; => 42
```
##### Complex Numbers
```arturo
z: to :complex [3 4] ; 3.0+4.0i
print abs z ; 5.0
print angle z ; 0.927295218001612
w: to :complex [1 1] ; 1.0+1.0i
print z * w ; -1.0+7.0i
```
> [!NOTE] Complex numbers are created using `to` with a block containing the real and imaginary parts.
##### Number Theory
```arturo
; prime numbers
prime? 17 ; => true
; factors
factors 12 ; => [1 2 3 4 6 12]
factors.prime 12 ; => [2 2 3]
; GCD and LCM
print gcd [24 36] ; 12
print lcm [4 6] ; 12
```
#### Common Patterns
##### Working with Angles
```arturo
ang: pi/6 ; 30 degrees
; trigonometric functions
print round.to: 2 sin ang ; 0.5
print cos ang ; 0.866025403784439
print tan ang ; 0.577350269189626
; inverse functions
print asin 0.5 ; 0.523598775598299
```
##### Random Number Generation
```arturo
; random integer in range (inclusive)
print random 1 6 ; dice roll...
; random floating-point numbers
print random 0.0 1.0
```
----
#### `abs`
get the absolute value for given integer
##### Arguments
- `value` (:integer,:floating,:complex,:rational)
##### Returns
:integer,:floating
##### Examples
```
print abs 6 ; 6
print abs 6-7 ; 1
```
```
abs to :complex @[pi 1]
; => 3.296908309475615
```
#### `acos`
calculate the inverse cosine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print acos 0 ; 1.570796326794897
print acos 0.3 ; 1.266103672779499
print acos 1.0 ; 0.0
```
```
acos to :complex @[pi 1]
; => 0.3222532939814587-1.86711439316026i
```
#### `acosh`
calculate the inverse hyperbolic cosine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print acosh 1.0 ; 0.0
print acosh 2 ; 1.316957896924817
print acosh 5.0 ; 2.292431669561178
```
```
acosh to :complex @[pi 1]
; => 1.86711439316026+0.3222532939814587i
```
#### `acsec`
calculate the inverse cosecant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print acsec 0 ; nan
print acsec 1.0 ; 1.570796326794897
print acsec 10 ; 0.1001674211615598
```
```
acsec to :complex @[pi 1]
; => 0.2918255976444114-0.0959139808172324i
```
#### `acsech`
calculate the inverse hyperbolic cosecant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print acsech 0 ; inf
print acsech 1.0 ; 0.0
print acsech 10 ; 0.09983407889920758
```
```
acsech to :complex @[pi 1]
; => 0.2862356627279947-0.08847073864038091i
```
#### `actan`
calculate the inverse cotangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print actan 0 ; 1.570796326794897
print actan 1 ; 0.7853981633974483
print actan 10.0 ; 0.09966865249116204
```
```
actan to :complex @[pi 1]
; => 0.2834557524705047-0.08505998507745414i
```
#### `actanh`
calculate the inverse hyperbolic cotangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print actanh 0 ; nan
print actanh 1 ; inf
print actanh 10.0 ; 0.1003353477310756
```
```
actanh to :complex @[pi 1]
; => 0.2946214403408572-0.09996750087543603i
```
#### `angle`
calculate the phase angle of given number
##### Arguments
- `number` (:complex)
##### Returns
:floating
##### Examples
```
a: to complex [1 1] ; a: 1.0+1.0i
print angle a ; 0.7853981633974483
```
#### `asec`
calculate the inverse secant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print asec 0 ; nan
print asec 45 ; 1.548572275176629
print asec 5 ; 1.369438406004566
```
```
asec to :complex @[pi 1]
; => 1.278970729150485+0.09591398081723231i
```
#### `asech`
calculate the inverse hyperbolic secant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print asech 0 ; inf
print asech 0.45 ; 1.436685652839686
print asech 1 ; 0.0
```
```
asech to :complex @[pi 1]
; => 0.09591398081723221-1.278970729150485i
```
#### `asin`
calculate the inverse sine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print asin 0 ; 0.0
print asin 0.3 ; 0.3046926540153975
print asin 1.0 ; 1.570796326794897
```
```
asin to :complex @[pi 1]
; => 1.248543032813438+1.867114393160262i
```
#### `asinh`
calculate the inverse hyperbolic sine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print asinh 0 ; 0.0
print asinh 0.3 ; 0.2956730475634224
print asinh 1.0 ; 0.881373587019543
```
```
asinh to :complex @[pi 1]
; => 1.904627686970658+0.2955850342116299i
```
#### `atan`
calculate the inverse tangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print atan 0 ; 0.0
print atan 0.3 ; 0.2914567944778671
print atan 1.0 ; 0.7853981633974483
```
```
atan to :complex @[pi 1]
; => 1.287340574324392+0.08505998507745416i
```
#### `atan2`
calculate the inverse tangent of y / x
##### Arguments
- `y` (:integer,:floating,:rational)
- `x` (:integer,:floating,:rational)
##### Returns
:floating,:complex
##### Examples
```
atan2 1 1 ; 0.7853981633974483
atan2 1 1.5 ; 0.9827937232473291
```
#### `atanh`
calculate the inverse hyperbolic tangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print atanh 0 ; 0.0
print atanh 0.3 ; 0.3095196042031118
print atanh 1.0 ; inf
```
```
atanh to :complex @[pi 1]
; => 0.2946214403408571+1.470828825919461i
```
#### `ceil`
calculate the smallest integer not smaller than given value
##### Arguments
- `value` (:integer,:floating,:rational)
##### Returns
:integer
##### Examples
```
print ceil 2.1 ; 3
print ceil 2.9 ; 3
print ceil neg 3.5 ; -3
print ceil 4 ; 4
print ceil to :rational @[neg 7 2] ; -3
```
#### `clamp`
force value within given range
##### Arguments
- `number` (:integer,:floating,:rational)
- `range` (:block,:range)
##### Returns
:integer,:floating,:rational
##### Examples
```
clamp 2 1..3 ; 2
clamp 0 1..3 ; 1
clamp 4 1..3 ; 3
clamp 4 3..1 ; 3
clamp 5 range.step: 2 0 5 ; 4
clamp 4.5 0..6 ; 4.5
clamp to :rational [1 5] 0..1 ; 1/5
clamp 4.5 [1 2.5] ; 2.5
clamp 2 [5 10] ; 5
clamp 2 [10 5] ; 5
clamp 2.5 @[1 to :rational [5 2]] ; 2.5
```
#### `conj`
calculate the complex conjugate of given number
##### Arguments
- `number` (:complex)
##### Returns
:complex
##### Examples
```
b: to :complex [1 2] ; b: 1.0+2.0i
print conj b ; 1.0-2.0i
```
#### `cos`
calculate the cosine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print cos 0 ; 1.0
print cos 0.3 ; 0.955336489125606
print cos 1.0 ; 0.5403023058681398
```
```
cos to :complex [1 1]
; => 0.8337300251311491-0.9888977057628651i
```
#### `cosh`
calculate the hyperbolic cosine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print cosh 0 ; 1.0
print cosh 0.3 ; 1.04533851412886
print cosh 1.0 ; 1.543080634815244
```
```
cosh to :complex [2 1]
; => 2.032723007019666+3.0518977991518i
```
#### `csec`
calculate the cosecant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print csec 0 ; inf
print csec 0.3 ; 3.383863361824123
print csec 1.0 ; 1.188395105778121
```
```
csec to :complex [1 1]
; => 0.6215180171704283-0.3039310016284264i
```
#### `csech`
calculate the hyperbolic cosecant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print csech 0 ; inf
print csech 0.3 ; 3.283853396698424
print csech 1.0 ; 0.8509181282393216
```
```
csech to :complex [1 1]
; => 0.3039310016284264-0.6215180171704283i
```
#### `ctan`
calculate the cotangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print ctan 0 ; inf
print ctan 0.3 ; 3.232728143765828
print ctan 1.0 ; 0.6420926159343308
```
```
ctan to :complex [1 1]
; => 0.2176215618544027-0.8680141428959249i
```
#### `ctanh`
calculate the hyperbolic cotangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print ctanh 0 ; inf
print ctanh 0.3 ; 3.432738430321741
print ctanh 1.0 ; 1.313035285499331
```
```
ctanh to :complex [1 1]
; => 0.8680141428959249-0.2176215618544027i
```
#### `denominator`
get the denominator of given number
##### Arguments
- `number` (:integer,:floating,:rational)
##### Returns
:integer
##### Examples
```
num: to :rational 12.4 ; num: 62/5
print denominator num
; => 5
```
```
print denominator 10
; => 1
```
#### `digits`
convert a number into an array of digits or an array of digits back into a number
##### Arguments
- `number` (:integer,:block)
##### Options
- `base` (:integer): use given based (default: 10)
##### Returns
:block
##### Examples
```
digits 123
; => [1 2 3]
digits [1 2 3]
; => 123
digits 0
; => [0]
digits neg 12345
; => [1 2 3 4 5]
; digits 1231231231231231231231231231023
; => [1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 0 2 3]
```
#### `epsilon`
the constant e, Euler's number
##### Examples
```
```
#### `even?`
check if given number is even
##### Arguments
- `number` (:integer)
##### Returns
:logical
##### Examples
```
even? 4 ; => true
even? 3 ; => false
```
```
print select 1..10 => even? ; 2 4 6 8 10
```
#### `exp`
calculate the exponential function for given value
##### Arguments
- `value` (:integer,:floating,:complex,:rational)
##### Returns
:floating,:complex
##### Examples
```
print exp 1.0 ; 2.718281828459045
print exp 0 ; 1.0
print exp neg 1.0 ; 0.3678794411714423
```
```
exp to :complex @[pi 1]
; => 12.50296958887651+19.47222141884161i
```
#### `factorial`
calculate the factorial of given value
##### Arguments
- `value` (:integer)
##### Returns
:integer
##### Examples
```
factorial 1 ; => 1
factorial 5 ; => 120
factorial 20 ; => 2432902008176640000
```
#### `factors`
get list of factors for given integer
##### Arguments
- `number` (:integer)
##### Options
- `prime` (:logical): prime factorization
##### Returns
:block
##### Examples
```
factors 16 ; => [1 2 4 8 16]
```
```
factors.prime 48 ; => [2 2 2 2 3]
unique factors.prime 48 ; => [2 3]
factors.prime 18446744073709551615123120
; => [2 2 2 2 3 5 61 141529 26970107 330103811]
```
#### `floor`
calculate the largest integer not greater than given value
##### Arguments
- `value` (:integer,:floating,:rational)
##### Returns
:integer
##### Examples
```
print floor 2.1 ; 2
print floor 2.9 ; 2
print floor neg 3.5 ; -4
print floor 4 ; 4
print floor to :rational @[neg 7 2] ; -4
```
#### `gamma`
calculate the gamma function for given value
##### Arguments
- `value` (:integer,:floating,:rational)
##### Returns
:floating
##### Examples
```
print gamma 3.0 ; 2.0
print gamma 10.0 ; 362880.0
print gamma 15 ; 87178291199.99985
```
#### `gcd`
calculate greatest common divisor for given collection of integers
##### Arguments
- `numbers` (:block)
##### Returns
:integer
##### Examples
```
print gcd [48 60 120] ; 12
```
#### `hypot`
calculate the hypotenuse of a right-angle triangle with given base and height
##### Arguments
- `base` (:integer,:floating,:rational)
- `height` (:integer,:floating,:rational)
##### Returns
:floating
##### Examples
```
print hypot 3 4
; 5.0
print hypot 4.0 5.0
; 6.403124237432849
```
#### `infinite`
the IEEE floating point value of positive infinity
##### Examples
```
```
#### `infinite?`
check whether given value is an infinite one
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
infinite? 4 ; false
infinite? infinite ; true
infinite? ∞ ; true
```
```
a: infinite
infinite? a ; true
b: 0
infinite? b ; false
```
#### `lcm`
calculate least common multiplier for given collection of integers
##### Arguments
- `numbers` (:block)
##### Returns
:integer
##### Examples
```
print lcm [48 60 120] ; 240
```
#### `ln`
calculate the natural logarithm of given value
##### Arguments
- `value` (:integer,:floating,:complex,:rational)
##### Returns
:floating,:complex
##### Examples
```
print ln 1.0 ; 0.0
print ln 0 ; -inf
print ln neg 7.0 ; nan
```
```
ln to :complex @[pi 1]
; => 1.19298515341341+0.308169071115985i
```
#### `log`
calculate the logarithm of value using given base
##### Arguments
- `value` (:integer,:floating,:rational)
- `base` (:integer,:floating,:rational)
##### Returns
:floating
##### Examples
```
print log 9 3 ; 2.0
print log 32.0 2.0 ; 5.0
print log 0.0 2 ; -inf
print log 100.0 10.0 ; 2.0
```
#### `negative?`
check if given number is negative
##### Arguments
- `number` (:integer,:floating,:complex,:rational)
##### Returns
:logical
##### Examples
```
negative? 5 ; => false
negative? 6-7 ; => true
```
#### `numerator`
get the numerator of given number
##### Arguments
- `number` (:integer,:floating,:rational)
##### Returns
:integer
##### Examples
```
num: to :rational 12.4 ; num: 62/5
print numerator num
; => 62
```
```
print numerator 10
; => 10
```
#### `odd?`
check if given number is odd
##### Arguments
- `number` (:integer)
##### Returns
:logical
##### Examples
```
odd? 4 ; => false
odd? 3 ; => true
```
```
print select 1..10 => odd? ; 1 3 5 7 9
```
#### `pi`
the number pi, mathematical constant
##### Examples
```
```
#### `positive?`
check if given number is positive
##### Arguments
- `number` (:integer,:floating,:complex,:rational)
##### Returns
:logical
##### Examples
```
positive? 5 ; => true
positive? 6-7 ; => false
```
#### `powmod`
modular exponentiation: calculate the result of (base^exponent) % divider
##### Arguments
- `base` (:integer)
- `exponent` (:integer)
- `divider` (:integer)
##### Returns
:null,:integer
##### Examples
```
powmod 1 10 3 ; => 1
powmod 3 2 6 ; => 3
powmod 5 5 15 ; => 5
powmod 2 3 5 ; => 3
powmod 2 4 5 ; => 1
print (powmod 2 168277 673109) = (2 ^ 168277) % 673109
; true
```
#### `prime?`
check if given integer is prime
##### Arguments
- `number` (:integer)
##### Returns
:logical
##### Examples
```
prime? 2 ; => true
prime? 6 ; => false
prime? 11 ; => true
```
```
; let's check the 14th Mersenne:
; 53113799281676709868958820655246862732959311772703192319944413
; 82004035598608522427391625022652292856688893294862465010153465
; 79337652707239409519978766587351943831270835393219031728127
prime? (2^607)-1 ; => true
```
#### `product` (alias: `∏` - infix: false)
calculate the product of all values in given list
##### Arguments
- `collection` (:block,:range)
##### Options
- `cartesian` (:logical): return the cartesian product of given sublists
##### Returns
:integer,:floating,:rational
##### Examples
```
print product [3 4] ; 12
print product [1 2 4 6] ; 48
print product [] ; 1
```
```
print product 1..10 ; 3628800
```
```
product.cartesian [[A B C][D E]]
; => [[A D] [A E] [B D] [B E] [C D] [C E]]
```
#### `random`
get a random number between given limits
##### Arguments
- `lowerLimit` (:integer,:floating,:rational)
- `upperLimit` (:integer,:floating,:rational)
##### Returns
:integer,:floating
##### Examples
```
rnd: random 0 60 ; rnd: (a random number between 0 and 60)
```
#### `reciprocal`
calculate the reciprocal of given number
##### Arguments
- `value` (:integer,:floating,:rational)
##### Returns
:rational
##### Examples
```
r: to :rational [3 2]
print reciprocal r
; 2/3
```
```
reciprocal 3 ; => 1/3
reciprocal 3.2 ; => 5/16
```
#### `round`
round given value
##### Arguments
- `value` (:integer,:floating,:rational)
##### Options
- `to` (:integer): round to given decimal places
##### Returns
:floating
##### Examples
```
print round 2.1 ; 2.0
print round 2.9 ; 3.0
print round 6 ; 6.0
print round to :rational [29 10] ; 3.0
print round to :rational [21 10] ; 2.0
print round to :rational [5 2] ; 3.0
print round pi ; 3.0
```
```
print round.to:5 pi ; 3.14159
print round.to:2 pi ; 3.14
```
#### `sec`
calculate the secant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print sec 0 ; 1.0
print sec 0.3 ; 1.046751601538086
print sec 1.0 ; 1.850815717680925
```
```
sec to :complex [1 1]
; => 0.4983370305551868+0.591083841721045i
```
#### `sech`
calculate the hyperbolic secant of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print sech 0 ; 1.0
print sech 0.3 ; 0.9566279119002483
print sech 1.0 ; 0.6480542736638855
```
```
sech to :complex [1 1]
; => 0.4983370305551868-0.5910838417210451i
```
#### `sin`
calculate the sine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print sin 0 ; 0.0
print sin 0.3 ; 0.2955202066613395
print sin 1.0 ; 0.8414709848078965
```
```
sin to :complex [1 1]
; => 0.4983370305551868-0.5910838417210451i
```
#### `sinh`
calculate the hyperbolic sine of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print sinh 0 ; 0.0
print sinh 0.3 ; 0.3045202934471426
print sinh 1.0 ; 1.175201193643801
```
```
sinh to :complex [1 1]
; => 0.6349639147847361+1.298457581415977i
```
#### `sqrt`
get square root of given value
##### Arguments
- `value` (:integer,:floating,:complex,:rational)
##### Options
- `integer` (:logical): get the integer square root
##### Returns
:floating
##### Examples
```
print sqrt 4 ; 2.0
print sqrt 16.0 ; 4.0
print sqrt 1.45 ; 1.20415945787923
```
```
sqrt to :complex @[pi 1]
; => 1.794226987182141+0.2786715413222365i
```
#### `sum` (alias: `∑` - infix: false)
calculate the sum of all values in given list
##### Arguments
- `collection` (:block,:range)
##### Returns
:integer,:floating,:rational
##### Examples
```
print sum [3 4] ; 7
print sum [1 2 4 6] ; 13
```
```
print sum 1..10 ; 55
```
#### `tan`
calculate the tangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print tan 0 ; 0.0
print tan 0.3 ; 0.3093362496096232
print tan 1.0 ; 1.557407724654902
```
```
tan to :complex [1 1]
; => 0.2717525853195119+1.083923327338695i
```
#### `tanh`
calculate the hyperbolic tangent of given angle
##### Arguments
- `angle` (:integer,:floating,:complex,:rational,:quantity)
##### Returns
:floating,:complex
##### Examples
```
print tanh 0 ; 0.0
print tanh 0.3 ; 0.2913126124515909
print tanh 1.0 ; 0.7615941559557649
```
```
tanh to :complex [1 1]
; => 1.083923327338695+0.2717525853195117i
```
#### `tau`
the number tau, mathematical constant
##### Examples
```
```
### Paths
Functions for path manipulation and information retrieval
----
The Paths module provides functionality for manipulating file system paths and extracting components from paths and URLs.
#### Key Concepts
- Path manipulation and normalization
- Path component extraction
- URL parsing
- Path type checking
- Relative path handling
#### Basic Usage
##### Path Components
```arturo
path: "photos/vacation/beach.jpg"
; extract components
extract.directory path ; photos/vacation
extract.filename path ; beach
extract.extension path ; .jpg
extract.basename path ; beach.jpg
; check path attributes
absolute? "/Users" ; => true
absolute? "photos/img.jpg" ; => false
```
##### URL Components
```arturo
url: "https://example.com:8080/path/page.html?q=term#section"
; extract URL parts
print extract.scheme url ; https
print extract.host url ; example.com
print extract.port url ; 8080
print extract.path url ; /path/page.html
print extract.query url ; q=term
print extract.anchor url ; section
```
##### Path Normalization
```arturo
; normalize paths (resolve . and ..)
print normalize "./folder/../file.txt" ; file.txt
; force treating string as file
print normalize.executable "script" ; ./script
; expand tildes
print normalize.tilde "~/code" ; /home/user/code
```
##### Relative Paths
```arturo
; get path relative to current script
read relative "some/file.txt" ; based on script location
; the exact same thing (and more natural-looking)
read ./"some/file.txt"
```
#### Common Patterns
##### Path Building
```arturo
pathBuilder: function [components][
path: "/"
loop components 'comp [
normalized: normalize comp
'path ++ normalized ++ "/"
]
return normalize path
]
; usage
fullPath: pathBuilder ["home" "user" "documents" "file.txt"]
print fullPath
; /home/user/documents/file.txt
```
##### URL Parsing Helper
```arturo
parseUrl: function [url][
extracted: extract url
#[
protocol: extracted\scheme
domain: extracted\host
port: extracted\port
endpoint: extracted\path
params: extracted\query
]
]
; usage
components: parseUrl "https://api.example.com:8080/v1/users?active=true"
print ["API Version:" components\endpoint]
; API Version: /v1/users
```
##### Working with Extensions
```arturo
getFileType: function [filepath][
ext: extract.extension filepath
case ext [
".txt" -> "text file"
".jpg" -> "image file"
".mp3" -> "audio file"
".mp4" -> "video file"
any -> "unknown file type"
]
]
; usage
print getFileType "document.txt" ; text file
```
##### Path Checks
```arturo
validatePath: function [filepath][
p: filepath
if not? absolute? p ->
p: normalize relative p
ensure exists? p
ensure file? p
return p
]
; usage
if error? try [
file: validatePath "setting.cfg"
print ["Valid file:" file]
][
print "Invalid or missing file"
]
```
----
#### `absolute`
get absolute path for given path, based on current script's location
##### Arguments
- `path` (:string)
##### Returns
:string
##### Examples
```
; we are in folder: /Users/admin/Desktop
; and have a file at: /Users/admin/Desktop/subfolder/test.txt
print absolute "../subfolder/test.txt"
; /Users/admin/subfolder/test.txt
print absolute "./test.txt"
; /Users/admin/Desktop/test.txt
```
#### `absolute?`
check if given path is an absolute path
##### Arguments
- `path` (:string)
##### Returns
:logical
##### Examples
```
absolute? "/usr/bin" ; => true
absolute? "usr/bin" ; => false
```
#### `extract`
extract components from path, url, or color
##### Arguments
- `path` (:string,:color)
##### Options
- `directory` (:logical): get path directory
- `basename` (:logical): get path basename (filename+extension)
- `filename` (:logical): get path filename
- `extension` (:logical): get path extension
- `scheme` (:logical): get scheme field from URL
- `host` (:logical): get host field from URL
- `port` (:logical): get port field from URL
- `user` (:logical): get user field from URL
- `password` (:logical): get password field from URL
- `path` (:logical): get path field from URL
- `query` (:logical): get query field from URL
- `anchor` (:logical): get anchor field from URL
- `red` (:logical): get red component from color
- `green` (:logical): get green component from color
- `blue` (:logical): get blue component from color
- `alpha` (:logical): get alpha component from color
- `hsl` (:logical): get HSL representation from color
- `hsv` (:logical): get HSV representation from color
- `hue` (:logical): get hue component from color
- `saturation` (:logical): get saturation component from color
- `luminosity` (:logical): get luminosity component from color
##### Returns
:string,:dictionary
##### Examples
```
path: "/this/is/some/path.txt"
print extract.directory path ; /this/is/some
print extract.basename path ; path.txt
print extract.filename path ; path
print extract.extension path ; .txt
print extract path
; [directory:/this/is/some basename:path.txt filename:path extension:.txt]
```
```
url: "http://subdomain.website.com:8080/path/to/file.php?q=something#there"
print extract.scheme url ; http
print extract.host url ; subdomain.website.com
print extract.port url ; 8080
print extract.user url ;
print extract.password url ;
print extract.path url ; /path/to/file.php
print extract.query url ; q=something
print extract.anchor url ; there
print extract url
; [scheme:http host:subdomain.website.com port:8080 user: password: path:/path/to/file.php query:q=something anchor:there]
```
```
extract #magenta
; => [red:255 green:0 blue:255]
extract.red #FF126D
; => 255
extract.hsl #magenta
; => [hue:300 saturation:1.0 luminosity:0.5]
extract.hue #magenta
; => 300
```
#### `list`
get files in given path
##### Arguments
- `path` (:string)
##### Options
- `recursive` (:logical): perform recursive search
- `relative` (:logical): get relative paths
##### Returns
:block
##### Examples
```
loop list "." 'file [
print file
]
; tests
; var
; data.txt
```
#### `normalize`
get normalized version of given path
##### Arguments
- `path` (:string,:literal,:pathliteral)
##### Options
- `executable` (:logical): treat path as executable
- `tilde` (:logical): expand tildes in path
##### Returns
:string,:nothing
##### Examples
```
normalize "one/../two/../../three"
; => ../three
normalize "~/one/../two/../../three"
; => three
```
```
normalize.tilde "~/one/../two/../../three"
; => /Users/three
normalize.tilde "~/Documents"
; => /Users/drkameleon/Documents
```
```
normalize.executable "myscript"
; => ./myscript
```
#### `relative` (alias: `./` - infix: false)
get relative path for given path, based on current script's location
##### Arguments
- `path` (:string)
##### Returns
:string
##### Examples
```
; we are in folder: /Users/admin/Desktop
print relative "test.txt"
; /Users/admin/Desktop/test.txt
```
### Quantities
Functions related to Quantities, physical units and constants
----
The Quantities module provides comprehensive support for physical quantities and units. It includes a wide range of physical properties, SI units, derived units, and constants, with automatic unit conversion and dimensional analysis.
#### Key Concepts
- Physical quantities with units (like "5 meters" or "72 kilometers per hour")
- Support for all SI base units and derived units
- Automatic unit conversion and compatibility checking
- Physical constants
- Dimensional analysis
- Support for currency units
#### Basic Usage
##### Creating Quantities
```arturo
; basic quantities
distance: 100`m ; 100 meters
time: 9.5`s ; 9.5 seconds
mass: 75`kg ; 75 kilograms
; derived units
speed: 60`km/h ; 60 kilometers per hour
force: 10`N ; 10 newtons
energy: 50`kWh ; 50 kilowatt-hours
```
##### Unit Conversions
```arturo
dist: 5`km
print convert dist `m ; 5000 m
; or using the infix operator
print dist --> `m ; 5000 m
speed: 90`km/h
print speed --> `m/s ; 25 m/s
temp: 25`degC
print temp --> `degF ; 77°F
```
##### Unit Compatibility
```arturo
length1: 5`m
length2: 3`km
; compatible units can be used in calculations
total: length1 + (length2 --> `m)
print total ; 3005 m
speed: 100`km/h
time: 2.5`h
; dimensional analysis works automatically
distance: speed * time
print distance ; 250 km
```
##### Working with Currencies
```arturo
price: 50`USD
euros: price --> `EUR
print euros ; 47.77 € (depends on the current
; exchange rate, obviously...)
salary: 5000`USD/mo
yearly: salary * 12
print yearly ; 60000 $/mo
```
#### Common Patterns
##### Complex Unit Calculations
```arturo
; calculating power
voltage: 220`V
current: 5`A
power: voltage * current
print power ; 1100 V·A
; calculating energy cost
time: 2`h
energy: power * time
price: 0.15`USD/kWh
cost: price * (energy --> `kWh)
print cost ; 0.33 $
```
##### Using Physical Constants
```arturo
; gravitational force
G: gravitationalConstant
m1: 5.97e24`kg ; mass of Earth
m2: 75`kg ; mass of a person
r: 6371000`m ; Earth's radius
force: G * m1 * m2 / (r * r)
print to :floating force ; 736.2513565961324
```
#### Available Properties
Physical quantities in Arturo are classified by their properties. Here are some key properties and their dimensions:
| Property | Dimensions | Example |
|----------|------------|---------|
| Length | L | `5`m |
| Time | T | `10`s |
| Mass | M | `75`kg |
| Current | I | `5`A |
| Temperature | K | `20`degC |
| Amount | N | `2`mol |
| Luminosity | J | `100`cd |
| Speed | L·T⁻¹ | `60`km/h |
| Acceleration | L·T⁻² | `9.81`m/s2 |
| Force | L·M·T⁻² | `10`N |
| Energy | L²·M·T⁻² | `100`J |
| Power | L²·M·T⁻³ | `1000`W |
> [!NOTE] There are many more properties available. Use `property` to inspect any quantity's dimensional formula.
#### Prefixes
Metric prefixes are supported for most units:
| Prefix | Symbol | Factor |
|--------|--------|--------|
| atto | a | 10⁻¹⁸ |
| femto | f | 10⁻¹⁵ |
| pico | p | 10⁻¹² |
| nano | n | 10⁻⁹ |
| micro | μ | 10⁻⁶ |
| milli | m | 10⁻³ |
| kilo | k | 10³ |
| mega | M | 10⁶ |
| giga | G | 10⁹ |
| tera | T | 10¹² |
| peta | P | 10¹⁵ |
| exa | E | 10¹⁸ |
> [!NOTE] Most units that allow prefixes can use any SI prefix (from atto- to exa-). Prefixes change the unit by the corresponding power of 10.
#### Supported Units
##### Base SI Units
| Unit | Symbol | Property | Example |
|------|---------|----------|----------|
| meter | m | Length | `5`m |
| second | s | Time | `10`s |
| kelvin | K | Temperature | `300`K |
| gram | g | Mass | `500`g |
| ampere | A | Current | `2`A |
| mole | mol | Substance | `1`mol |
| candela | cd | Luminosity | `100`cd |
##### Length Units
| Unit | Symbol | Definition | Note |
|------|--------|------------|------|
| inch | in | 127/5000 m | |
| foot | ft | 12 in | |
| yard | yd | 3 ft | |
| mile | mi | 5280 ft | |
| nautical mile | nmi | 1852 m | |
| angstrom | Å | 10⁻¹⁰ m | |
| light year | ly | 9.461e15 m | |
| astronomical unit | au | 1.496e11 m | |
| pixel | px | 1/96 in | |
| point | pt | 1/72 in | |
##### Area Units
| Unit | Symbol | Definition |
|------|---------|------------|
| acre | ac | 4840 yd² |
| hectare | ha | 10000 m² |
| barn | b | 100 ftm² |
##### Volume Units
| Unit | Symbol | Definition |
|------|---------|------------|
| liter | L | 1000 cm³ |
| gallon | gal | 231 in³ |
| barrel | bbl | 42 gal |
| quart | qt | 1/4 gal |
| pint | p | 1/2 qt |
| cup | cup | 1/2 p |
| fluid ounce | floz | 1/8 cup |
| bushel | bu | 2150.42 in³ |
| cord | cord | 128 ft³ |
##### Mass Units
| Unit | Symbol | Definition |
|------|---------|------------|
| pound | lb | 0.45359237 kg |
| ounce | oz | 1/16 lb |
| stone | st | 14 lb |
| ton | ton | 2000 lb |
| metric ton | t | 1000 kg |
| carat | ct | 0.2 g |
| grain | gr | 64.79891 mg |
##### Time Units
| Unit | Symbol | Definition |
|------|---------|------------|
| minute | min | 60 s |
| hour | h | 60 min |
| day | day | 24 h |
| week | wk | 7 day |
| month | mo | 2629746 s |
| year | yr | 31556952 s |
##### Speed Units
| Unit | Symbol | Definition |
|------|---------|------------|
| kilometers per hour | km/h | 1000/3600 m/s |
| miles per hour | mph | 5280/3600 ft/s |
| knot | kn | 1852/3600 m/s |
| mach | mach | 340.29 m/s |
##### Force Units
| Unit | Symbol | Definition |
|------|---------|------------|
| newton | N | 1 kg·m/s² |
| dyne | dyn | 10⁻⁵ N |
| pound-force | lbf | 4.44822 N |
##### Pressure Units
| Unit | Symbol | Definition |
|------|---------|------------|
| pascal | Pa | 1 N/m² |
| bar | bar | 100000 Pa |
| atmosphere | atm | 101325 Pa |
| torr | Torr | 133.3224 Pa |
| psi | psi | 6894.76 Pa |
##### Energy Units
| Unit | Symbol | Definition |
|------|---------|------------|
| joule | J | 1 N·m |
| watt-hour | Wh | 3600 J |
| calorie | cal | 4.184 J |
| electron volt | eV | 1.602e-19 J |
| BTU | BTU | 1055.06 J |
##### Power Units
| Unit | Symbol | Definition |
|------|---------|------------|
| watt | W | 1 J/s |
| horsepower | hp | 745.7 W |
##### Electric Units
| Unit | Symbol | Definition |
|------|---------|------------|
| volt | V | 1 W/A |
| ohm | Ω | 1 V/A |
| farad | F | 1 C/V |
| henry | H | 1 V·s/A |
| weber | Wb | 1 V·s |
| tesla | T | 1 Wb/m² |
##### Angle Units
| Unit | Symbol | Definition |
|------|---------|------------|
| radian | rad | base unit |
| degree | ° | π/180 rad |
| arcminute | ' | π/10800 rad |
| arcsecond | " | π/648000 rad |
##### Radiation Units
| Unit | Symbol | Definition |
|------|---------|------------|
| becquerel | Bq | 1/s |
| gray | Gy | 1 J/kg |
| sievert | Sv | 1 J/kg |
##### Information Units
| Unit | Symbol | Definition |
|------|---------|------------|
| byte | B | base unit |
| bit | b | 1/8 B |
| kibibyte | KiB | 1024 B |
| mebibyte | MiB | 1024 KiB |
| gibibyte | GiB | 1024 MiB |
| tebibyte | TiB | 1024 GiB |
> [!TIP] Arturo supports many world currencies including: AED, ALL, ARS, AUD, BGN, BHD, BND, BOB, BRL, BWP, CAD, CHF, CLP, CNY, COP, CRC, CZK, DKK, DOP, DZD, EGP, ETB, EUR, FJD, GBP, HKD, HNL, HRK, HUF, IDR, ILS, INR, IRR, ISK, JMD, JOD, JPY, KES, KRW, KWD, KYD, KZT, LBP, LKR, MAD, MDL, MKD, MXN, MUR, MYR, NAD, NGN, NIO, NOK, NPR, NZD, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, SAR, SCR, SEK, SGD, SLL, SOS, SVC, THB, TND, TRY, TTD, TWD, TZS, UAH, UGX, UYU, UZS, VES, VND, XAF, XOF, YER, ZAR, ZMW.
>
> Cryptocurrency codes are also supported: BTC (Bitcoin), ETH (Ethereum), BNB (Binance Coin).
----
#### `acceleration?`
checks if given quantity describes Acceleration
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
acceleration? 3`m/s2
; => true
```
#### `action?`
checks if given quantity describes Action
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
action? 4`kg.m2/s
; => true
```
#### `alphaParticleMass`
the mass of an alpha particle
##### Examples
```
```
#### `angle?`
checks if given quantity describes Angle
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
angle? 5`rad
; => true
```
#### `angstromStar`
one ten-billionth of a meter
##### Examples
```
```
#### `angularVelocity?`
checks if given quantity describes Angular Velocity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
angularVelocity? 6`rad/s
; => true
```
#### `area?`
checks if given quantity describes Area
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
area? 3`m2
; => true
```
#### `areaDensity?`
checks if given quantity describes Area Density
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
areaDensity? 4`kg/m2
; => true
```
#### `atomicMass`
the mass of an atomic mass unit
##### Examples
```
```
#### `avogadroConstant`
the number of atoms in 12 grams of carbon-12
##### Examples
```
```
#### `bohrRadius`
the radius of the first Bohr orbit of the hydrogen atom
##### Examples
```
```
#### `boltzmannConstant`
the ratio of the universal gas constant to Avogadro's number
##### Examples
```
```
#### `capacitance?`
checks if given quantity describes Capacitance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
capacitance? 5`F
; => true
```
#### `charge?`
checks if given quantity describes Charge
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
charge? 6`C
; => true
```
#### `classicalElectronRadius`
the radius of an electron
##### Examples
```
```
#### `conductance?`
checks if given quantity describes Conductance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
conductance? 3`S
; => true
```
#### `conductanceQuantum`
the conductance of a superconductor
##### Examples
```
```
#### `conforms?` (alias: `:=` - infix: true)
check if given quantities/units are compatible
##### Arguments
- `a` (:unit,:quantity)
- `b` (:unit,:quantity)
##### Returns
:logical
##### Examples
```
conforms? 3`m `m ; => true
conforms? 4`m `cm ; => true
4`yd := 5`m ; => true
5`m := `s ; => false
```
```
givenValue: 6`yd/s
conforms? givenValue `m ; => false
conforms? givenValue `km/h ; => true
```
```
3`m := 4`m ; => true
5`W := 5`N ; => false
5`W := 3`J/s ; => true
```
#### `convert` (alias: `-->` - infix: true)
convert quantity to given unit
##### Arguments
- `value` (:integer,:floating,:rational,:quantity)
- `unit` (:string,:word,:literal,:unit)
##### Returns
:quantity
##### Examples
```
print convert 3`m `cm
; 300.0 cm
print 1`yd2 --> `m2
; 0.836127 m²
```
#### `currency?`
checks if given quantity describes Currency
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
currency? 4`USD
; => true
```
#### `current?`
checks if given quantity describes Current
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
current? 5`A
; => true
```
#### `currentDensity?`
checks if given quantity describes Current Density
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
currentDensity? 6`A/m2
; => true
```
#### `dataTransferRate?`
checks if given quantity describes Data-Transfer Rate
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
dataTransferRate? 3`B/s
; => true
```
#### `density?`
checks if given quantity describes Density
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
density? 4`kg/m3
; => true
```
#### `deuteronMass`
the mass of a deuteron
##### Examples
```
```
#### `elastance?`
checks if given quantity describes Elastance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
elastance? 5`Daraf
; => true
```
#### `electricField?`
checks if given quantity describes Electric Field
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
electricField? 6`V/m
; => true
```
#### `electricityPrice?`
checks if given quantity describes Electricity Price
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
electricityPrice? 3`USD/kWh
; => true
```
#### `electronCharge`
the charge of an electron
##### Examples
```
```
#### `electronMass`
the mass of an electron
##### Examples
```
```
#### `electronMassEnergy`
the energy equivalent of the mass of an electron
##### Examples
```
```
#### `energy?`
checks if given quantity describes Energy
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
energy? 4`J
; => true
```
#### `entropy?`
checks if given quantity describes Entropy
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
entropy? 5`J/K
; => true
```
#### `force?`
checks if given quantity describes Force
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
force? 6`N
; => true
```
#### `frequency?`
checks if given quantity describes Frequency
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
frequency? 3`Hz
; => true
```
#### `gravitationalConstant`
the gravitational constant
##### Examples
```
```
#### `hartreeEnergy`
the energy of the ground state of the hydrogen atom
##### Examples
```
```
#### `heatFlux?`
checks if given quantity describes Heat Flux
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
heatFlux? 4`W/m2
; => true
```
#### `helionMass`
the mass of a helion
##### Examples
```
```
#### `illuminance?`
checks if given quantity describes Illuminance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
illuminance? 5`lx
; => true
```
#### `impedanceOfVacuum`
the impedance of free space
##### Examples
```
```
#### `in`
convert quantity to given unit
##### Arguments
- `unit` (:string,:word,:literal,:unit)
- `value` (:integer,:floating,:rational,:quantity)
##### Returns
:quantity
##### Examples
```
print in`cm 3`m
; 300.0 cm
print in`m2 1`yd2
; 0.836127 m²
```
#### `inductance?`
checks if given quantity describes Inductance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
inductance? 6`H
; => true
```
#### `information?`
checks if given quantity describes Information
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
information? 3`kB
; => true
```
#### `inverseConductanceQuantum`
the inverse of the conductance of a superconductor
##### Examples
```
```
#### `jerk?`
checks if given quantity describes Jerk
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
jerk? 4`m/s3
; => true
```
#### `josephsonConstant`
The inverse of the flux quantum
##### Examples
```
```
#### `kinematicViscosity?`
checks if given quantity describes Kinematic Viscosity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
kinematicViscosity? 5`m2/s
; => true
```
#### `length?`
checks if given quantity describes Length
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
length? 6`m
; => true
```
#### `luminosity?`
checks if given quantity describes Luminosity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
luminosity? 3`cd
; => true
```
#### `luminousFlux?`
checks if given quantity describes Luminous Flux
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
luminousFlux? 4`lm
; => true
```
#### `magneticFieldStrength?`
checks if given quantity describes Magnetic Field Strength
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
magneticFieldStrength? 3`A/m
; => true
```
#### `magneticFlux?`
checks if given quantity describes Magnetic Flux
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
magneticFlux? 5`Wb
; => true
```
#### `magneticFluxDensity?`
checks if given quantity describes Magnetic Flux Density
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
magneticFluxDensity? 6`T
; => true
```
#### `magneticFluxQuantum`
the magnetic flux of a superconductor
##### Examples
```
```
#### `mass?`
checks if given quantity describes Mass
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
mass? 4`kg
; => true
```
#### `massFlowRate?`
checks if given quantity describes Mass Flow Rate
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
massFlowRate? 5`kg/s
; => true
```
#### `molarConcentration?`
checks if given quantity describes Molar Concentration
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
molarConcentration? 6`mol/m3
; => true
```
#### `molarGasConstant`
the universal gas constant
##### Examples
```
```
#### `moleFlowRate?`
checks if given quantity describes Mole Flow Rate
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
moleFlowRate? 3`mol/s
; => true
```
#### `momentofInertia?`
checks if given quantity describes Moment of Inertia
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
momentofInertia? 4`kg.m2
; => true
```
#### `momentum?`
checks if given quantity describes Momentum
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
momentum? 5`kg.m/s
; => true
```
#### `muonMass`
the mass of a muon
##### Examples
```
```
#### `neutronMass`
the mass of a neutron
##### Examples
```
```
#### `permeability?`
checks if given quantity describes Permeability
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
permeability? 6`H/m
; => true
```
#### `permittivity?`
checks if given quantity describes Permittivity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
permittivity? 3`F/m
; => true
```
#### `planckConstant`
the ratio of the energy of a photon to its frequency
##### Examples
```
```
#### `planckLength`
the length of the Planck scale
##### Examples
```
```
#### `planckMass`
the mass of the Planck scale
##### Examples
```
```
#### `planckTemperature`
the temperature of the Planck scale
##### Examples
```
```
#### `planckTime`
the time of the Planck scale
##### Examples
```
```
#### `potential?`
checks if given quantity describes Potential
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
potential? 4`V
; => true
```
#### `power?`
checks if given quantity describes Power
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
power? 5`W
; => true
```
#### `pressure?`
checks if given quantity describes Pressure
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
pressure? 6`Pa
; => true
```
#### `property`
get the described property of given quantity or unit
##### Arguments
- `quantity` (:unit,:quantity)
##### Options
- `hash` (:logical): get property as a hash
##### Returns
:integer,:literal
##### Examples
```
property 3`m ; => 'length
property 4`m2 ; => 'area
property 5`m3 ; => 'volume
property 6`J/s ; => 'power
property 3`V ; => 'potential
```
#### `protonMass`
the mass of a proton
##### Examples
```
```
#### `protonMassEnergy`
the energy equivalent of the mass of a proton
##### Examples
```
```
#### `radiation?`
checks if given quantity describes Radiation
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
radiation? 3`Gy
; => true
```
#### `radiationExposure?`
checks if given quantity describes Radiation Exposure
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
radiationExposure? 4`C/kg
; => true
```
#### `reducedPlanckConstant`
the ratio of the energy of a photon to its frequency
##### Examples
```
```
#### `resistance?`
checks if given quantity describes Resistance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
resistance? 5`Ohm
; => true
```
#### `resistivity?`
checks if given quantity describes Resistivity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
resistivity? 6`Ohm.m
; => true
```
#### `rydbergConstant`
the Rydberg constant
##### Examples
```
```
#### `salary?`
checks if given quantity describes Salary
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
salary? 3`USD/h
; => true
```
#### `scalar`
get quantity value in the appropriate numeric type
##### Arguments
- `value` (:quantity)
##### Returns
:integer,:floating,:rational
##### Examples
```
scalar 3`m ; => 3
scalar 4.0`m2 ; => 4
scalar 10:2`m3 ; => 5
```
```
scalar 3.1`m ; => 3.1
scalar 5:2`m ; => 2.5
```
```
scalar 13:3`m ; => 13/3
```
#### `snap?`
checks if given quantity describes Snap
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
snap? 3`m/s4
; => true
```
#### `solidAngle?`
checks if given quantity describes Solid Angle
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
solidAngle? 4`sr
; => true
```
#### `specificVolume?`
checks if given quantity describes Specific Volume
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
specificVolume? 5`m3/kg
; => true
```
#### `specify`
define new user unit
##### Arguments
- `name` (:string,:literal)
- `value` (:unit,:quantity)
##### Options
- `symbol` (:string): define main unit symbol
- `describes` (:string): set corresponding property for new unit
- `property` (:logical): define a new property
##### Returns
:literal
##### Examples
```
specify 'nauMile 1.1508`mi
print 2`nauMile ; 2 nauMile
print 3`nauMile --> `km ; 5.5560992256 km
```
```
specify.symbol:"NM" 'nauMile 1.1508`mi
print 2`nauMile ; 2 NM
```
```
specify.describes:"coding speed" 'lph `lines/h
print 100`lph ; 100 lph
print property 100`lph ; coding speed
```
```
specify.property "sweetness" `tspSugar
print property 3`tspSugar ; sweetness
```
#### `speed?`
checks if given quantity describes Speed
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
speed? 6`m/s
; => true
```
#### `speedOfLight`
the speed of light in a vacuum
##### Examples
```
```
#### `standardGasVolume`
the volume of one mole of an ideal gas at standard temperature and pressure
##### Examples
```
```
#### `standardPressure`
the standard pressure
##### Examples
```
```
#### `standardTemperature`
the standard temperature
##### Examples
```
```
#### `substance?`
checks if given quantity describes Substance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
substance? 4`mol
; => true
```
#### `surfaceTension?`
checks if given quantity describes Surface Tension
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
surfaceTension? 5`N/m
; => true
```
#### `tauMass`
the mass of a tau
##### Examples
```
```
#### `temperature?`
checks if given quantity describes Temperature
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
temperature? 6`oC
; => true
```
#### `thermalConductivity?`
checks if given quantity describes Thermal Conductivity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
thermalConductivity? 3`W/m.K
; => true
```
#### `thermalInsulance?`
checks if given quantity describes Thermal Insulance
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
thermalInsulance? 4`m2.K/W
; => true
```
#### `thomsonCrossSection`
the cross section of an electron
##### Examples
```
```
#### `time?`
checks if given quantity describes Time
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
time? 5`s
; => true
```
#### `tritonMass`
the mass of a triton
##### Examples
```
```
#### `unitless?`
checks if given quantity describes Unitless
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
unitless? 6`items
; => true
```
#### `units`
get the units of given quantity
##### Arguments
- `value` (:unit,:quantity)
##### Options
- `base` (:logical): get base units
##### Returns
:unit
##### Examples
```
units 3`m ; => `m
units `m2 ; => `m2
units 8`J/s ; => `J/s
units 7`W ; => `W
```
```
units.base 3`m ; => `m
units.base `m2 ; => `m2
units.base 8`J/s ; => `J/s
units.base 7`W ; => `J/s
```
```
specify 'ff 3`items
units 3`ff ; => `items
units.base 3`ff ; => `items
units.base 3`ff.ha ; => `items.m2
```
```
specify 'kk 3`m2
units 3`kk ; => `kk
units.base 3`kk ; => `m2
```
#### `vacuumPermeability`
the permeability of free space
##### Examples
```
```
#### `vacuumPermittivity`
the permittivity of free space
##### Examples
```
```
#### `viscosity?`
checks if given quantity describes Viscosity
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
viscosity? 3`Pa.s
; => true
```
#### `volume?`
checks if given quantity describes Volume
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
volume? 4`m3
; => true
```
#### `volumetricFlow?`
checks if given quantity describes Volumetric Flow
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
volumetricFlow? 5`m3/s
; => true
```
#### `vonKlitzingConstant`
the resistance of a superconductor
##### Examples
```
```
#### `waveNumber?`
checks if given quantity describes Wave Number
##### Arguments
- `value` (:quantity)
##### Returns
:logical
##### Examples
```
waveNumber? 6`/m
; => true
```
### Reflection
Functions and helpers for retrieving runtime information about different objects, components, or types
----
The Reflection module provides tools for runtime introspection and program analysis. From inspecting variables to benchmarking code, it offers comprehensive capabilities for understanding and analyzing your program's behavior.
#### Key Concepts
- Runtime information retrieval
- Symbol and attribute inspection
- Performance measurement
- Stack examination
#### Basic Usage
##### Inspecting Values
```arturo
value: [1 2 #[name: "John"] [nested block]]
; detailed inspection
inspect value ; shows full structure with types
; get information about function/symbol
info 'print ; shows details about 'print function
info.get 'print ; returns info as dictionary
; get current stack
print stack ; shows current value stack (as a block)
```
##### Working with Attributes
```arturo
doSth function [x][
; check if attribute exists
if attr? 'verbose ->
print "verbose mode on"
; get attribute value
level: attr 'level ; returns null if not set
; get all attributes
options: attrs ; returns dictionary of all set attributes
]
```
##### Symbol Management
```arturo
; get all defined symbols
syms: symbols ; returns dictionary of all symbols
; check if symbol exists
print set? 'x ; true if 'x is defined
; get function arity
funcs: arity ; get dictionary of function arities
print arity\add ; 2 (which is the number of parameters `add` takes ;-))
```
##### Performance Measurement
```arturo
; basic benchmarking
benchmark [
loop 1..1000 'x [
; some operation
]
]
; with the .get attribute
elapsed: benchmark.get [
; some operation
]
print ["Operation took:" elapsed]
; multiple runs for better accuracy
total: 0
loop 1..100 'run [
'total ++ benchmark.get [
; operation to measure
]
]
average: total / 100
```
#### Common Patterns
##### Function Analysis
```arturo
; get complete function information
analyzeFunction: function [funcName][
info: info.get funcName
print ["Function:" funcName]
print ["Type:" info\type]
print ["Arguments:" info\args]
print ["Returns:" info\returns]
if key? info 'options [
print ["Options:" info\options]
]
]
analyzeFunction 'split
; Function: split
; Type: :function
; Arguments: [collection:[:string :literal :pathliteral :block]]
; Returns: [:block :nothing]
```
##### Performance Profiling
```arturo
; simple profiling helper
profile: function [label operation][
print ["Profiling:" label]
; multiple runs for stability
times: []
loop 1..10 'run [
'times ++ to :floating benchmark.get operation
]
; calculate statistics
avg: average times
dev: deviation times
print ["Average:" avg "±" dev "seconds"]
]
; usage example
profile "array sorting" [
sort [5 3 8 1 9 2 7 4 6 0]
]
```
> [!TIP] When benchmarking, always run multiple iterations to get stable results and consider system load variations.
##### Runtime Information
```arturo
; check execution context
if standalone? [
; very useful in the case of "importable" modules/packages
; or when you want to inject some tiny bit of testing code, etc...
print "Running as standalone script"
]
```
----
#### `arity`
get index of function arities
##### Returns
:dictionary
##### Examples
```
print arity\print ; 1
```
#### `attr`
get given attribute, if it exists
##### Arguments
- `name` (:string,:literal)
##### Returns
:null,:any
##### Examples
```
multiply: function [x][
switch attr? "with"
-> x * attr "with"
-> 2*x
]
print multiply 5
; 10
print multiply.with: 6 5
; 30
```
#### `attr?`
check if given attribute exists
##### Arguments
- `name` (:string,:literal)
##### Returns
:logical
##### Examples
```
greet: function [x][
switch attr? 'later
-> ~"|x| I'm afraid, I'll greet you later"
-> ~"Hello, |x|!"
]
greet "John"
; => Hello, John!
greet.later "John"
; => John I'm afraid, I'll greet you later!
; Have in mind that `attr?` won't pop your attribute's stack
greet "Joe"
; => Joe I'm afraid, I'll greet you later!
```
#### `attrs`
get dictionary of set attributes
##### Returns
:dictionary
##### Examples
```
greet: function [x][
print ["Hello" x "!"]
print attrs
]
greet.later "John"
; Hello John!
; [
; later: true
; ]
```
#### `benchmark`
benchmark given code
##### Arguments
- `action` (:block,:bytecode)
##### Options
- `get` (:logical): get benchmark time
##### Returns
:floating,:nothing
##### Examples
```
benchmark [
; some process that takes some time
loop 1..10000 => prime?
]
; [benchmark] time: 0.065s
```
```
benchmark.get [
loop 1..10000 => prime?
]
; => 0.3237628936767578
```
#### `info`
print info for given symbol
##### Arguments
- `symbol` (:string,:word,:literal,:pathliteral,:symbolliteral)
##### Options
- `get` (:logical): get information as dictionary
##### Returns
:dictionary,:nothing
##### Examples
```
info 'print
; |--------------------------------------------------------------------------------
; | print :function Io
; |--------------------------------------------------------------------------------
; | print given value to screen with newline
; |--------------------------------------------------------------------------------
; | usage print value :any
; |
; | options .lines -> print each value in block in a new line
; |
; | returns :nothing
; |--------------------------------------------------------------------------------
```
```
info '++
; |--------------------------------------------------------------------------------
; | append :function 0x107555A10
; | alias ++
; |--------------------------------------------------------------------------------
; | append value to given collection
; |--------------------------------------------------------------------------------
; | usage append collection :char :string :literal :block
; | value :any
; |
; | returns :string :block :nothing
; |--------------------------------------------------------------------------------
```
```
print info.get 'print
; [name:print address:0x1028B3410 type::function module:Io args:[value:[:any]] attrs:[] returns:[:nothing] description:print given value to screen with newline example:print "Hello world!" ; Hello world!]
```
#### `inspect`
print detailed structure and type information of given value
##### Arguments
- `value` (:any)
##### Options
- `muted` (:logical): don't use color output
##### Returns
:nothing
##### Examples
```
inspect 3 ; 3 :integer
a: "some text"
inspect a ; some text :string
```
#### `methods`
get list of methods for given object or module
##### Arguments
- `object` (:object,:module)
##### Returns
:block
##### Examples
```
define :cat [
init: method [nick][
this\nick: join.with: " " @["Mr." capitalize nick]
]
meow: method [][
print [this\nick ":" "'meow!'"]
]
]
snowflake: to :cat ["snowflake"]
methods snowflake
; => [init meow]
```
#### `stack`
get current stack
##### Returns
:dictionary
##### Examples
```
1 2 3 "done"
print stack
; 1 2 3 done
```
#### `standalone?`
checks if current script runs from the command-line
##### Returns
:logical
##### Examples
```
doSomething: function [x][
print ["I'm doing something with" x]
]
if standalone? [
print "It's running from command line and not included."
print "Nothing to do!"
]
```
#### `symbols`
get currently defined symbols
##### Returns
:dictionary
##### Examples
```
a: 2
b: "hello"
print symbols
; [
; a: 2
; b: "hello"
;_]
```
### Sets
Common functions and operations for sets (union, intersection, difference, etc)
----
The Sets module provides functions for performing set theory operations on blocks. It includes all standard set operations and set relationship tests.
#### Key Concepts
- Sets are represented using blocks (duplicate values are handled automatically)
- Standard set operations (union, intersection, difference)
- Set relationship tests (subset, superset)
- Support for powerset generation
#### Basic Usage
##### Basic Set Operations
```arturo
A: [1 2 3 4]
B: [3 4 5 6]
union A B ; => [1 2 3 4 5 6]
intersection A B ; => [3 4]
difference A B ; => [1 2]
```
##### Set Relationships
```arturo
X: [1 2 3]
Y: [1 2 3 4]
subset? X Y ; true
subset?.proper X Y ; true
superset? Y X ; true
; check if sets have common elements
intersect? X Y ; true
disjoint? X Y ; false
```
> [!NOTE] A proper subset/superset means that one set must be strictly smaller/larger than the other - they cannot be equal.
##### Powerset Generation
```arturo
print powerset [1 2 3]
; [] [1] [2] [1 2] [3] [1 3] [2 3] [1 2 3]
```
> [!NOTE] The powerset contains all possible subsets of a set, including the empty set and the set itself.
#### Common Patterns
##### Symmetric Difference
```arturo
A: [1 2 3 4]
B: [3 4 5 6]
; elements that are in either set but not in both
print difference.symmetric A B ; 1 2 5 6
```
##### Set Operations with Multiple Sets
```arturo
sets: [[1 2] [2 3] [3 4]]
result: fold sets => intersection
; []
unionAll: fold sets => union
; [1 2 3 4]
```
----
#### `difference`
return the difference of given sets
##### Arguments
- `setA` (:literal,:pathliteral,:block)
- `setB` (:block)
##### Options
- `symmetric` (:logical): get the symmetric difference
##### Returns
:block,:nothing
##### Examples
```
print difference [1 2 3 4] [3 4 5 6]
; 1 2
```
```
a: [1 2 3 4]
b: [3 4 5 6]
difference 'a b
; a: [1 2]
```
```
print difference.symmetric [1 2 3 4] [3 4 5 6]
; 1 2 5 6
```
#### `disjoint?`
check if given sets are disjoint (they have no common elements)
##### Arguments
- `setA` (:block)
- `setB` (:block)
##### Returns
:logical
##### Examples
```
disjoint? [1 2 3 4] [3 4 5 6]
; => false
disjoint? [1 2 3 4] [5 6 7 8]
; => true
```
#### `intersect?`
check if given sets intersect (they have at least one common element)
##### Arguments
- `setA` (:block)
- `setB` (:block)
##### Returns
:logical
##### Examples
```
intersect? @1..10 @8..12
; => true
intersect? ["one" "two" "three"] ["three" "four" "five"]
; => true
intersect? ["one" "two" "three"] ["four" "five" "six"]
; => false
```
#### `intersection` (alias: `∩` - infix: true)
return the intersection of given sets
##### Arguments
- `setA` (:literal,:pathliteral,:block)
- `setB` (:block)
##### Returns
:block,:nothing
##### Examples
```
print intersection [1 2 3 4] [3 4 5 6]
; 3 4
```
```
a: [1 2 3 4]
b: [3 4 5 6]
intersection 'a b
; a: [3 4]
```
#### `powerset`
return the powerset of given set
##### Arguments
- `set` (:literal,:pathliteral,:block)
##### Returns
:block,:nothing
##### Examples
```
powerset [1 2 3]
; [[] [1] [2] [1 3] [3] [1 2] [2 3] [1 2 3]]
```
#### `subset?` (alias: `⊆` - infix: true)
check if given set is a subset of second set
##### Arguments
- `setA` (:block)
- `setB` (:block)
##### Options
- `proper` (:logical): check if proper subset
##### Returns
:logical
##### Examples
```
subset? [1 3] [1 2 3 4]
; => true
subset?.proper [1 3] [1 2 3 4]
; => true
subset? [1 3] [3 5 6]
; => false
subset? [1 3] [1 3]
; => true
subset?.proper [1 3] [1 3]
; => false
```
#### `superset?` (alias: `⊇` - infix: true)
check if given set is a superset of second set
##### Arguments
- `setA` (:block)
- `setB` (:block)
##### Options
- `proper` (:logical): check if proper superset
##### Returns
:logical
##### Examples
```
superset? [1 2 3 4] [1 3]
; => true
superset?.proper [1 2 3 4] [1 3]
; => true
superset? [3 5 6] [1 3]
; => false
superset? [1 3] [1 3]
; => true
superset?.proper [1 3] [1 3]
; => false
```
#### `union` (alias: `∪` - infix: true)
return the union of given sets
##### Arguments
- `setA` (:literal,:pathliteral,:block)
- `setB` (:block)
##### Returns
:block,:nothing
##### Examples
```
print union [1 2 3 4] [3 4 5 6]
; 1 2 3 4 5 6
```
```
a: [1 2 3 4]
b: [3 4 5 6]
union 'a b
; a: [1 2 3 4 5 6]
```
### Sockets
High-level socket interface and relevant socket communication methods
----
The Sockets module provides a straightforward way to handle network communication using TCP/UDP sockets. Rather than dealing with low-level details, you can focus on building networked applications with just a few simple functions.
#### Key Concepts
- Server sockets listen for incoming connections
- Client sockets connect to servers
- Messages can be sent/received as strings
- Both TCP (default) and UDP protocols are supported
#### Basic Usage
##### Creating a Server
```arturo
server: listen 8000
print "Server listening on port 8000..."
```
> [!IMPORTANT] Always remember to `unplug` your sockets when you're done with them to free up system resources.
##### Accepting Connections & Handling Messages
```arturo
; accept new client
client: accept server
; send a message
send client "hello!"
; receive a message
message: receive.timeout:1000 client ; timeout after 1 second if no message
```
> [!CAUTION] Watch out for message sizes when using receive: for large ones, consider implementing a chunking strategy or using a protocol with clear message boundaries.
##### Using UDP
When you need faster, connectionless communication:
```arturo
server: listen.udp 8000
```
> [!WARNING] UDP messages may arrive out of order or not at all. Only use UDP when your application can handle message loss.
#### Common Patterns
##### Echo Server
A minimal TCP server that echoes back messages:
```arturo
; server.art
server: listen 8000
print "Server listening on port 8000..."
while [true][
client: accept server
message: receive client
send client ~"got: |message|"
unplug client ; clean up when done
]
```
And its corresponding client:
```arturo
; client.art
client: connect.to:"localhost" 8000
send client "hello server!"
print receive client
unplug client
```
##### Multi-Client Chat Server
A more complete example showing how to handle multiple clients:
```arturo
server: listen 8000
clients: []
print "Chat server started..."
while [true][
; accept new connection
client: accept server
'clients ++ client
; broadcast arrival
loop clients 'c [
if c <> client ->
send c "* new user joined *"
]
; handle messages
; note: in a real implementation, you'd want to handle
; client disconnections and cleanup as well
while [true][
message: receive client
if empty? message -> break
; broadcast to all other clients
loop clients 'c [
if c <> client ->
send c message
]
]
]
```
----
#### `accept`
accept incoming connection and return corresponding socket
##### Arguments
- `server` (:socket)
##### Returns
:socket
##### Examples
```
server: listen 18966
print "started server connection..."
client: accept server
print ["accepted incoming connection from:" client]
```
#### `connect`
create new socket connection to given server port
##### Arguments
- `port` (:integer)
##### Options
- `to` (:string): set socket address
- `udp` (:logical): use UDP instead of TCP
##### Returns
:socket
##### Examples
```
; connect to local server on port 18966
server: connect 18966
```
```
; "connect" to a udp server on port 12345
server: connect.udp 12345
```
```
; connect to a remote server on port 18966
server: connect.to:"123.456.789.123" 18966
```
#### `listen`
start listening on given port and return new socket
##### Arguments
- `port` (:integer)
##### Options
- `udp` (:logical): use UDP instead of TCP
##### Returns
:socket
##### Examples
```
; start a server listening on port 18966
server: listen 18966
```
#### `receive`
receive line of data from selected socket
##### Arguments
- `origin` (:socket)
##### Options
- `size` (:integer): set maximum size of received data
- `timeout` (:integer): set timeout (in milliseconds)
##### Returns
:string
##### Examples
```
server: listen 18966
print "started server connection..."
client: accept server
print ["accepted incoming connection from:" client]
keepGoing: true
while [keepGoing][
message: receive client
print ["received message:" message]
if message = "exit" [
unplug client
keepGoing: false
]
]
unplug server
```
#### `send`
send given message to selected socket
##### Arguments
- `destination` (:socket)
- `message` (:string)
##### Options
- `chunk` (:logical): don't send data as a line of data
##### Returns
:nothing
##### Examples
```
; connect to a local server on port 256
socket: connect.to:"localhost" 256
; send a message to the server
send socket "Hello Socket World"
```
#### `send?`
send given message to selected socket and return true if successful
##### Arguments
- `destination` (:socket)
- `message` (:string)
##### Returns
:logical
##### Examples
```
; connect to a local server on port 256
socket: connect.to:"localhost" 256
; send a message to the server
; and check if it was successful
sent?: send? socket "Hello Socket World"
print ["Message was sent successfully:" sent?]
```
#### `unplug`
close given socket
##### Arguments
- `socket` (:socket)
##### Returns
:nothing
##### Examples
```
; connect to a local server on port 256
socket: connect.to:"localhost" 256
; send a message to the server
send socket "Hello Socket World"
; disconnect from the server
unplug socket
```
### Statistics
Functions and helpers for working with statistics and samples
----
The Statistics module provides essential functions for statistical analysis of numerical data. From basic averages to more complex statistical measures like variance and kurtosis, it offers everything you need for common statistical operations.
#### Key Concepts
- Works with collections of numbers (blocks and ranges)
- Supports both population and sample statistics
- All operations handle integer, floating and rational numbers
- Results are always returned as floating-point numbers for maximum precision
#### Basic Usage
##### Getting Averages and Medians
```arturo
data: [1 2 3 5 7]
avg: average data ; => 3.6
med: median data ; => 3
; works with ranges too!
print average 1..100 ; 50.5
```
> [!NOTE] `average` and `median` both require the data to be numeric. For mixed data types, make sure to filter non-numeric values first.
##### Calculating Variance and Standard Deviation
```arturo
numbers: [2 4 4 4 5 5 7 9]
; population statistics (default)
print deviation numbers ; 2.0
print variance numbers ; 4.0
; sample statistics
print deviation.sample numbers ; 2.138089935299395
print variance.sample numbers ; 4.571428571428571
```
> [!TIP] Use sample statistics (with the `.sample` attribute) when working with data that represents a subset of a larger population.
##### Distribution Analysis
```arturo
data: [1 2 2 3 3 3 4 4 5]
; check how the distribution leans
print round.to:3 skewness data ; 0.0 (symmetric)
print round.to:3 kurtosis data ; -0.75 (platykurtic)
; for sample data
print round.to:3 skewness.sample data ; 0.0
print round.to:3 kurtosis.sample data ; -0.286
```
#### Common Patterns
##### Basic Statistical Summary
A common task is getting a quick overview of your data:
```arturo
data: [12 15 18 22 25 28 32]
print ["Average:" average data]
print ["Deviation: ±" deviation data]
print ["Range:" min data ".." max data]
```
##### Outlier Detection
Using standard deviations to find potential outliers:
```arturo
scores: [75 78 82 85 85 86 89 91 92 97 98 135]
avg: average scores
dev: deviation scores
loop scores 'score [
if (abs score - avg) > 2 * dev ->
print ["Possible outlier:" score]
]
```
----
#### `average`
get average from given collection of numbers
##### Arguments
- `collection` (:block,:range)
##### Returns
:floating
##### Examples
```
print average [2 4 5 6 7 2 3]
; 4.142857142857143
```
#### `deviation`
get population standard deviation of given collection of numbers
##### Arguments
- `collection` (:block)
##### Options
- `sample` (:logical): calculate the sample standard deviation
##### Returns
:floating
##### Examples
```
arr: [1 2 3 4]
arr2: [3 120 4 7 87 2 6 34]
print deviation arr ; 1.118033988749895
print deviation arr2 ; 42.70959347734417
deviation.sample arr ; => 1.290994448735806
deviation.sample arr2 ; => 45.65847597731914
```
#### `kurtosis`
get population kurtosis of given collection of numbers
##### Arguments
- `collection` (:block)
##### Options
- `sample` (:logical): calculate the sample kurtosis
##### Returns
:floating
##### Examples
```
arr: [1 2 3 4]
arr2: [3 120 4 7 87 2 6 34]
print kurtosis arr ; -1.36
print kurtosis arr2 ; -0.3863717894076322
kurtosis.sample arr ; => -1.200000000000001
kurtosis.sample arr2 ; => 0.5886192422439724
```
#### `median`
get median from given collection of numbers
##### Arguments
- `collection` (:block)
##### Returns
:null,:integer,:floating
##### Examples
```
print median [2 4 5 6 7 2 3]
; 6
print median [1 5 2 3 4 7 9 8]
; 3.5
```
#### `skewness`
get population skewness of given collection of numbers
##### Arguments
- `collection` (:block)
##### Options
- `sample` (:logical): calculate the sample skewness
##### Returns
:floating
##### Examples
```
arr: [1 2 3 4]
arr2: [3 120 4 7 87 2 6 34]
print skewness arr ; 0.0
print skewness arr2 ; 1.127950016816592
skewness.sample arr ; => 0.0
skewness.sample arr2 ; => 1.40680083744453
```
#### `variance`
get population variance of given collection of numbers
##### Arguments
- `collection` (:block)
##### Options
- `sample` (:logical): calculate the sample variance
##### Returns
:floating
##### Examples
```
arr: [1 2 3 4]
arr2: [3 120 4 7 87 2 6 34]
print variance arr ; 1.25
print variance arr2 ; 1824.109375
variance.sample arr ; => 1.666666666666667
variance.sample arr2 ; => 2084.696428571428
```
### Strings
Functions and helpers for manipulating and dealing with strings or character blocks
----
The Strings module provides comprehensive functionality for string manipulation, from basic operations to advanced templating. It handles strings as Unicode character collections and offers powerful pattern matching capabilities.
#### Key Concepts
- Full Unicode support
- String interpolation and templating
- Multiple string creation syntaxes
- Pattern matching and substitution
- Case conversion and manipulation
#### Basic Usage
##### String Creation
```arturo
; basic strings
str: "hello world"
; multi-line strings
text: {
This is a multi-line string
that preserves formatting
but strips common indentation
}
; verbatim strings (keep exact formatting)
code: {:
def main():
print("hello")
:}
; right smart-quote strings (everything until end of line)
message: « This is a single line string
; heredoc-style
data:
------
Everything after the dashes
until the end of the file
is part of the string
------
```
##### Basic Operations
```arturo
; concatenation
full: "hello " ++ "world" ; hello world
; case conversion
upper "hello" ; HELLO
lower "WORLD" ; world
capitalize "john" ; John
; checking content
prefix? "hello" "he" ; => true
suffix? "hello" "lo" ; => true
contains? "hello" "ll" ; => true
; whitespace handling
strip " hello " ; hello
strip.start " hi" ; hi
strip.end "hi " ; hi
```
##### Pattern Matching
```arturo
text: "hello world"
; using regex
match text {/o(.+)d/} ; "o world"
; capturing matches
match.capture text {/([wrl]+)o/}
; => ["ll" "w"]
; replace patterns
final: replace "hi there" "hi" "hello"
print final ; hello there
; with regex
result: replace "Date: 2024" {/\d+/} "2025"
print result ; Date: 2025
```
#### Common Patterns
##### String Manipulation
```arturo
; word wrapping
text: "This is a very long line that needs to be wrapped"
print wordwrap.at:20 text
; This is a very long
; line that needs to
; be wrapped
; truncating
print truncate "Hello World" 5 ; Hello...
print truncate.with:"..." "Hello World" 5 ; Hello...
; padding
print pad.right "Price:" 10 ; Price:
print pad.center "Title" 20 ; -------Title--------
```
##### Working with Parts
```arturo
text: "hello world"
; splitting
words: split.words text
; ["hello" "world"]
chars: split text
; ["h" "e" "l" "l" "o" " " "w" "o" "r" "l" "d"]
; joining
print join.with:", " ["a" "b" "c"] ; a, b, c
; slicing
print slice text 0 4 ; hello
```
#### String Templates
Arturo's templating system uses pipe characters (`|...|`) for interpolation:
##### Simple Interpolation
```arturo
name: "Bill"
age: 38
; basic interpolation
print ~"Hello |name|!" ; Hello Bill!
print ~"I am |age| years old" ; I am 38 years old
; with expressions
print ~"Next year I'll be |age + 1|" ; Next year I'll be 39
```
##### Conditional Templates
```arturo
age: 30
template: {
<||= (age > 21)? [ ||>
You can enter the club
<||][||>
Sorry, too young
<||]||>
}
print render.template template
; You can enter the club
```
##### Loops in Templates
```arturo
items: ["apple" "banana" "orange"]
template: {
<|| loop items 'item [||>
-
<||= item ||>
<||]||>
}
print render.template template
;
; -
; apple
;
; -
; banana
;
; -
; orange
;
;
```
##### Advanced Template Features
```arturo
users: @[
#[name: "John" role: "admin"]
#[name: "Alice" role: "user"]
]
template: {
Users:
<|| loop users 'user [||>
* <||= user\name ||>
<||= user\role = "admin" [||>
(Administrator)
<||]||>
<||]||>
}
print render.template template
; Users:
; * John
; true
; * Alice
; false
```
----
#### `alphabet`
get dictionary-index charset for given locale
##### Arguments
- `locale` (:string,:literal)
##### Options
- `lower` (:logical): return lowercase characters (default)
- `upper` (:logical): return uppercase characters
- `all` (:logical): also return non-dictionary characters
##### Returns
:null,:block
##### Examples
```
alphabet'es
; => [a b c d e f g h i j k l m n ñ o p q r s t u v w x y z]
alphabet.upper 'es
; => [A B C D E F G H I J K L M N Ñ O P Q R S T U V W X Y Z]
alphabet.all 'es
; => [a b c d e f g h i j k l m n ñ o p q r s t u v w x y z á é í ó ú ü]
alphabet.lower.upper.all 'es
; => [a b c d e f g h i j k l m n ñ o p q r s t u v w x y z á é í ó ú ü A B C D E F G H I J K L M N Ñ O P Q R S T U V W X Y Z Á É Í Ó Ú Ü]
```
#### `ascii?`
check if given character/string is in ASCII
##### Arguments
- `string` (:char,:string)
##### Returns
:logical
##### Examples
```
ascii? 'd' ; true
```
```
ascii? '😀' ; false
ascii? "hello world" ; true
ascii? "Hællø wœrld" ; false
ascii? "Γειά!" ; false
```
#### `capitalize`
convert given string to capitalized
##### Arguments
- `string` (:char,:string,:literal,:pathliteral)
##### Returns
:char,:string,:nothing
##### Examples
```
print capitalize "hello World" ; "Hello World"
```
```
str: "hello World"
capitalize 'str ; str: "Hello World"
```
#### `escape`
escape given string
##### Arguments
- `string` (:string,:literal,:pathliteral)
##### Options
- `json` (:logical): for literal use in JSON strings
- `regex` (:logical): for literal use in regular expression
- `shell` (:logical): for use in a shell command
- `xml` (:logical): for use in an XML document
##### Returns
:string,:nothing
##### Examples
```
str: {a long "string" + with \diffe\rent symbols.}
print escape str
; "a long \"string\" + with \\diffe\\rent symbols."
print escape.json str
; a long \"string\" + with \\diffe\\rent symbols.
print escape.regex str
; a\x20long\x20\x22string\x22\x20\x2B\x20with\x20\x5Cdiffe\x5Crent\x20symbols\x2E
print escape.shell str
; 'a long "string" + with \diffe\rent symbols.'
print escape.xml str
; a long "string" + with \diffe\rent symbols.
```
#### `indent`
indent each line of given text
##### Arguments
- `text` (:string,:literal,:pathliteral)
##### Options
- `n` (:integer): pad by given number of spaces (default: 4)
- `with` (:string): use given padding
##### Returns
:string,:nothing
##### Examples
```
str: "one\ntwo\nthree"
print indent str
; one
; two
; three
print indent .n:10 .with:"#" str
; ##########one
; ##########two
; ##########three
```
#### `jaro`
calculate Jaro distance/similarity between given strings
##### Arguments
- `stringA` (:string)
- `stringB` (:string)
##### Returns
:floating
##### Examples
```
jaro "one" "one" ; => 1.0
jaro "crate" "trace" ; => 0.7333333333333334
jaro "dwayne" "duane" ; => 0.8222222222222223
jaro "abcdef" "fedcba" ; => 0.3888888888888888
jaro "abcde" "vwxyz" ; => 0.0
```
#### `join`
join collection of values into string
##### Arguments
- `collection` (:literal,:pathliteral,:block)
##### Options
- `with` (:char,:string): use given separator
- `path` (:logical): join as path components
- `lines` (:logical): join with newlines as separator.
- `words` (:logical): join with spaces as separator
##### Returns
:string,:nothing
##### Examples
```
arr: ["one" "two" "three"]
print join arr
; onetwothree
print join.with:"," arr
; one,two,three
join 'arr
; arr: "onetwothree"
```
```
print join ['H' 'e' 'l' 'l' 'o' '!']
; Hello!
print join @["1 + 2 = " 1+2]
; 1 + 2 = 3
```
```
join.with:'-' ["Hello" "world"]
; => "Hello-world"
```
```
join.words ["This" "is" "a" "sentence."]
; => "This is a sentence."
```
```
; This example uses the universal new line character
; If you need to use carriage return for some reason, use join.with: "\\r\\n" instead.
$> join.lines ["# Recipe", "", "1. Apple", "2. Banana"]
=> # Recipe
1. Apple
2. Banana
```
#### `levenshtein`
calculate Levenshtein distance/similarity between given strings
##### Arguments
- `stringA` (:string)
- `stringB` (:string)
##### Options
- `align` (:logical): return aligned strings
- `with` (:char): use given filler for alignment (default: -)
##### Returns
:integer,:block
##### Examples
```
print levenshtein "for" "fur" ; 1
print levenshtein "one" "one" ; 0
```
```
print join.with:"\n" levenshtein .align "ACTGCACTGAC" "GCATGACTAT"
; AC-TGCACTGAC
; GCATG-ACT-AT
```
#### `lower`
convert given string to lowercase
##### Arguments
- `string` (:char,:string,:literal,:pathliteral)
##### Returns
:char,:string,:nothing
##### Examples
```
print lower "hello World, 你好!" ; "hello world, 你好!"
```
```
str: "hello World, 你好!"
lower 'str ; str: "hello world, 你好!"
```
```
ch: 'A'
lower ch
; => 'a'
```
#### `lower?`
check if given string is lowercase
##### Arguments
- `string` (:char,:string)
##### Returns
:logical
##### Examples
```
lower? "ñ" ; => true
lower? "X" ; => false
lower? "Hello World" ; => false
lower? "hello" ; => true
```
```
lower? 'a' ; => true
lower? 'A' ; => false
```
#### `match`
get matches within string, using given pattern or regular expression
##### Arguments
- `string` (:string)
- `regex` (:char,:string,:regex)
##### Options
- `once` (:logical): get just the first match
- `count` (:logical): just get number of matches
- `capture` (:logical): get capture groups only
- `named` (:logical): get named capture groups as a dictionary
- `bounds` (:logical): get match bounds only
- `in` (:range): get matches within given range
- `full` (:logical): get results as an array of match results
##### Returns
:integer,:dictionary,:block
##### Examples
```
match "hello" "hello" ; => ["hello"]
match "x: 123, y: 456" {/[0-9]+/} ; => ["123" "456"]
match "this is a string" {/[0-9]+/} ; => []
```
```
match.once "x: 123, y: 456" {/[0-9]+/} ; => ["123"]
```
```
match.count "some words" {/\w+/} ; => 2
```
```
match.capture "abc" {/(.)/} ; => ["a" "b" "c"]
match.capture "x: 123, y: 456 - z: 789, w: 012"
{/\w: (\d+), \w: (\d+)/}
; => [["123" "456"] ["789" "012"]]
```
```
inspect match.capture.named "x: 123, y: 456 - z: 789, w: 012"
{/\w: (?\d+), \w: (?\d+)/}
;[ :block
; [ :dictionary
; numA : 123 :string
; numB : 456 :string
; ]
; [ :dictionary
; numA : 789 :string
; numB : 012 :string
; ]
;]
```
```
match.bounds "hELlo wORLd" {/[A-Z]+/}
; => [1..2 7..9]
```
```
match.in:0..2 "hello" {/l/} ; => ["l"]
```
#### `match?`
check if string matches given regular expression
##### Arguments
- `string` (:string)
- `regex` (:string,:regex)
##### Options
- `in` (:range): get matches within given range
##### Returns
:logical
##### Examples
```
match? "hello" {/l/} ; => true
match? "hello" {/x/} ; => false
match? "hello" "l" ; => true
```
```
match?.in:0..1 "hello" {/l/} ; => false
match?.in:2..4 "hello" {/l/} ; => true
```
#### `numeric?`
check if given string is numeric
##### Arguments
- `string` (:char,:string)
##### Returns
:logical
##### Examples
```
numeric? "hello" ; => false
numeric? "3.14" ; => true
numeric? "18966" ; => true
numeric? "3:5" ; => true
numeric? "0xdeadbeef" ; => true
numeric? "123xxy" ; => false
```
#### `outdent`
outdent each line of given text, by using minimum shared indentation
##### Arguments
- `text` (:string,:literal,:pathliteral)
##### Options
- `n` (:integer): unpad by given number of spaces
- `with` (:string): use given padding
##### Returns
:string,:nothing
##### Examples
```
print outdent {:
one
two
three
:}
; one
; two
; three
```
```
print outdent.n:1 {:
one
two
three
:}
; one
; two
; three
```
#### `pad`
align string by adding given padding
##### Arguments
- `string` (:string,:literal,:pathliteral)
- `padding` (:integer)
##### Options
- `center` (:logical): add padding to both sides
- `right` (:logical): add right padding
- `with` (:char): pad with given character
##### Returns
:string
##### Examples
```
pad "good" 10 ; => " good"
pad.right "good" 10 ; => "good "
pad.center "good" 10 ; => " good "
```
```
a: "hello"
pad 'a 10 ; a: " hello"
```
```
pad.with:`0` to :string 123 5
; => 00123
```
#### `prefix?`
check if string starts with given prefix
##### Arguments
- `string` (:string)
- `prefix` (:char,:string,:regex)
##### Returns
:logical
##### Examples
```
prefix? "hello" "he" ; => true
prefix? "boom" "he" ; => false
```
```
prefix? "hello" {/\w+/} ; => true
prefix? "world" {/\d+/} ; => false
```
```
prefix? "hello" 'h' ; => true
```
#### `render` (alias: `~` - infix: false)
render template with |string| interpolation
##### Arguments
- `template` (:string,:literal,:pathliteral)
##### Options
- `once` (:logical): don't render recursively
- `template` (:logical): render as a template
##### Returns
:string,:nothing
##### Examples
```
x: 2
greeting: "hello"
print ~"|greeting|, your number is |x|" ; hello, your number is 2
```
#### `replace`
replace every matched substring/s with given replacement string and return result
##### Arguments
- `string` (:string,:literal,:pathliteral)
- `match` (:string,:regex,:block)
- `replacement` (:string,:block)
##### Returns
:string,:nothing
##### Examples
```
replace "hello" "l" "x" ; => "hexxo"
```
```
str: "hello"
replace 'str "l" "x" ; str: "hexxo"
```
```
replace "hello" ["h" "l"] "x" ; => "xexxo"
replace "hello" ["h" "o"] ["x" "z"] ; => "xellz"
```
#### `strip`
strip whitespace from given string
##### Arguments
- `string` (:string,:literal,:pathliteral)
##### Options
- `start` (:logical): strip leading whitespace
- `end` (:logical): strip trailing whitespace
##### Returns
:string,:nothing
##### Examples
```
str: " Hello World "
print ["strip all:" ">" strip str "<"]
print ["strip leading:" ">" strip.start str "<"]
print ["strip trailing:" ">" strip.end str "<"]
; strip all: > Hello World <
; strip leading: > Hello World <
; strip trailing: > Hello World <
```
#### `suffix?`
check if string ends with given suffix
##### Arguments
- `string` (:string)
- `suffix` (:char,:string,:regex)
##### Returns
:logical
##### Examples
```
suffix? "hello" "lo" ; => true
suffix? "boom" "lo" ; => false
```
```
suffix? "hello" {/\w/} ; => true
suffix? "world" {/\d/} ; => false
```
```
suffix? "hello" 'o' ; => true
suffix? "world" 'o' ; => false
```
#### `translate`
takes a dictionary of translations and replaces each instance sequentially
##### Arguments
- `string` (:string,:literal,:pathliteral)
- `translations` (:dictionary)
##### Returns
:string,:nothing
##### Examples
```
print translate "the brown fox jumped over the lazy dog" #[
brown: "green"
fox: "wolf"
jumped:"flew"
dog:"cat"
]
; the green wolf flew over the lazy cat
```
#### `truncate`
truncate string at given length
##### Arguments
- `string` (:string,:literal,:pathliteral)
- `cutoff` (:integer)
##### Options
- `with` (:string): use given filler
- `preserve` (:logical): preserve word boundaries
##### Returns
:string,:nothing
##### Examples
```
str: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse erat quam"
truncate str 30
; => "Lorem ipsum dolor sit amet, con..."
truncate.preserve str 30
; => "Lorem ipsum dolor sit amet,..."
truncate.with:"---" str 30
; => "Lorem ipsum dolor sit amet, con---"
truncate.preserve.with:"---" str 30
; => "Lorem ipsum dolor sit amet,---"
```
#### `upper`
convert given string to uppercase
##### Arguments
- `string` (:char,:string,:literal,:pathliteral)
##### Returns
:char,:string,:nothing
##### Examples
```
print upper "hello World, 你好!" ; "HELLO WORLD, 你好!"
```
```
str: "hello World, 你好!"
upper 'str ; str: "HELLO WORLD, 你好!"
```
```
ch: 'a'
upper ch
; => 'A'
```
#### `upper?`
check if given string is uppercase
##### Arguments
- `string` (:char,:string)
##### Returns
:logical
##### Examples
```
upper? "Ñ" ; => true
upper? "x" ; => false
upper? "Hello World" ; => false
upper? "HELLO" ; => true
```
```
upper? 'A' ; => true
upper? 'a' ; => false
```
#### `whitespace?`
check if given string consists only of whitespace
##### Arguments
- `string` (:char,:string)
##### Returns
:logical
##### Examples
```
whitespace? "hello" ; => false
whitespace? " " ; => true
whitespace? "\n \n" ; => true
whitespace? "" ; => false
```
```
whitespace? ' ' ; => true
whitespace? '\n' ; => true
whitespace? 'a' ; => false
```
#### `wordwrap`
word wrap a given string
##### Arguments
- `string` (:string,:literal,:pathliteral)
##### Options
- `at` (:integer): use given max line width (default: 80)
##### Returns
:string
##### Examples
```
print wordwrap {Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget mauris non justo mattis dignissim. Cras in lobortis felis, id ultricies ligula. Curabitur egestas tortor sed purus vestibulum auctor. Cras dui metus, euismod sit amet suscipit et, cursus ullamcorper felis. Integer elementum condimentum neque, et sagittis arcu rhoncus sed. In luctus congue eros, viverra dapibus mi rhoncus non. Pellentesque nisl diam, auctor quis sapien nec, suscipit aliquam velit. Nam ac nisi justo.}
; Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget mauris non
; justo mattis dignissim. Cras in lobortis felis, id ultricies ligula. Curabitur
; egestas tortor sed purus vestibulum auctor. Cras dui metus, euismod sit amet
; suscipit et, cursus ullamcorper felis. Integer elementum condimentum neque, et
; sagittis arcu rhoncus sed. In luctus congue eros, viverra dapibus mi rhoncus
; non. Pellentesque nisl diam, auctor quis sapien nec, suscipit aliquam velit. Nam
; ac nisi justo.
```
```
print wordwrap.at: 10 "one two three four five six seven eight nine ten"
; one two
; three four
; five six
; seven
; eight nine
; ten
```
### System
Functions and helpers for interacting with the operation system and shell
----
The System module provides access to operating system functionality, environment variables, process management, and system information.
#### Key Concepts
- Environment variable access
- System information retrieval
- Process execution and management
- Command-line argument handling
- Configuration management
#### Basic Usage
##### System Information
```arturo
; get system information
print ["OS:" sys\os]
print ["CPU Arch:" sys\cpu\arch]
print ["CPU Cores:" sys\cpu\cores]
print ["Endianness:" sys\cpu\endian]
print ["Hostname:" sys\hostname]
; OS: macos
; CPU Arch: amd64
; CPU Cores: 8
; Endianness: little
; Hostname: drkameleons-MBP.home
; get process information
proc: process
print ["PID:" proc\id]
; PID: 92123
```
##### Environment Variables
```arturo
; access environment variables
vars: env
print ["PATH:" env\PATH]
print ["HOME:" env\HOME]
; check specific variable
if key? env 'ARTURO_HOME ->
print ["Arturo home:" env\ARTURO_HOME]
```
##### Command Execution
```arturo
; simple command execution
result: execute "ls -l"
print result
; with arguments as block
files: execute.args:["-l" "-a"] "ls"
; get exit code
status: execute.code "some_command"
if status <> 0 ->
print "Command failed!"
; asynchronous execution
pid: execute.async "long_running_process"
print ["Started process:" pid]
; direct shell execution
execute.directly "echo 'hello' > output.txt"
```
> [!TIP] Use `execute.code` when you need to check if a command succeeded, and `execute.async` for long-running processes that shouldn't block.
##### Command-line Arguments
```arturo
; access command line arguments
arg ; get raw arguments list as a block
; arg\0 -> first argument
; arg\1 -> second argument, etc...
inspect args
; with: -a --boom --c:123 "one"
;
; [ :dictionary
; a : true :logical
; boom : true :logical
; c : 123 :integer
; values : [ :block
; one :string
; ]
; ]
```
#### Common Patterns
##### Process Management
```arturo
define :processManager [
start: function [command][
pid: execute.async command
print ["Started process:" pid]
return pid
]
stop: function [pid][
terminate pid
print ["Terminated process:" pid]
]
stopWithCode: function [pid code][
terminate.code:code pid
print ["Terminated process:" pid "with code:" code]
]
]
processManager: to :processManager []!
; let's start another Arturo process
pid: processManager\start sys\binary
pause 1000
processManager\stop pid
```
##### Configuration Management
```arturo
; example configuration helper
getConfig: function [key defaultValue][
if key? config key ->
return config\[key]
return defaultValue
]
; usage
port: getConfig 'server_port 8080
host: getConfig 'server_host "localhost"
```
##### Path Management
```arturo
; get path information
print ["Current dir:" path\current]
print ["Home dir:" path\home]
print ["Temp dir:" path\temp]
```
##### System Checks
```arturo
; check for administrator/root privileges
if superuser? ->
print "Running with elevated privileges"
; check if running as standalone script
if standalone? ->
print "Running as standalone script"
; forcefully exit
exit
```
----
#### `arg`
get command-line arguments as a list
##### Returns
:block
##### Examples
```
; called with no parameters
arg ; => []
; called with: 1 two 3
arg ; => ["1" "two" "3"]
```
#### `args`
get all command-line arguments parsed as a dictionary
##### Returns
:dictionary
##### Examples
```
; called with: 1 two 3
args
; => #[
; 1
; "two"
; 3
; ]
```
```
; called with switches: -c -b
args
; => #[
; c : true
; b : true
; values: []
; ]
; called with switches: -c -b and values: 1 two 3
args
; => #[
; c : true
; b : true
; values: [1 "two" 3]
; ]
```
```
; called with named parameters: -c:2 --name:newname myfile.txt
args
; => #[
; c : 2
; name : "newname"
; values: ["myfile.txt"]
; ]
```
#### `config`
get local or global configuration
##### Returns
:store
##### Examples
```
; `config` searches for `config.art` into your current directory.
; if not found, it returns from `~/.arturo/stores/config.art`
config
; => []
; `config.art` is empty at first, but we can change this manually
write.append path\home ++ normalize ".arturo/stores/config.art"
"language: {Arturo}"
config
; => []
; this stills empty, but now try to relaunch Arturo:
exit
```
```
config
; => [language:Arturo]
```
#### `env`
get environment variables
##### Returns
:dictionary
##### Examples
```
print env\SHELL
; /bin/zsh
print env\HOME
; /Users/drkameleon
print env\PATH
; /Users/drkameleon/.arturo/bin:/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
#### `execute`
execute given shell command
##### Arguments
- `command` (:string)
##### Options
- `args` (:block): use given command arguments
- `async` (:logical): execute asynchronously as a process and return id
- `code` (:logical): return process exit code
- `directly` (:logical): execute command directly, as a shell command
##### Returns
:string,:dictionary
##### Examples
```
print execute "pwd"
; /Users/admin/Desktop
split.lines execute "ls"
; => ["tests" "var" "data.txt"]
```
```
execute.args: ["-s"] "ls"
; => total 15
; 0 aoc
; 0 architectures
; 4 bundle
; 0 cave
; 4 cmd.c
; 1 expr.art
; 0 galilee
; 4 generic_klist.c
; 1 jquery.js
; 0 shell
; 1 test.art
```
```
execute.code "ls"
; => [output:aoc
; architectures
; bundle
; cave
; cmd.c
; expr.art
; galilee
; generic_klist.c
; jquery.js
; shell
; test.art
; code:0]
```
```
; This prints the output directly
; And only returns the exit code.
execute.code.directly "ls"
aoc bundle cmd.c galilee jquery.js test.art
architectures cave expr.art generic_klist.c shell
=> 0
```
#### `exit`
exit program
##### Returns
:nothing
##### Examples
```
exit ; (terminates the program)
```
#### `panic`
exit program with error message
##### Arguments
- `message` (:string)
##### Options
- `code` (:integer): return given exit code (default: 1)
- `unstyled` (:logical): don't use default error template
##### Returns
:logical
##### Examples
```
panic.unstyled "oops! that was wrong"
; quits with the default exit code (= 1) and
; just outputs a simple - unformatted - message
```
```
panic.code:0 "something went terribly wrong. quitting..."
; quits without an error code but still
; prints a properly formatted error with the given message
```
#### `path`
get path information
##### Returns
:dictionary
##### Examples
```
path
; => [current:C:\Users\me\my-proj home:C:\Users\me\ temp:C:\Users\me\AppData\Local\Temp\
```
#### `pause`
pause program's execution for the given amount of time
##### Arguments
- `time` (:integer,:quantity)
##### Returns
:nothing
##### Examples
```
print "wait a moment"
pause 1000 ; sleeping for 1000ms = one second
print "done. let's continue..."
```
```
print "waiting for 2 seconds"
pause 2:s ; let's sleep for a while
print "done!"
```
#### `process`
get information on current process/program
##### Returns
:dictionary
##### Examples
```
print process\id
; 78046
inspect process
; [ :dictionary
; id : 78046 :integer
; memory : [ :dictionary
; occupied : 1783104 :integer
; free : 360448 :integer
; total : 2379776 :integer
; max : 2379776 :integer
; ]
; ]
```
#### `script`
get embedded information about the current script
##### Returns
:dictionary
##### Examples
```
;; author: {Me :P}
;; year: 2023
;; license: Some License
;;
;; description: {
;; This is an example of documentation.
;;
;; You can get this by using ``script``.
;; }
;;
;; hint: {
;; Notice that we use `;;` for documentation,
;; while the single `;` is just a comment,
;; that will be ignored.
;; }
;;
;; export: [
;; 'myFun
;; 'otherFun
;; 'someConst
;; ]
;;
inspect script
; [ :dictionary
; author : Me :P :string
; year : 2023 :integer
; license : [ :block
; Some :string
; License :string
; ]
; description : This is an example of documentation.
;
; You can get this by using ``script``. :string
; hint : Notice that we use `;;` for documentation,
; while the single `;` is just a comment,
; that will be ignored. :string
; export : [ :block
; myFun :string
; otherFun :string
; someConst :string
; ]
; ]
```
#### `superuser?`
check if current user has administrator/root privileges
##### Returns
:logical
##### Examples
```
; when running as root
superuser? ; => true
; when running as regular user
superuser? ; => false
```
#### `sys`
get current system information
##### Returns
:dictionary
##### Examples
```
inspect sys
; [ :dictionary
; author : Yanis Zafirópulos :string
; copyright : (c) 2019-2026 :string
; version : 0.10.0-dev+3454 :version
; codename : :string
; built : [ :date
; hour : 12 :integer
; minute : 56 :integer
; second : 12 :integer
; nanosecond : 0 :integer
; day : 13 :integer
; Day : Tuesday :string
; days : 12 :integer
; month : 1 :integer
; Month : January :string
; year : 2026 :integer
; utc : -3600 :integer
; ]
; deps : [ :dictionary
; gmp : 6.3.0 :version
; mpfr : 4.2.1 :version
; sqlite : 3.43.2 :version
; ]
; binary : /Users/drkameleon/.arturo/bin/arturo :string
; cpu : [ :dictionary
; arch : amd64 :literal
; endian : little :literal
; cores : 8 :integer
; ]
; os : macos :literal
; hostname : drkameleons-MacBook-Pro.local :string
; release : full :literal
; ]
```
#### `terminate`
kill process with given id
##### Arguments
- `id` (:integer)
##### Options
- `code` (:integer): use given error code
##### Returns
:nothing
##### Examples
```
; start process
pid: execute.async "someProcessThatDoesSomethingInTheBackground"
; wait for 5 seconds
pause 5000
; terminate background process
terminate pid
```
### Types
Built-in types, custom user types/objects and related helpers
----
The Types module provides the foundation for Arturo's type system, including type checking, custom type definitions, and object-oriented programming capabilities.
#### Key Concepts
- Basic type checking
- Custom type definitions
- Object creation and manipulation
- Type conversion
- Magic methods for operator overloading
- Inheritance and composition
#### Basic Usage
##### Type Checking
```arturo
; basic type checks
print type 42 ; :integer
print type "hello" ; :string
print type [1 2 3] ; :block
; check specific type
print integer? 42 ; true
print string? 42 ; false
; check if value is of type
print is? :integer 42 ; true
print is? :string "hi" ; true
```
##### Custom Types
```arturo
; define new type
define :person [
; constructor
init: method [name age][
this\name: name
this\age: age
]
; string representation
string: method [][
~{|this\name| (|this\age| years old)}
]
]
; create instance
john: to :person ["John" 38]!
print john
; John (38 years old)
```
> [!TIP] Within methods, you can use `\field` as a shortcut for `this\field`. This makes code more concise and readable. For example:
> ```arturo
> string: method [][
> ; these are equivalent:
> print this\name ; explicit
> print \name ; shortcut
> ]
> ```
##### Inheritance
```arturo
; base type
define :animal [
init: method [species][
\species: species
]
speak: method [][
print "..."
]
]
; derived type
define :dog is :animal [
init: method [name][
; call parent constructor
super "canis"
\name: name
]
speak: method [][
print "woof!"
]
]
; usage
fido: to :dog ["Fido"]!
print fido\species ; canis
fido\speak ; woof!
```
##### Type Conversions
```arturo
; basic conversions
str: to :string 42 ; "42"
num: to :integer "42" ; 42
flt: to :floating "3.14" ; 3.14
; with custom format
date: to :date .format:"yyyy-MM-dd" "2024-01-15"
```
#### Magic Methods
Magic methods allow you to customize how your types behave with various operations.
| Method | Arguments | Description | Example Use |
|--------|-----------|-------------|-------------|
| `init` | any | Constructor | Object initialization |
| `get` | field | Field access | `obj\field` |
| `set` | field, value | Field assignment | `obj\field: value` |
| `changing` | - | Before change hook | Pre-modification |
| `changed` | - | After change hook | Post-modification |
| `compare` | that | Custom comparison | Sort ordering |
| `equal?` | that | Equality check | `obj1 = obj2` |
| `less?` | that | Less than | `obj1 < obj2` |
| `greater?` | that | Greater than | `obj1 > obj2` |
| `add` | that | Addition | `obj1 + obj2` |
| `sub` | that | Subtraction | `obj1 - obj2` |
| `mul` | that | Multiplication | `obj1 * obj2` |
| `div` | that | Division | `obj1 / obj2` |
| `fdiv` | that | Float division | `obj1 // obj2` |
| `mod` | that | Modulo | `obj1 % obj2` |
| `pow` | that | Power | `obj1 ^ obj2` |
| `inc` | - | Increment | `inc 'obj` |
| `dec` | - | Decrement | `dec 'obj` |
| `neg` | - | Negation | `neg obj` |
| `key?` | key | Key existence | `key? obj "field"` |
| `contains?` | what | Contains check | `contains? obj item` |
| `append` | value | Add item | `'obj ++ value` |
| `remove` | value | Remove item | `'obj -- value` |
| `string` | - | String conversion | `to :string obj` |
| `integer` | - | Integer conversion | `to :integer obj` |
| `floating` | - | Float conversion | `to :floating obj` |
| `rational` | - | Rational conversion | `to :rational obj` |
| `complex` | - | Complex conversion | `to :complex obj` |
| `quantity` | - | Quantity conversion | `to :quantity obj` |
| `logical` | - | Logical conversion | `to :logical obj` |
| `block` | - | Block conversion | `to :block obj` |
| `dictionary` | - | Dictionary conversion | `to :dictionary obj` |
> [!TIP] Magic methods are optional - implement only those that make sense for your type's behavior. Also, remember that when implementing magic methods, they affect how your type behaves with standard operators and functions throughout Arturo.
#### Common Patterns
##### Implementing Comparable Objects
```arturo
define :score [
init: method [value][
\value: value
]
; custom comparison
compare: method [that][
if \value < that\value -> return neg 1
if \value > that\value -> return 1
return 0
]
]
; usage
scores: @[
to :score [42]!
to :score [18]!
to :score [73]!
]
print sort scores
; [value:18] [value:42] [value:73]
```
> [!TIP] For simple comparisons based on a single field, you can use the sortable helper instead of implementing a full `compare` method. In the above example, for instance:
> ```arturo
> ;...
> compare: sortable 'value
> ;...
> ```
##### Custom Collections
```arturo
define :stack [
init: method [][
\items: []
]
push: method [item][
'this\items ++ item
]
pop: method [][
if empty? \items -> return null
return pop 'this\items
]
; custom conversion
string: method [][
~{Stack(|size \items| items)}
]
; support iteration
contains?: method [item][
contains? \items item
]
]
; usage
s: to :stack []!
s\push 1
s\push 2
print s\pop ; 2
```
##### Property Change Notifications
```arturo
define :observable [
init: method [value][
\value: value
\observers: []
]
changing: method [][
loop \observers 'obs [
obs\beforeChange \value
]
]
changed: method [][
loop observers 'obs [
obs\afterChange \value
]
]
addObserver: method [observer][
'this\observers ++ observer
]
]
; usage
value: to :observable [42]!
value\addObserver #[
beforeChange: function [val][
print ["About to change from:" val]
]
afterChange: function [val][
print ["Changed to:" val]
]
]
```
----
#### `attribute?`
checks if given value is of type :attribute
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
attribute? first [.something x]
; => true
```
#### `attributeLabel?`
checks if given value is of type :attributeLabel
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
attributeLabel? first [.something: x]
; => true
```
#### `binary?`
checks if given value is of type :binary
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
binary? to :binary "string"
; => true
```
#### `block?`
checks if given value is of type :block
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print block? [1 2 3] ; true
print block? #[name: "John"] ; false
print block? "hello" ; false
print block? 123 ; false
```
#### `bytecode?`
checks if given value is of type :bytecode
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
code: [print 1 + 2]
bcode: to :bytecode code
print bytecode? bcode ; true
print bytecode? code ; false
```
#### `char?`
checks if given value is of type :char
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print char? 'a' ; true
print char? 123 ; false
```
#### `color?`
checks if given value is of type :color
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print color? #FF0000 ; true
print color? #green ; true
print color? 123 ; false
```
#### `complex?`
checks if given value is of type :complex
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
c: to :complex [1 2]
print complex? c ; true
print complex? 123 ; false
```
#### `constructor`
create a type constructor method automatically using given arguments
##### Arguments
- `arguments` (:literal,:block)
##### Returns
:method
##### Examples
```
define :cat [
init: constructor [nick :string]
meow: method [][
print [this\nick ":" "'meow!'"
]
]
snowflake: to :cat [15]
; Assertion | [is? :string nick]
; error |
snowflake: to :cat ["Snowflake"]
snowflake\meow
; Snowflake: 'meow!'
```
#### `database?`
checks if given value is of type :database
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
database? open "my.db"
; => true
```
#### `date?`
checks if given value is of type :date
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print date? now ; true
print date? "hello" ; false
```
#### `define`
define new type with given prototype
##### Arguments
- `type` (:type)
- `prototype` (:type,:dictionary,:block)
##### Returns
:nothing
##### Examples
```
; define a simple type
define :person [name surname]
; and create an object
someone: to :person ["John" "Doe"]
print someone ; [name:John surname:Doe]
```
```
; define a simple type
define :person [name surname]
; and create an object
; using a dictionary with field values
someone: to :person #[surname: "Doe", name: "John"]
print someone ; [name:John surname:Doe]
```
```
; define a new type
; with custom constructor
define :person [
init: method [name, surname, age][
this\name: name
this\surname: surname
this\dob: now\year - age
]
]
; create an object
jd: to :person ["John" "Doe" 38]
print jd ; [name:John surname:Doe dob:1986]
```
```
; define type with overloaded
; magic methods
define :natural [
init: constructor [value]
; custom `+` overload
add: method [x :integer :natural][
(integer? x)? -> this\value + x
-> to :natural @[this\value + x\value]
]
; custom `to :string` overload
string: method [][
to :string this\value
]
]
; create two new 'natural' numbers
n1: to :natural @[3]
n2: to :natural @[5]
print n1 + n2 ; 8
```
#### `defined?`
checks if given type is defined
##### Arguments
- `type` (:type,:string,:word,:literal)
##### Returns
:logical
##### Examples
```
defined? :cat
; => false
defined? "cat"
; => false
defined? 'cat
; => false
define :cat [
init: constructor [name :string age :integer]
]
defined? :cat
; => true
defined? "cat"
; => true
defined? 'cat
; => true
defined? :dog
; => false
```
#### `dictionary?`
checks if given value is of type :dictionary
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print dictionary? #[name: "John"] ; true
print dictionary? 123 ; false
```
#### `error?`
checks if given value is of type :error
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
error? try -> throw "Some Error"
; => true
```
#### `errorKind?`
checks if given value is of type :errorKind
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
errorKind? to :errorKind "Some error kind"
; => true
errorKind? genericError
; => true
```
#### `floating?`
checks if given value is of type :floating
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print floating? 3.14 ; true
print floating? 123 ; false
print floating? "hello" ; false
```
#### `function?`
checks if given value is of type :function
##### Arguments
- `value` (:any)
##### Options
- `builtin` (:logical): check if, internally, it's a built-in
##### Returns
:logical
##### Examples
```
print function? $[x][2*x] ; true
print function? var 'print ; true
print function? "print" ; false
print function? 123 ; false
```
```
f: function [x][x+2]
function? var'f ; => true
function? var'print ; => true
function?.builtin var'f ; => false
function?.builtin var'print ; => true
```
#### `inline?`
checks if given value is of type :inline
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
inline? first [(something) x]
; => true
```
#### `integer?`
checks if given value is of type :integer
##### Arguments
- `value` (:any)
##### Options
- `big` (:logical): check if, internally, it's a bignum
##### Returns
:logical
##### Examples
```
print integer? 123 ; true
print integer? "hello" ; false
```
```
integer?.big 123 ; => false
integer?.big 12345678901234567890 ; => true
```
#### `is`
get derivative type with given prototype
##### Arguments
- `type` (:type)
- `prototype` (:dictionary,:block)
##### Returns
:type
##### Examples
```
define :animal [
init: constructor [nick :string age :integer]
speak: method [][
print "..."
]
]
define :fish is :animal []
define :cat is :animal [
speak: method [][
print [~"|this\nick|:" "'meow!'"]
]
]
a: to :cat []
; >> Runtime | cannot initialize object of type :cat
; error | wrong number of parameters: 0
; | expected: 2 (nick, age)
scooby: to :animal ["Scooby" 7]
scooby\speak
; ...
bubble: to :fish ["Bubble" 1]
bubble\speak
; ...
snowflake: to :cat ["Snowflake" 3]
snowflake\speak
; Snowflake: 'meow!'
```
#### `is?`
check whether value is of given type
##### Arguments
- `type` (:type,:block)
- `value` (:any)
##### Returns
:logical
##### Examples
```
is? :string "hello" ; => true
is? :block [1 2 3] ; => true
is? :integer "boom" ; => false
is? [:string] ["one" "two"] ; => true
is? [:integer] [1 "two] ; => false
```
#### `label?`
checks if given value is of type :label
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
label? first [something: x]
; => true
```
#### `literal?`
checks if given value is of type :literal
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print literal? 'x ; true
print literal? "x" ; false
print literal? 123 ; false
```
#### `logical?`
checks if given value is of type :logical
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print logical? true ; true
print logical? false ; true
print logical? maybe ; true
```
```
print logical? 1=1 ; true
print logical? 123 ; false
```
#### `method?`
checks if given value is of type :method
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
greet: method [name :string][print ~"How are you, |name|?"]
reply: function [name :string][print ~"Hi, I'm fine |name|!"]
method? greet
; => true
method? reply
; => false
```
#### `null?`
checks if given value is of type :null
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print null? null ; true
print null? ø ; true
print null? 123 ; false
```
#### `object?`
checks if given value is a custom-type object
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
define :person [name,surname][]
x: to :person ["John","Doe"]
print object? x ; true
print object? "hello" ; false
```
#### `path?`
checks if given value is of type :path
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
path? first [a\b\c x]
; => true
```
#### `pathLabel?`
checks if given value is of type :pathLabel
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
pathLabel? first [a\b\c: x]
; => true
```
#### `pathLiteral?`
checks if given value is of type :pathLiteral
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
pathLiteral? 'a\b\c
; => true
```
#### `quantity?`
checks if given value is of type :quantity
##### Arguments
- `value` (:any)
##### Options
- `big` (:logical): check if, internally, it's a bignum
##### Returns
:logical
##### Examples
```
print quantity? 1:m ; true
print quantity? 2:yd2 ; true
print quantity? 3 ; false
```
#### `range?`
checks if given value is of type :range
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
r: 1..3 ; r: [1 2 3]
print range? r ; true
print range? [1 2 3] ; false
```
#### `rational?`
checks if given value is of type :rational
##### Arguments
- `value` (:any)
##### Options
- `big` (:logical): check if, internally, it's a bignum
##### Returns
:logical
##### Examples
```
r: to :rational 3.14 ; r: 157/50
print rational? r ; true
print rational? 3.14 ; false
```
#### `regex?`
checks if given value is of type :regex
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print regex? {/[a-z]+/} ; true
print regex? "[a-z]+" ; false
print regex? 123 ; false
```
#### `socket?`
checks if given value is of type :socket
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
server: listen 18966
socket? server
; => true
```
#### `sortable`
create a sort descriptor method automatically using given type field
##### Arguments
- `field` (:literal)
##### Returns
:method
##### Examples
```
define :cat [
init: constructor [name :string age :integer]
compare: sortable 'age
]
snowflake: to :cat ["Snowflake" 3]
smith: to :cat ["Smith" 6]
compare snowflake smith
; => -1
snowflake < smith
; => true
```
#### `store?`
checks if given value is of type :store
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
store? config
; => true
```
#### `string?`
checks if given value is of type :string
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print string? "x" ; true
print string? 'x ; false
print string? 123 ; false
```
#### `symbol?`
checks if given value is of type :symbol
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
symbol? first [+ x]
; => true
```
#### `symbolLiteral?`
checks if given value is of type :symbolLiteral
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
symbolLiteral? '++
; => true
```
#### `to`
convert value to given type
##### Arguments
- `type` (:type,:block)
- `value` (:any)
##### Options
- `format` (:string): use given format (for dates or floating-point numbers)
- `unit` (:string,:literal): use given unit (for quantities)
- `intrepid` (:logical): convert to bytecode without error-line tracking
- `hsl` (:logical): convert HSL block to color
- `hsv` (:logical): convert HSV block to color
##### Returns
:any
##### Examples
```
to :integer "2020" ; 2020
to :integer 'A' ; 65
to :char 65 ; 'A'
to :integer 4.3 ; 4
to :floating 4 ; 4.0
to :complex [1 2] ; 1.0+2.0i
; make sure you're using the `array` (`@`) converter here, since `neg` must be evaluated first
to :complex @[2.3 neg 4.5] ; 2.3-4.5i
to :rational [1 2] ; 1/2
to :rational @[neg 3 5] ; -3/5
to :boolean 0 ; false
to :boolean 1 ; true
to :boolean "true" ; true
to :literal "symbol" ; 'symbol
```
```
to :string 2020 ; "2020"
to :string 'symbol ; "symbol"
to :string :word ; "word"
to :string .format:"dd/MM/yy" now
; 22/03/21
to :string .format:".2f" 123.12345
; 123.12
```
```
to :block "one two three" ; [one two three]
do to :block "print 123" ; 123
```
```
to :date 0 ; => 1970-01-01T01:00:00+01:00
print now ; 2021-05-22T07:39:10+02:00
to :integer now ; => 1621661950
to :date .format:"dd/MM/yyyy" "22/03/2021"
; 2021-03-22T00:00:00+01:00
```
```
to [:string] [1 2 3 4]
; ["1" "2" "3" "4"]
to [:char] "hello"
; ['h' 'e' 'l' 'l' 'o']
```
```
define :person [name surname age][]
to :person ["John" "Doe" 35]
; [name:John surname:Doe age:35]
```
```
to :color [255 0 10]
; => #FF000A
to :color .hsl [255 0.2 0.4]
; => #5C527A
```
#### `type`
get type of given value
##### Arguments
- `value` (:any)
##### Returns
:type
##### Examples
```
print type 18966 ; :integer
print type "hello world" ; :string
```
#### `type?`
checks if given value is of type :type
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print type? :string ; true
print type? "string" ; false
print type? 123 ; false
```
#### `unit?`
checks if given value is of type :unit
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
unit? `m
; => true
```
#### `version?`
checks if given value is of type :version
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
print version? 1.0.2 ; true
print version? "1.0.2" ; false
```
#### `word?`
checks if given value is of type :word
##### Arguments
- `value` (:any)
##### Returns
:logical
##### Examples
```
word? first [something x]
; => true
```
### Ui
UI- and webview-related helpers
----
The UI module provides functionality for creating basic desktop interactions, managing clipboard content, and displaying web-based user interfaces through webviews.
#### Key Concepts
- System dialogs and alerts
- Clipboard operations
- Web-based interfaces via webview
- File selection dialogs
- User notifications
#### Basic Usage
##### System Dialogs
```arturo
; basic popup
result: popup "Warning" "Are you sure?"
; different dialog types
popup.info "Info" "Operation complete"
popup.warning "Warning" "Low disk space"
popup.error "Error" "Connection failed"
; with different buttons
response: popup.yesNo "Question" "Save changes?"
response: popup.okCancel "Confirm" "Proceed?"
response: popup.retryCancel "Failed" "Try again?"
```
##### System Notifications
```arturo
; basic notification
alert "Title" "Message"
; with different types
alert.info "Info" "Download complete"
alert.warning "Warning" "Battery low"
alert.error "Error" "Update failed"
```
##### File Selection
```arturo
; select file
file: dialog "Select file"
; select folder
folder: dialog.folder "Select folder"
; with starting path
config: dialog .path: "~/Documents" "Select config"
```
##### Clipboard Operations
```arturo
; set clipboard content
clip "text to copy"
; get clipboard content
text: unclip
print ["Clipboard contains:" text]
```
##### WebView Interface
```arturo
; basic webview with HTML content
webview {
Hello World
}
; with custom window properties
webview
.title:"My App"
.width: 800
.height: 600
.fixed: true
.debug
{!html
Custom Window
}
```
> [!TIP] If you are using a text editor that supports this syntax (e.g. VSCode), using `!html` in front of `{..}`-enclosed blocks will enable proper HTML highlighting.
> [!TIP] WebView's `.debug` attribute opens Chrome's DevTools for easier development and debugging.
#### Common Patterns
##### Interactive Dialog Flow
```arturo
getUserInput: function [default][
response: popup.okCancel "Input needed" "Use default settings?"
if response ->
return default
file: dialog "Select custom config"
if empty? file ->
return default
return file
]
; usage
config: getUserInput "config.ini"
```
> [!NOTE] Dialog or popup buttons, behavior and general look'n'feel might vary slightly depending on the operating system.
##### Clipboard Manager
```arturo
define :clipboardManager [
history: []
save: method [text][
clip text
\history: \history ++ text
]
last: method [][
if empty? \history ->
return null
return last \history
]
clear: method [][
clip ""
\history: []
]
]
; usage
clipboardManager: to :clipboardManager []!
clipboardManager\save "important text"
previous: clipboardManager\last
```
----
#### `alert`
show notification with given title and message
##### Arguments
- `title` (:string)
- `message` (:string)
##### Options
- `info` (:logical): show informational notification
- `warning` (:logical): show notification as a warning
- `error` (:logical): show notification as an error
##### Returns
:nothing
##### Examples
```
alert "Hello!" "This is a notification..."
; show an OS notification without any styling
alert.error "Ooops!" "Something went wrong!"
; show an OS notification with an error message
```
#### `clip`
set clipboard content to given text
##### Arguments
- `content` (:string)
##### Returns
:nothing
##### Examples
```
clip "this is something to be pasted into the clipboard"
```
#### `dialog`
show a file selection dialog and return selection
##### Arguments
- `title` (:string)
##### Options
- `folder` (:logical): select folders instead of files
- `path` (:string): use given starting path
##### Returns
:string
##### Examples
```
selectedFile: dialog "Select a file to open"
; gets full path for selected file, after dialog closes
```
```
selectedFolder: dialog.folder "Select a folder"
; same as above, only for folder selection
```
#### `popup`
show popup dialog with given title and message and return result
##### Arguments
- `title` (:string)
- `message` (:string)
##### Options
- `info` (:logical): show informational popup
- `warning` (:logical): show popup as a warning
- `error` (:logical): show popup as an error
- `question` (:logical): show popup as a question
- `ok` (:logical): show an OK dialog (default)
- `okCancel` (:logical): show an OK/Cancel dialog
- `yesNo` (:logical): show a Yes/No dialog
- `yesNoCancel` (:logical): show a Yes/No/Cancel dialog
- `retryCancel` (:logical): show a Retry/Cancel dialog
- `retryAbortIgnore` (:logical): show an Abort/Retry/Ignore dialog
- `literal` (:logical): return the literal value of the pressed button
##### Returns
:logical,:literal
##### Examples
```
popup "Hello!" "This is a popup message"
; shows a message dialog with an OK button
; when the dialog is closed, it returns: true
```
```
if popup.yesNo "Hmm..." "Are you sure you want to continue?" [
; a Yes/No dialog will appear - if the user clicks YES,
; then the function will return true; thus we can do what
; we want here
]
```
```
popup.okCancel.literal "Hello" "Click on a button"
; => 'ok (if user clicked OK)
; => 'cancel (if user clicked Cancel)
```
#### `unclip`
get clipboard content
##### Returns
:string
##### Examples
```
; paste something into the clipboard (optionally)
clip "this is something to be pasted into the clipboard"
; now, let's fetch whatever there is in the clipboard
unclip
; => "this is something to be pasted into the clipboard"
```
#### `webview`
show webview window with given url or html source
##### Arguments
- `content` (:string,:literal)
##### Options
- `title` (:string): set window title
- `width` (:integer): set window width
- `height` (:integer): set window height
- `fixed` (:logical): window shouldn't be resizable
- `maximized` (:logical): start in maximized mode
- `fullscreen` (:logical): start in fullscreen mode
- `borderless` (:logical): show as borderless window
- `topmost` (:logical): set window as always-on-top
- `debug` (:logical): add inspector console
- `on` (:dictionary): execute code on specific events
- `inject` (:string): inject JS code on webview initialization
##### Returns
:nothing
##### Examples
```
webview "Hello world!"
; (opens a webview windows with "Hello world!")
```
```
webview .width: 200
.height: 300
.title: "My webview app"
; (opens a webview with given attributes)
---
This is my webpage
This is some content
```