# Bee Data Types

Data types represent abstract domains of values. In other words, data type represent constrain rules that can be used to validate a particular data value. Data"type" is an attribute of any data element. In Bee there is no data element without this attribute.

Bee use 2 kind of data types:

#### Usability:

• Without data types, a programming language is a dynamic language. We think dynamic typing is more fragile and prone to errors than the static typing. Bee language is strongly typed language that uses type inference. That means any data is constrained by fixed "data type" rules.

• Bee has predefined data types. You can create new data types based on predefined types using a special declaration. You can create sub-types or composite types having new constraints and rules that can improve data validation further.

• A data type can be manipulated using rules and operators. You can have a variable of type: Type. To detect a data type of any variable you can use function type(). Therefore type(type_variable) = Type.

## Primitive Types

Primitive data types are defined using one capital letter.

Alias Code Description + Default representation
Logic L Numeric enumeration of two values: 0 = False, 1 = True
Alpha A Alpha-numeric code point E-ASCII ('0'..'9') ('a'..'Z')
Binary B Binary number on 8 bit, max: 0b11111111 (0..255) (0..0xFF)
Unicode U Unsigned code point on 32 bit, max: U-FFFFFFFF (UTF32)
Rational Q Fix point representation number: like 1/2. Notation: Q(14,17)
Natural N Unsigned large positive integer 64 bit [0..+]
Integer Z Signed large integer 64 bit [-..+] Z(64)
Real R Double precision float 64 bit (-..+) R(64)

#### Notes:

• Each data type has a default representation for literal, print & output,
• Output representation can be establish using a format template,
• Using print with primitive type will create a specific representation,
• Precision can be specified in parenthesis after the type: Z(32) = 32 bit integer,
• Primitive data types are values allocated on the stack or in the registry.

## Constant Literals

These are symbolic representations for primitive data types:

Example Type Literal characters
'a' A (+-) & (0..9) & (a..z) & (A..Z)
'Ω' U (Δ Λ Φ Γ Ψ Ω Σ Π π ⊥ ǁ α β ɣ ε δ μ ω ...)
"str" S (∀ UTF8)
0b11111111 B (0b) & (0,1)
1234567890 N (0,1,2,3,4,5,6,7,8,9)
+0 Z (-+) & (0,1,2,3,4,5,6,7,8,9)
0xFFFF A (0x) & (0,1,2,3,4,5,6,7,8,9) & ABCDEF
U+FFFF U (U+) & (0,1,2,3,4,5,6,7,8,9) & ABCDEF
U-FFFFFFFF U (U-) & (0,1,2,3,4,5,6,7,8,9) & ABCDEF
0.05 R (-.) & (0,1,2,3,4,5,6,7,8,9)
-1/2 Q (-/) & (0,1,2,3,4,5,6,7,8,9)
1E10 R (-1E)& (0,1,2,3,4,5,6,7,8,9)
1e10 R (-1e)& (0,1,2,3,4,5,6,7,8,9)

note

• primitive types are ordered and can be compared,
• primitive literals are identical to themselves,
• primitive variables are identical to themselves.

## Composite types

Predefined composite types have an alias starting with capital letter:

Alias Type Description
Complex C Double precision pair of double float numbers (9r+9j)
String S UTF8 encoded double quoted string "α β ɣ ε δ μ ω"
Text X Multi-line large block of text ...
Date D "DD/MM/YYYY"
Time T "hh:mm,ms"
Error E Error object: {code, message, line}
File F File handler

#### Notes:

• Composite variables are references to objects;
• Composite variables have variable size;
• Composite variables are allocated on the heap;

## Collection types

Bee define a collection literal using a special notation based on brackets.

delimiter collection types
() List
[] Array / Matrix
{} Ordinal / Set / Hash / Object

#### Notes:

• All collections are also composite types therefore references,
• Collection elements can be references or native types,
• Elements of collection are separated by comma,
• Pair of values in Hash map and Object are separated by columns ":"

## Type declaration

User can define super-types and sub-types using operators ":" and "<:".

``````** declare new type
type Type_Identifier: type_descriptor <: super_type;
** declare variables using new type
make var_name,var_name ... ∈ Type_Identifier;
``````

#### Notes:

• User defined types are starting with capital letter;
• User defined super-types are usually composite types;
• User defined sub-types are usually domains of values;

## Range Type

A range is a notation that designate a sub-set of consecutive integer numbers between two limits: lower limit and upper limit included in round paranthesis and separated by two dots (..) or (!).

#### Syntax:

```Range ::= (min..max);
Range ::= (min.!max); //exclude upper limit
Range ::= (min!.max); //exclude lower limit
```

#### Notes:

• Both limits are included in range by default
• Upper or lower limits can be excluded using "!"
• Range notation can be open at one end or both ends
• Open lower limit is symbolic (-) with no number
• Open upper limit is symbolic (+) with no number

#### Example:

``````#integer domain
rule main():
print (0..5); // 0,1,2,3,4,5
print (0.!5); // 0,1,2,3,4
print (0!.5); // 1,2,3,4,5

pass if  32667 ∈ (0..+); //expect to pass
pass if -32668 ∈ (-..0); //expect to pass
return;
``````

Ranges can use symbols that are ASCII or Unicode. In this case the symbols must be included in single quotes: 'X' or use U+ notation:

#### Example:

``````** sub-type declarations
type Digit:    ('0'..'9')       <: Z;
type Capital:  ('A'..'Z')       <: A;
type Lowercase:('a'..'z')       <: A;
type Latin:    (U+0041..U+FB02) <: U;
rule main():
** following statements should pass
pass if '0' ∈ Digit;
fail if 'x' ∈ Capital;
pass if 'X' ∈ Capital;
pass if 'e' ∈ Latin;
return;
``````

## Domain Type

Domain is very symilar to range except a domain has a ratio. This is the difference, the numbers are not integers, can be fractionar or Q umber.

```Domain ::= (min..max:ratio)  <: Super_Type
```

#### Examples:

``````** generate rational numbers
print (0..1:1/4); // 0/4, 1/4, 2/4, 3/4, 4/4

** generate float numbers
print (0..1:0.25); // 0.00, 0.25, 0.50, 0.75, 1.00
``````

## Constant declarations

Constants are defined identifiers for literal constants.

``````** using explicit type
stow constant_name: constant_literal ∈ type_name;

** using implicit type
stow constant_name:= constant_literal;
``````

#### Notes:

• Constant initial value is assigned using operator ":",
• Constant initial value van be assigned using operator ":=",
• System constants are public and have prefix "\$",
• User defined constants using prefix "." are also public,
• Local constants are possible but they are transient.

#### Example:

``````#symbol constants
stow n: U+2200     ∈ A; //Symbol: ∀
stow n: U-00002200 ∈ U; //Symbol: ∀
``````

#### Note:

• After U+ compiler is expecting 4 hexadecimal symbols;
• After U- compiler is expecting 8 hexadecimal symbols;

## Variable declarations

Variables are defined using keyword make plus one of the operators:

operator purpose
declare variable/element type
: define type | set initial value | pair up operator
:= type inference | share a reference | assign operator
:: deep copy | duplicate object | cloning operator

#### Notes:

• Symbol ":" can be used to initialize one variable at a time,
• Symbol ":" can not accept expressions when is used in declarations,
• Symbol ":" used in declarations require ∈ otherwise you must use ":=",
• Symbol ":" can be used as pair-up operator for arguments and maps.
``````** primitive variable declarations with type
make var_name ∈  type_name; // declaration only type without initial value
make var_name: value ∈  type_name; // declaration with initial value and type

** Variable declaration using type inference
make var_name := expression; //expression ":=" do not require type hint ("∈").

** Multiple variables can be define in one single line using comma separator:
make var1, var2 ... ∈  TypeName;   //default initial values
make var1, var2 ... := Expression; //use type inference for all initial values

** Initialize multiple variables, of the same type (type is required)
make var1:con1, var2:con2 ... ∈ TypeName;
``````

## Modify values

One can modify variables using alter statement.

#### Example:

``````#fragment of code

make a:10, b:0 ∈ Z; // initialize two variables
alter b := a + 1;   // modify b using binding operator :=
alter b += 1;       // modify b using modifier +=
print b;            // expected 12
``````

#### Notes:

• Multiple variables can be modified all at once when separated by comma;
• The alter statement can use operators:
• {":=","::"}
• {"+=","-=","÷=","·=","^=","%="}

#### Examples:

``````** declare a constant
stow pi: 3.14 ∈ R;
** declare multiple variables
make a   ∈ Z; //Integer
make x,y ∈ R; //Double
make q,p ∈ L; //Logic
rule main():
** using modifiers
alter a := 10; //modify value of a := 10
alter a += 1;  //increment value of a := 11
alter a -= 1;  //decrement value of a := 10

** modify two variables using one single constant
alter x, y := 10.5;

** modify two variables using two constants
alter q, p := True, False;

** swapping two variables
alter p, q := q, p;
return;
``````

## Type conversion

When data type mismatch you must perform explicit conversion.

• Explicit conversion is using a symbolic operator: ":>"
• This is unsafe operation. A range check is recommended before conversion;
• Data precision may suffer. Some decimals may be lost;
• If data do not fit in the new type, the overflow exception is raised.

#### Example:

``````make a: 0, b:20 ∈ Z;
make v: 10.5, x: 0.0 ∈ R;
rule main():
** explicit conversion
alter a := v :> N;
print a; //truncated to 10
** explicit conversion
alter x := b :> R;
print x; //expect 20.00
return;
``````

#### Notes:

• making conversion will copy value not reference
• conversion to same data type is equivalent to copy "::"

## Alphanumeric type

Bee define A as single UTF-8 code point with representation: U+HH

``````make a, b ∈ A; //ASCII
make x, y ∈ B; //Binary integer
rule main():
alter a :='0';     //ASCII symbol '0'
alter x := a :> B; //convert to binary 30
alter y := 30;     //decimal code for '0'
alter b := y :> A; //convert to ASCII symbol '0'
return;
``````

## Type inference

You can use symbol ":=" to initialize variables using type inference.

``````** declare constants
stow a := 4;   //integer constant
stow b := 2.5; //real constant
stow c := 1/8; //rational constant
** declare variables
make x := 0;   //integer variable
make y := 0.0; //real variable
make z := 0/0; //rational variable
``````

## Type checking

We can use variable type to validate expression type.

``````** using type inference
make a := 0;   //integer variable
make b := 0.0; //real variable
rule main():
alter a:= 10.5; //Warning: a is of type: Integer
alter b:= 10;   //Warning: b is of type: Real
print a, b;     // 10, 10.00
return;
``````

You can use operator "∈" to verify data type:

``````make a := 0 ∈ Z;
rule main():
** expected: Integer
fail if ¬ (a ∈ Z); // fail if a is not integer
return;
``````

## Logic type

Logic type is an enumeration of two public symbols: False and True

``````type .L: {.False: 0, .True: 1} <: Ordinal;
** printing logical values
rule main():
print True;  //1
print False; //0
return;
``````

### Logic operations

Bee uses several familiar logic operators from mathematics:

• ¬ (not)
• ∧ (and)
• ∨ (or)
• ⊕ (xor)

Precedence: { ¬, ∧, ∨, ⊕, = }. Symbol ¬ apply first (has higher precedence)

bitwise

In Bee we define special operators to perform bitwise operations. One opperator is overwrite: ⊕. This operator (xor) can operate on both, logical values or expressions and also on integer numbers.

• ~ (not)
• & (and)
• | (or)
• ⊕ (xor)
``````# betweese opperations
print 4 | 3;//out:7 is becouse 100 ∨ 011 = 111 = 7;
print ~4    //out:3 is becouse: 100 ⊕  100 = 011 = 3;
print 4 & 7 //out:4 is becouse: 100 ∧ 111 = 100 = 4;
print 4⊕4  //out:0 is becouse: 100 ⊕ 100 = 000 = 0;
print 1<<2  //out:2 is becouse: 001 << 2   = 100 = 4;
print 6<<2  //out:1 is becouse: 110 << 2   = 001 = 1;
``````

comparison Comparison operators will create a logical response: 1 = True or 0 = False

• comparison ( ≈, =, ≠, ≡, >, <, ≤, ≥)
• belonging ( ∈, ⊃, ⊂ )

#### Example:

``````make  (x, y):4 ∈  Z; //primitive integer
rule main():
** value comparison
print x = 4;  //1 (equal)
print x ≡ 4;  //1 (identical)
print x = y;  //1
print x ≡ y;  //1
print x ≠ 5;  //1 (different)
print x!≡ 5;  //1 (not identical)

** reference ordering
print x ≥ y;  //1: x and a are actually equal
print x ≥ 4;  //1: greater or equivalent to 4
print x ≤ 4;  //1: less than or equivalent to 4
print x > 4;  //0: not greater than 4
print x < 4;  //0: not less than 4

** arithmetic expressions have primitive results
print x - 4 = 0; //1
print x - 4 ≡ 0; //1
return;
``````

singleton

Primitive types are unique. That means they are identical.

``````** primitive values are singleton
print  1  ≡  1;  //1
print `s` ≡ `s`; //1
``````

Precedence:

Logic operators have greater precedence than comparison operators.

### Logical expression

Logical expression have value { 0 = False, 1 = True }

``````make x := False ∈ L;
make y := True  ∈ L;
rule main():
** expressions with single operant
print   x; //0
print ¬ x; //1

** expressions with two operands
print (x = y); //0
print (x ≡ y); //0
print (x ≠ y); //1
print (x < y); //1
print (x > y); //0
print (x ∧ y); //0
print (x ∨ y); //1
print (x ⊕ y); //1
return;
``````

#### Notes:

• Operators { ¬ } is unary operator;
• Operators { ∧, ∨ } are also bitwise operators;
• Operators { ¬, ⊕ } are also bitwise operators;
• Operators { «, » } are bitwise operators;

coercion Any numeric expression can be converted to a logic value using coercion operator ":>" (easy to memorize if you think is like an arrow).

``````make (x, y) ∈ L;
make (a:0.0, b:1.5) ∈ R;
rule main():
alter x := a :> L; //0
alter y := b :> L; //1
return;
``````

#### Notes:

• Only the integer part of a number is used in conversion to logical;
• Fraction is truncated before conversion to logical;
• A string: "Yes", "yes", "True", "true", "On","on", "T", "t" or "1" convert to: True = 1
• A string: "No", "no", "False", "false", "Off","off", "F", "f" or "0" convert to: False = 0

design

``````** logical values are singleton
print True  ≡ True;   //1
print False ≡ False;  //1
** logical values are numeric
print False - True; //-1
print True  + True; //+2
** Null value is a singleton
print Null  ≡ Null   //1
** Null is not the same as false
print Null  ≡ False  //0
print Null  = False  //0
``````

### Conditionals

A conditional is a logic expression used to control statement execution.

``````statement if condition;
``````

The statement is executed only if the expression evaluate to True.

restrictions:

1. Can not use "if" with type statement;
2. Can not use "if" with make statement;
3. Can not use "if" with block statement;
``````make a := 0 ∈ Z;
rule main():
** conditional execution
alter a := 1 if a = 0;
** conditional print
print "a is 0" if a = 0;
return;
``````

#### Notes:

• Keywords "if" do not have "else",
• There is no ";" before "if" keyword

### Pattern Matching

Instead of ternary operator we use conditional expressions. These expressions are separated by coma and enclosed in ().

#### Syntax:

``````make var ∈ type;
rule main():
** single condition matching
alter var := (xp1 if cnd1, xp);

** multiple matching with default value
alter var := (xp1 if cnd1, xp2 if cnd2,...xp);

** alternative code alignment
alter var :=
(xp1 if cnd1
,xp2 if cnd2
,xp);
return;
``````

Legend:

• var ::= predefined variable,
• xp1 ::= expression of same type with var,
• xp2 ::= expression of same type with var,
• xp ::= default expression (no condition).
• cnd1 ::= condition to produce exp1,

#### Example:

``````rule main():
make x := '0'; //symbol
write "x:"
read   x;

make kind := ("digit" if x ∈ ['0'..'9'], "letter" if x ∈ ['a'..'z'],or "unknown");
print ("x is " + kind); //expect: "x is digit"
return;
``````

## Type inference

Type inference is a logical deduction of data type from constant literals.

### Default types

Each literal has associated a default type, induced by operators {":=", "::"}.

``````** string expressions
make c := 'a'     ;  //type = A
make s := '∈'     ;  //type = U
make s := "str"   ;  //type = S
make b := <Text>  ;  //type = Text
** numeric expressions
make i := 0;    //type = Z
make j := 0.50; //type = R
** define synonyms for logic constants
stow false := False; //type L = 0
stow true  := True;  //type L = 1
** multiple variables get same value
make x, y, z := 5; //type = Z for all
** multiple variables get multiple values
make int, rea := 4, 4.44;
print type(int); // Z
print type(rea); // R
``````

### Composite Types

Composite structures are using () [] and {} to create different data types. Next you can study some examples. We wil explain later all these types: List, Map, Array, Object, String. All of these are also called Bee collections.

``````** boxed integer (type = Z)
make i := ; //array of one value!
** list of one value (Z)
make a := (1,);
** list of integers (Z)
make b := (1,2);
** list of symbols (type = A)
make l := ('a','b');
** list of Unicode symbol (type = U)
make u := ('Δ', 'Λ', 'Γ');
** array with capacity of 4 integers: Z
make d := [1,2,3,4];
** array with capacity of 10 real numbers: R
make e := [0.00](10);
** matrix with capacity of 10x10 real numbers: R
make m := [0.00](10,10);
** data set of 4 integers: Z
make s := {1,2,3,4};
** hash map of (Z: String)
make c := {(1:"storage"),(2:"string")};
** object with two attributes: name ∈ String, age ∈ Z
make b := {name:"Goliath", age:30};
``````

### Parameter types

When we define parameters we can use type inference only for optional parameters:

Optional Parameters:

``````** in rule foo, parameters a, b are optional.
rule foo(a: 0, b: 0 ∈ Z) => (r ∈ Z):
alter r := a + b;
rule;

rule main():
print foo();    // 0
print foo(1);   // 1
print foo(1,2); // 3
return;
``````

Multiple parameters:

``````** parameters: a, b are mandatory, c is optional.
rule foo(a, b, c: 0 ∈ Z) => (r ∈ Z):
alter r := (a + b + c);
return;
rule main():
print foo(1,2);   // 3
print foo(1,2,3); // 6
print foo(1);     // Error: expected 2 arguments
return;
``````

Pass arguments by name:

We can use parameter name and pair-up ":" symbol for argument value.

``````** rule with optional parameters (Z)
rule bar(a: 0, b: 0, c: 0 ∈ Z) => (result ∈ Z):
alter result := (a+b+c);
return;
** observe we use pair-up ":" to give value for each argument
rule main():
print bar(a: 1); //print 1 because b,c = 0
print bar(b: 1); //print 1 because a,b = 0
print bar(c: 1); //print 1 because a,b = 0
return;  ``````

## Rational numbers

In mathematics rational number is any number that can be expressed as the fraction p\q of two integer numbers: numerator "p" of type integer and a non-zero denominator "q" of type natural> 0.
Since "q" may be equal to 1, every binary integer is also a rational number.

Note: Q numbers are approximated numbers.

• Default precision for Q numbers is \$precision: 10⁻⁵ = 0.00001
• Default precision can be set using: \$precision:x; global constant
• Operator "≈" is using the precision if the operator "±" is not used;

Other precision constants:

• \$deci := 1d = 10⁻¹
• \$centi := 1c = 10⁻²
• \$mili := 1m = 10⁻³
• \$micro := 1μ = 10⁻⁶

Literal Notation: p/q

It can be used with type inference to create Q numbers:

#### Example:

``````make x := 0    ∈ Q; //0
make a := 1/2  ∈ Q; //0.5
make b := 1/4  ∈ Q; //0.25
make c := 1/8  ∈ Q; //0.125
make d := 1/8  ∈ Q; //0.062
make e := 1/8  ∈ Q; //0.031
``````

#### Note:

• The inch is a unit of length in the British imperial and United States
• It is equal to 1/36 yard or 1/12 of a foot
• One inch is divided in 1/2, 1/4, 1/8, 1/16 and 1/32

### Q Notation

Rational number has a magnitude and precision defined by the user. Q numbers are defined using "fixed point arithmetic" This is a way of computing fractional numbers and control the precision.
• Qm.n is m+n+1 bit signed integer container with n fractional bits.

• Qm is a m+1 bit signed integer containing 0 fractional bits.

• number of bits = m+n+1

• precision is 2⁻ⁿ

• range is [-(2ᵐ)..(2ᵐ-2⁻ⁿ)]

For example: A number format "Q5.2" can store in range (-32.00..31.75) on 8 bits.

• with precision of 2⁻² = 1/4 = 0.25
• from value: -2⁵ = -32.00
• to value: 2⁵ - 2⁻² = 32 - 0.25 = 31.75
``````make  v ∈ Q5.2;
alter v := -32; //minim value
alter v := 31.75; //maxim value
``````

See also: wikipedia

### Typical Q numbers

Next I have predefined some numbers for orientation.

rezolution -> 1\4 ≈ 1\8 ≈ 1\16 ≈ 1\32 ≈ 1\64 ≈
↓ memory space ±0.25 ±0.125 ±0.062 ±0.031 ±0.015
8 bytes Q(5.2 ) Q(4.3 ) Q(3.4 ) Q(2.5 ) Q(1.6 )
16 bytes Q(13.2 ) Q(12.3 ) Q(11.4 ) Q(10.5 ) Q(9.6 )
32 bytes Q(29.2 ) Q(28.3 ) Q(27.4 ) Q(26.5 ) Q(25.6 )
64 bytes Q(61.2 ) Q(60.3 ) Q(59.4 ) Q(58.5 ) Q(56.6 )
128 bytes Q(125.2) Q(124.3) Q(123.4) Q(122.5) Q(121.6)

Note: r ≈ is the approximate resolution.

#### Examples:

A very large number with high resolution on 64 bit:

Q(50.12)

• Min: -1125899906842624
• Max: +1125899906842623
• Res: 0.000244140625

A number on 32 bit with resolution = 0.0005:

Q(20.11)

• Min: -1048576
• Max: 1048575
• Res: 0.00048828125

### Default Q number

Q(14.17)

Default Q number has precision 10⁻⁵ = 2⁻¹⁷ ≈ 0.00001 and occupy 32 bit.

• Min: -16384
• Max: +16383
• Res: 0.0000076

smallest fraction: 1/10000 largest fraction: 32766/2

### Approximate comparison

Rational numbers and other numbers can be compared using "≈" instead of "=".

• Operator "≈" can be used to compare two numbers using default precision;
• Operator "≈" can be used with "±" to overwrite default precision;

#### Example:

In next example b = 0.33(3), delta = (b - a) = 0.083

``````** override default precision
\$precision := 0.01;
make a := 0.25; //real
make b := 1/3;  //rational
** using specified precision 0.01 < 0.083
print (a ≈ b); //false
print (a ≈ b ± 0.1); //true
print (a ≈ c ± 0.5); //true
print (b ≈ c ± 0.5); //true
``````

#### Notes:

• Rational numbers are for 2D GIS maps,
• Rational numbers improve computation efficiency.

Read next: Control