about summary refs log tree commit diff stats
path: root/js/baba-yaga/docs/04_types.md
blob: bf70ef0e87e5cc6737cf9beff5668abfb37ae0f2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# Type System

Types are optional. If a type is declared, assignments are checked at runtime.

## Declaring Types

```baba
// Type declaration (name Type)
myValue Int;

// Assignment must match declared type
myValue : 10;       // OK (Int)
// myValue : "x";   // Error: expected Int
```

## Runtime Type Inference

Without declarations, values carry runtime type tags used by pattern matching:
- Numbers are tagged as `Int` or `Float`; `Number` is a supertype accepted in validation where numeric values are allowed
- Strings as `String`, Booleans as `Bool`
- Lists and Tables have `List`/`Table` tags

## Runtime Type Validation Semantics

- Parameter validation happens at call time for parameters with annotations only.
- Return type validation happens after body evaluation when a return type is declared.
- Untyped parameters are accepted as-is and are not validated.


## Function Return Types

```baba
add : (x: Int, y: Int) -> Int -> x + y;
```

## Typed Locals with `with`

Locals in a header can be typed exactly like globals using a declaration followed by assignment.

```baba
sumNext : (x: Int, y: Int) -> Int ->
  with (nx Int; ny Int; nx : x + 1; ny : y + 1;) -> nx + ny;
```

## Numeric Type Lattice and Widening

The numeric types form a simple lattice:

```
Int ⊂ Float ⊂ Number
```

- When a parameter expects `Float`, an `Int` is accepted (widened) implicitly.
- When a parameter expects `Number`, either `Int` or `Float` are accepted.
- When a parameter expects `Int`, `Float` is rejected.
- Many `math.` functions return `Float` for predictability.

## Typed Functions

Typed functions annotate parameters and the return value. At runtime, arguments and returns are validated.

### Multi-Parameter Typed Functions

```baba
// Parameter types and return type
add : (x: Int, y: Int) -> Int -> x + y;

// Using typed functions
result1 : add 2 3;        // OK => 5
// result2 : add 2 "3";   // Runtime error: parameter type mismatch

// Multi-parameter function takes all arguments at once
multiply : (x: Float, y: Float) -> Float -> x * y;
result : multiply 2.0 3.0;  // 6.0
```

### Curried Typed Functions

Curried functions take one parameter at a time and return functions for partial application:

```baba
// Curried function with typed first parameter and function return type
mul : (x: Float) -> (Float -> Float) -> y -> x * y;
double : mul 2.0;          // Partial application: double : (Float -> Float)
result : double 3.5;       // 7.0

// Three-parameter curried function
add3 : (x: Int) -> (Int -> (Int -> Int)) -> y -> z -> x + y + z;
add5 : add3 5;             // add5 : (Int -> (Int -> Int))
add5and3 : add5 3;         // add5and3 : (Int -> Int)
result : add5and3 2;       // 10
```

### Function Type Syntax

Function types use the syntax `(ParamType -> ReturnType)`:

```baba
// Simple function type
transform : (x: Int) -> (Int -> Int) -> y -> x + y;

// Function that returns another function
makeAdder : (x: Int) -> (Int -> Int) -> y -> x + y;
add5 : makeAdder 5;           // add5 : (Int -> Int)
result : add5 3;              // 8
```
Heads up! Complex nested parameter types like (f: (Int -> Int)) aren't implemented. The first parameter must use simple types like Int, Float, String, or Bool.

### Mixed Typed/Untyped Functions

```baba
// Mixed typed/untyped parameters (untyped are not validated)
concatIf : (flag: Bool, x, y) -> String ->
  when flag is
    true then x .. y
    _    then y .. x;

// Return type enforcement
// This will raise a runtime error if the body evaluates to a non-String
greet : (name: String) -> String -> "Hello " .. name;
```

### Backward Compatibility

All existing function syntax continues to work:

```baba
// Untyped curried function (existing)
multiply : x -> y -> x * y;

// Multi-parameter typed function (existing)
add : (x: Float, y: Float) -> Float -> x + y;

// New: Typed curried function
multiply : (x: Float) -> (Float -> Float) -> y -> x * y;
```

## Typed Tables

Table values carry the `Table` tag and can be typed via variable declarations. Currently, there is no way to create complex types that totally model the typing of the values contained within a table data structure.

```baba
// Variable type declaration (applies to subsequent assignments)
user Table;
user : { name: "Alice", age: 30 };

// Access remains the same
userName : user.name;  // "Alice"
userAge  : user.age;   // 30
```

## Result Type

`Result` encodes success (`Ok value`) or failure (`Err message`).

```baba
divide : x y ->
  when y is
    0 then Err "Division by zero"
    _ then Ok (x / y);

useDivide : when (divide 10 2) is
  Ok val then val
  Err _  then 0;
```
Pattern matching binds inner values:

```baba
// Function returning a Result
parseIntOrErr : (s: String) -> Result ->
  when (str.trim s) is
    "" then Err "Empty"
    _  then Ok 42;  // placeholder

// Consuming Result
answer : when (parseIntOrErr "  10  ") is
  Ok v  then v
  Err e then 0;
```

## Error messages

All runtime errors are thrown as plain `Error` with messages:

```
Type mismatch in function 'add': Expected Int for parameter 'y', but got String (value: "3")
Return type mismatch in function 'greet': Expected String, but got Int (value: 42)
Type mismatch for myValue: expected Int but got String (value: "x")
Division by zero
Index out of bounds: 5
Undefined variable: foo
Undefined property: age of person
Unknown operator: ^
Unexpected token: RPAREN ()) at 12:17
```
When a location is available, the CLI/REPL shows a code frame indicating `line:column`.