index<--

The purpose of any programming language is to manipulate data. On the lowest level, data is basicly 0 and 1 signals. EVE is a high level language so our idea of data type is more complex. EVE has a gradual-typing system that will be explaine below.

Let's describe the basic types:

- Primitive
- Composite
- Data coercion
- Type inference
- Default types
- Logical type
- Gradual typing
- Calendar date
- Time duration

Class Name | Description | Minim | Maxim |
---|---|---|---|

Integer | Signed on 64 bit | -2⁶³ | 2⁶³-1 |

Natural | Unsigned on 64 bit | 0 | 2⁶⁴-1 |

Decimal | Float precision number on 8 bytes | 0 | 1.8 × 10³⁰⁸ |

Unicode | Single Unicode symbol UTF-32 4 bytes | 0 | 2³²-1 |

Ordinal | Enumeration of symbols, Short 16 bit | 0 | 2¹⁶-1 |

Date | Calendar date | 01/01/0001 | 01/01/9999 |

Time | Time of the day (24h) | 0 | 8.64e+7ms |

Logic | Is a Ordinal subtype having values: False = 0, True = 1 | 0 | 1 |

In EVE we can have two categories of numbers:

Category | EVE Types |
---|---|

Discrete | Ordinal, Integer, Natural, Range |

Continuous | Single, Double, Decimal, Domain |

type | Chars | Bytes | min | max | maximum number |
---|---|---|---|---|---|

Integer | 20 | 8 | -2⁶³ | 2⁶³-1 | ≤ 9,223,372,036,854,775,807 |

Natural | 20 | 8 | 0 | 2⁶⁴-1 | ≤ 18,446,744,073,709,551,615 |

For conversion into characters:

- The number of characters required for Integer numbers is 20. (19+sign)
- For Double numbers, conversion into characters is controled by #precision directive

The type *Double* is represented using floating precision numbers.

Floating decimal numbers are most simply described by 3 Integers:

- s: a sign (0 or 1)
- c: a coefficient
- n: an exponent

The numerical value of a finite number is −1ˢ × c × 2ⁿ Using this formula EVE define two floating point types.

Single: is single-precision 32-bit IEEE 754:

Double is double-precision 64-bit IEEE 754:

type | Digits | Bytes | maximum number |
---|---|---|---|

Single | 7 | 4 | ≤ 3.4 × 10³⁸ |

Double | 16 | 8 | ≤ 1.8 × 10³⁰⁸ |

Precision is variable depending on the size of the number. The number of digits represents the largest number that can be converted from string format into a Double and back without loosing any digit. Think of it like a digital display from a packet calculator.

Example | Description |
---|---|

0 | Integer zero |

123 | Integer number using symbols: {0,1,2,3,4,5,6,7,8,9} |

1/2 | Single number use symbols: {.,0,1,2,3,4,5,6,7,8,9} |

0.5 | Double number use symbols: {.,0,1,2,3,4,5,6,7,8,9} |

```
#numeric literals
routine main:
Integer i; // Initial value = 0
Natural n; // Initial value = 0
Double r; // Initial value = 0.00
process
i := 9223372036854775807; // maximum
n := 18446744073709551615; // maximum
r := 1/2; // 0.5
return;
```

**See also:** scientific notation

Composite data types are unions of data elements. A composite variable that is not initialized can have Null value that is similar to zero but different. Some of these types are going to be explained later. We enumerate them all here to grasp the idea.

Class Name | Description |
---|---|

Range | Integer range of numbers equaly distanced (x..y:ratio) |

Domain | Decimal range of numbers equaly distanced [x..y:ratio] |

String | Limited capacity string: ('single quoted') |

Text | Unlimited capacity string: ("double quoted") |

List | Dynamic unsorted enumeration of values or objects of same type |

Map | Enumeration of (key:value) pairs unique sorted by key |

Set | Enumeration of unique elements of the same type sorted by value |

Object | Base class for creation of plain simple objects |

Exception | Composite type derived from Object base class |

A range is a notation that can create a sub-set of integer numbers.

```
range ::= (min..max:ratio);
```

- Limits are included by default,
- Upper or lower limits can be excluded using "!" instead of "."
- Range notation can be open at one end or both ends.

Numeric ranges:

```
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)
expect( 32667 in (0..+)); //will pass
expect(-32668 in (-..0)); //will pass
return;
```

Symbol ranges:

```
** using symbol ranges
routine main:
process
print ('0'..'5') // ('0','1','2','3','4','5')
** following statements should pass
expect ('0' in ('0'..'9')); //will pass
expect ('X' in ('A'..'Z')); //will pass
return;
```

Domains are similar to ranges, except they cover continuous numbers. Domains are decimal numbers not integers. So you can not print an entire domain. If you try, an infitinet loop may trigger. To prevent it we use $loop_limit constant.

- A domain include min and max limits,
- Limits can be excluded using (!) instead of (.),
- A domain can be continuous or discrete,
- A domain can be used to create a class.

```
domain ::= [min..max:ratio] <: Super_Type
```

```
** sub-type declarations
routine main:
process
print [0..1:0.25]; // 0.00, 0.25, 0.50, 0.75, 1.00
return;
```

- In the future we will cover a complete set of physical types
- Physical types include measurement unit and transformation methods

In computer science coercion is used to implicitly or explicitly change an entity of one data type into another of different type. This is ready to take advantage of type hierarchies and type representations. If not designed properly the coercion can be a fatal mistake. EVE is a safe language so we do only safe coercion.

**Implicit coercion** In EVE the arithmetic operators are polymorphic. Numeric operators can do implicit data conversion to accommodate the data types and return an accurate result. Automatic conversion is possible only when there is no risk of loosing data precision. If there is a loss of precision we can end-up with a *run-time error*. To prevent this EVE will implement a safe compile-time check.

- Implicit conversion is possible and
*safe*: - Explicit conversion is possible but
*unsafe*:

```
#example of implicit conversion
routine main:
Integer a = 2;
Double b = 1.5;
process
b := a; // this implicit cast is possible b = 2.0
b := a + 3.5; // add 3.5 then assign result to b = 5.5
a := b; // error: can not assign Double to Integer
a := 1.5; // error: can not assign Double to Integer
return;
```

**Explicit coercion** Explicit coercion is a *forced conversion*. Can be used to convert backwards from higher data range to lower data range or from continuous numbers to discrete numbers. This however can cause a data or precision loss. Explicit coercion is using a function.

Examples of explicit coercion:

```
# explicit coercion in EVE
routine main:
Integer a = 0;
Double b = 1.5;
process
**explicit coercion lose (0.5)
a := floor(b);
write a; //will print: 1
**explicit coercion add (0.5)
a := ceiling(b);
print a; //will print: 2
**explicit coercion rounding:
a := round(b);
print a; // will print: 2
return;
```

**Number to a string**

```
local
String s;
Integer v = 1000;
begin
s := format(v); // explicit coercion s = '1000'
end local;
```

**String to a number**

This can be ready using the casting function parse(), only if the string contains a number. Otherwise the conversion fail and will rise and exception.

```
local
Integer v;
Double b;
String s = '1000';
String r = '200.02';
process
v := parse(s); // make v = 1000
v := parse(r); // make v = 200 and decimal .02 is lost
b := parse(r); // make b = 200.02 and decimal .02 is preserved
end local;
```

**Note:** Build-in functions that are located in EVE *default* library: { parse(), format(), ceiling(), floor() round()}. This module is one of the standard modules that are automatically included in any EVE program.

This is a logical deduction of data type from constant literals.

```
** Define a list of 10 elements using type inference
routine main:
List ls = [0,1,2,3,4,5,6,7,8,9]; // initialized list of Integer
process
print ls.type(); // List[Integer]
expect (ls is List[Integer]);
return;
```

Literals are representations of specific particular data type in source code.

**Basic types** Next notation use "9" to show any digit in range [0..9].

Literal | Type |
---|---|

9 | Integer |

-9 | Integer |

0x9ABCDEF | Natural |

0b1010101 | Binary |

9.9 | Double |

U+0001 | Word |

U-FFFFFFFF | Binary |

**Zero literals**

Literal | Type |
---|---|

[] | List |

{} | Set/Map |

() | List |

"" | Text |

'' | String |

0 | Integer |

0.0 | Double |

**Collection literals**

Literal | Type |
---|---|

{a:0, b, c} | Ordinal |

{x:'b',y:'d'} | Object |

[1, 2, 3] | List[Byte] |

['a','b','c'] | List[Symbol] |

["a","b","c"] | List[Text] |

Sometimes the type is partially specified to simplify type declaration:

```
variable
** member type is inferred later from first member
List a := [];
```

We can verify the type using "is" operator:

```
routine main:
Object r = {name:"test", age:"24"};
Map t = {('key1':"value1"),('ley2':"value2")};
do
** check variable types using introspection
expect r.name is Text;
expect r.age is Text;
expect t.key is String;
expect t.value is Text;
return;
```

For type introspection we can use type() built-in function:

```
routine main:
Double i = 1.5;
do
expect i is Double;
write "type of i is \s" ? type(i);
return;
```

In mathematics there are very few operators: {+, -, / , * } that can operate with any kind of numbers: negative, positive, rational or real. Operators are not bound to specific data types. Therefore these operators are called *"polymorphic"*.

Some languages define different operators for Integers and Floating decimal numbers. For example in OCaml the operator "/" can divide Integers while "/." can divide Floating point decimal numbers. This is unexpected for a mathematician who is expecting to use one single operator for division.

In EVE, operators are mapped to functions. To design polymorphic operators we overload the function signature using type dispatch. The dispatch is using left side operand first, this is the leading operand. For unary operators there is only right side operand so this becomes the leading operand.

In Latin the "falsus" and "verum" are translated in English to "false" and "true".

- falsus := ⊥ defined by ⊥ := ¬ ⊤ and ( P ∧ ¬P )
- verum := ⊤ defined by ⊤ := ¬ ⊥ and ( P ∨ ¬P )

name | value | binary |
---|---|---|

False | Logic.False | 00000000 00000000 |

True | Logic.True | 00000000 00000001 |

```
variable
Logic: name = False; // explicit initialization
```

**Internal design**

Probably best to define Logic type is Ordinal:

```
type Logic = { .False , .True } <: Ordinal;
```

**Logical expressions**

A logical expression is a demonstration or logical deduction having result T or F. The order of operations can be controlled using operator precedence and parentheses ().

Operator precedence:`{not, and, or, xor}`

Result of logical expressions can be used into a conditional statement to make a decision. Also results of logical expressions can be stored in logical variables to be used later in other conditions.

Gradual typing is a type system in which some variables may be given types and the correctness of the typing is checked at compile-time (which is static typing) and some variables may be left un-typed and eventual type errors are reported at run-time (which is dynamic typing). To declare gradual types we use a polymorphic type called "@variant".

**Variant Types**

A Variant is a polymorphic variable that can have multiple types but only one at a time:

```
type Name = {Type | Type | ... } <: Variant;
variable
Name: v = value; // declare single variable (with initial value)
```

- Variant data type is assigned at runtime;
- One variant can have a single value at a time;
- One variant is a "union" of several types

For this we use a special type Null

- The Null type is a curious type;
- It can have only one value = Null;

```
type Number = {Integer | Double | Null} <: Variant;
variable
Number: x; // default value is Null
```

**Usability**

A variant can establish its data type at runtime:

```
#variant
routine main:
Double | Integer v, x ,t;
process
** positive example
v := 1; // v is Integer
x := 1.5; // x is Double
t := 1 / 2; // make t Double
** safe conversion
t := 12; // t is Double
** negative examples
v := x; // ERROR: v is Integer
return;
```

A variant is a way to create a generic routine.

```
# variant parameter in routines
routine swap(Integer | Double x, y):
Integer | Double i
process
expect type(x) = type(y);
i := x; // intermediate reference
x := y; // first swap
y := x; // second swap
return;
routine main:
Integer y; // default zero
Double a, b; // default zero
process
** invert two Integer numbers
x := 10;
y := 20;
swap(x, y);
expect (x == 20) and (y == 10);
** invert two Double numbers
a := 1.5;
b := 2.5;
swap(a, b);
expect (a == 2.5) and (b == 1.5);
return;
```

Symbols are Unicode UTF32. That is using 32 bit Integer

- Single-quoted strings like: 'α'
- U+HHHH from: U+0000 to U+FFFF
- U-HHHHHH from: U+000000 to U+FFFFFF

Value NUL = U+0000. This is also the default value.

In EVE we represent calendar date.

**Date storage**

- Date type is internally stored as number on 4 bytes;
- First byte store the day, second byte store the month;
- Last 2 bytes store the year;

**Date literals**

When can create a date literal using 3 format functions:

- ydm() format: "YYYY/DD/MM"
- dmy() format: "DD/MM/YYYY"
- ydm() format: "MM/DD/YYYY"

**Note:** A reversible function is overloaded.

```
#overloaded function
routine main:
Date: date := "2019/01/30" as YDM
process
print date as YDM; // 2019/01/30
print date as DMY; // 30/01/2019
print date as MDY; // 01/30/2019
return;
```

Time data type can be used to represent duration.

- EVE duration can represent minimum 1 millisecond.
- EVE duration can represent maximum 4294967296 hours.

**Representation** Time is represented as a number on 8 bytes.

- First 2 bytes are the milliseconds.
- Next 2 bytes are representing seconds and minutes.
- Last 4 bytes represents hours.

**Conversion**

Time format is created using two reversible functions: t12() and t24()

- T12 accept format ("hhhh:mm:ss,9999ms")
- T24 accept format ("hhhh:mm:ssxx, 9999ms" )

ss: can be 0..60 seconds

xx: can be: (am/pm)

```
# time demo
routine main:
Time: (time1, time2, time3) = "00:00";
process
time1 := "23:63" as T24;
time2 := "23:63:59,99" as T24;
time3 := "11:63:59pm,99ms" as T12;
return;
```

```
** example of collection iteration
routine test():
List this = ["a","b","c","d","e"];
Integer i = 0;
Symbol: e;
process
while i < this.length() loop
e := this[i];
i := i + 1;
if e >= "c" then
write e + (e == this.tail ? '' : ',')
end if;
else
write ('i = ' + i);
end loop;
print;
return;
```

**Read next:**
Collections