A minimal but powerful programming language based on C, Go and Haskell

Because a lot of non-essential features are removed from the language and core, the user has freedom to implement them however they want. In this section we provide some of possible solutions for these types of challenges.

Polymorphism can be achieved using cloure and lambdas.

```
drawCircle = fn(s: Circle, c: Canvas, f: float -> int) {...}
drawSquare = fn(s: Square, c: Canvas, f: float -> int) {...}
drawFunction = fn(Canvas, float -> int)
#function to get another function to draw the given shape
getShape = fn(name: String -> drawFunction)
{
["Circle": fn{
c = Circle(...)
drawCircle(c, _, _)
},
"Square": ...
][name]()
}
f = getShape("Circle")
f(my_canvas, 1.12)
```

If you want to add a new shape (e.g. Triangle), you should define appropriate functions (e.g. `drawTriangle`

), and modify the map in `getShape`

.
If you want to add a new operation (e.g. print), you will need to add a new function (e.g. `getShapePrinter`

).

Another approach to implement polymorphism is by using a minified VTable:

```
drawCircle = fn(s: Circle, c: Canvas, f: float -> int) {...}
drawSquare = fn(s: Square, c: Canvas, f: float -> int) {...}
getDraw = fn(x: T, T: type -> fn(Canvas, float -> int))
{
vtable = [Circle : drawCircle, Square: drawSquare]
cast(fn(T, Canvas, float), vtable[T])(x, _, _)
}
f = getDraw(my_circle)(my_canvas, 1.52)
```

There is no explicit support for exceptions. You can return a specific `exception`

type instead (or use `nothing`

type to indicate exception).

If a really unrecoverable error happens, you should exit the application by calling `exit`

built-in function.

In special cases like a plugin system, where you must control exceptions, you can use built-in functions to call plugin. It will return an error result if the function which it calls exits unexpectedly.

Example: `result = safeInvoke(myPluginHandler)`

If and Else constructs can be implemented using the fact that booleans converted to integer will result to `0`

or `1`

(for `false`

and `true`

).

```
ifElse = fn(cond: bool, true_case: T, false_case:T, T: type -> T)
{
[true: true_case, false: false_case][cond]
}
```

Another example:

```
process = fn(x:int -> string)
{
options = [x>0 : fn{ saveLargeFileToDB("SDSDASDA") },
x<=0: fn{ innerProcess(x) }
]
options[true]()
}
```

Above sample implemented using ifElse function:

```
process = fn(x:int -> string)
{
ifElse(x>0, fn{
saveLargeFileToDB("SDSDASDA")
}, fn{
innerProcess(x)
})()
}
```

Above is translation of below C code:

```
string process(int x) {
char* result;
if ( x > 0 ) {
result = saveLargeFileToDB("SDSDASDA");
} else {
result = innerProcess(x);
}
return result;
}
```

It is advised to put all import dependency paths in one module like `refs`

and import it to specify import paths.

```
#refs
std_map = "/http/github.com/dotLang/std/v1.9.5/MapHelper"
```

and then use above to do actual import:

```
#File1 module
refs = import("/src/main")
MapHelper = import(refs..std_map)
```

Sometimes we need to have a generic function that can accept any other function (regardless of input count/type and output type). This is not directly possible in dotLang but there are other alternatives that can help in these cases. For example suppose that you have a function that accepts an optional validation function. If the function is provided, you want to call it, but if not, you want to ignore. You can define a generic function that can do this as here, we only care about the output of the validation function:

```
nothingFunc1 = fn(useless:T, T: type -> nothing) { nothing }
tryInvoke1 = (x: fn(T->U)|nothing, input:T -> U|nothing)
{
(x//nothingFunc1)(input)
}
checkedInvoke = fn(t:T|nothing, result: fn(->U), T: type, U: type -> U|nothing)
{
[fn{nothing}, result][isNothing(t)]()
}
```

And this is how you use this function:

```
result = checkedInvoke(validator, fn{tryInvoke1(validator, data)})
```

```
main = fn( -> int ) { 0 }
```

This is a function, called `main`

which has no input and always returns `0`

(very similar to C/C++ except `main`

function has no input).

You can simplify `main`

to:

`main = fn{ 0 }`

```
main = fn( -> int)
{
print("Hello world!")
0
}
```

We want to write a function which accepts a string like `"2+4-3"`

and returns the result (`3`

).

```
NormalExpression = struct (op: char, left: Expression, right: Expression)
Expression = int|NormalExpression
eval = fn(input: string -> float)
{
#assume we already have parse function
exp = parse(input)
innerEval(exp)
}
innerEval = fn(exp: Expression -> float)
{
int_val, normal_exp = exp
int_val // fn{
#now we are sure that exp is of type NormalExpression
y = unwrap(normal_exp)
['+' : fn{innerEval(y.left) + innerEval(y.right)},
'-' : fn{innerEval(y.left) - innerEval(y.right)},
'*' : fn{innerEval(y.left) * innerEval(y.right)},
'/' : fn{innerEval(y.left) / innerEval(y.right)}][y.op]()
}()
}
```

```
quickSort = fn(list:[int], low: int, high: int -> [int])
{
ifElse(high<low, list, fn{
mid_index = (high+low)/2
pivot = list[mid_index]
#filter is a built-in function
small_list = filter(list, fn(x:int -> bool) {x < pivot}))
big_list = filter(list, fn(x:int -> bool) {x > pivot}))
quickSort(small_list) + [pivot] + quickSort(big_list)
})
}
```

A function which accepts a list of numbers and returns sum of numbers.

```
sum = (data: [int] -> int)
{
calc = (index: int, sum: int -> int)
{
iElse(index >= length(data), fn{sum}
fn{calc(index+1, sum + data[index]})()
}
calc(0,0)
}
```

A function which accepts a number and returns its digits in a sequence of characters. Generally for this purpose, using a linked-list is better because it will provide better performance, but we are using recursion to show how it works.

```
extractor = (n: number, result: string -> string)
{
ifElse(n < 10, fn{result + char(48+n)}, fn{
digit = n % 10
extractor(n/10, result + char(48+digit)
})
}
```

A function which accepts two sequences of numbers and returns the maximum of sum of any any two numbers chosen from each of them. This can be done by finding maximum element in each of the arrays but we want to do it with a nested loop.

```
maxSum = (a: [int], b: [int] -> int)
{
calc = (idx1: int, idx2: int, current_max: int -> int)
{
ifElse(idx2 >= length(b), fn{current_max}, fn{
sum = a[idx1] + b[idx2]
next1 = (idx1+1) % length(a)
next2 = idx2 + int((idx1+1)/length(a))
calc(next1, next2, max(current_max, sum))
})
}
calc(0, 0, 0)
}
```

```
fib = (n: int, cache: [int|nothing] -> int)
{
ifElse(cache[n] != nothing, unwrap(cache[n], int),
fn{
seq_final1 = set(seq, n-1, fib(n-1, cache))
seq_final2 = set(seq_final1, n-2, fib(n-2, seq_final1))
seq_final2[n-1] + seq_final2[n-2]
})
}
```

```
std = import("/http/github.com/dotLang/std")
stdin = std..stdin
stdout = std..stdout
rand = std..random
main = fn
{
secret = rand(1,100)
stdout.write("Please enter a number: ");
guessRaw: int|nothing = tryParseString(int, stdin.readLine())
ifElse(guessRaw == nothing,
fn{
stdout.write("Invalid number")
},
fn {
guess = unwrap(guessRaw)
actions = [guess<secret: fn{ stdout.write("Too small!") },
guess>secret: fn{ stdout.write("Too large!") },
guess==secret: fn{ stdout.write("Well done!") }
][true]()
})
}
```