# Surprises

SCaml is designed to minimize the surprises of its programmers: Some of OCaml language features are not available, but they are clearly listed.

Unfortunatelly, there are still some amount of surprises. Some class of valid OCaml programs are rejected by SCaml compiler even though they only use supported features.

## Many constuctors only take constants

Many constructors defined in `SCaml`

are used to write smart contract specific constants. They only take constants as arguments.

For example `Int 3`

and `Nat 42`

are valid, but the following expressions are invalid:

```
(* Error: [ESCaml200] Int can only take an integer constant *)
let x = 20 in Int x
(* Error: [ESCaml200] Int can only take an integer constant *)
Nat (int_of_float 10.0)
```

This applies to blockchain related constant constructors such as `Address "tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN"`

. You cannot extract the string of the address by pattern matching like:

```
(* Error: [ESCaml200] Address only takes a string literal *)
fun (Address s) -> s
```

You cannot create an address from a string either like:

```
(* Error: [ESCaml200] Address only takes a string literal *)
let s = "tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" in Address s
```

## No partial application of primitives

Functions defined in `SCaml`

are all primitives. They must be fully applied:

```
(* Error: [ESCaml000] SCaml does not support partial application of primitive (here SCaml.+) *)
let incr = (+) 1
```

## Unintuitive type constraints are required sometimes

SCaml is monomorphic. If a type of its expression contains type variables, SCaml rejects it. Explicit type constraints are required to instantiate these type variables.

Users may find type constraints are required at unexpected places:

```
(* Error: [ESCaml100] This expression has type (SCaml.int, 'a) SCaml.sum, whose type variable 'a is not supported in SCaml. *)
match Left (Int 1) with
| Left x -> x
| Right y -> y
```

In this case you have to constrain the type of `Left (int 1)`

to `(int, int) sum`

:

```
(* valid *)
match (Left (Int 1) : (int, int) sum) with
| Left x -> x
| Right y -> y
```

For whom familiar with OCaml, this is a bit puzzling, since at a glance the expression looks to have type `(int, int) sum`

without the constraint because the argument type of `Right`

is unified with the one of `Left`

in the pattern match cases, but it does *not* actually. OCaml's type system is not so simple as the ordinary ML typing, and it performs more powerful type inferenece. Here, it generalizes the type of the expression just as if we had a let binding for the match target:

```
(* Invalid *)
match let v = Left (Int 1) in v with
| Left x -> x
| Right y -> y
```

Due to this virtual let binding, the expression has a generalized type `(int, 'a) sum`

which is rejected by SCaml.

## Function bodies cannot have non packable free variables in the bodies

The most puzzling surprise of SCaml.

SCaml's functions do not allow free variable occurrences of *non packable types* in their bodies.

Non packable types are `SCaml.big_map`

, `SCaml.operation`

, `SCaml.contract`

, and types containing them.

The free variable occurrences of a function are variables defined outside of the function body. For example, `fun x -> (x, y, let z = 1 in z)`

, `y`

is the sole free variable occurrence of the function; `x`

is bound by the function abstractrion and `z`

is locally defined.

A function is rejected in SCaml if it is not an entry point and has a free variable occurrence of a non packable type.

It sounds strange, but it is a restriction derived from the same limitation of Michelson's functional values. To explain further for who are familiar with functional programming, Michelson closures must be packable and therefore they cannot have non packable types in their environments.

Note that this restriction is *not* applied to the entry point functions; they are handled without Michelson closures.

### Example

This is an *invalid* example of a voting system:

```
(* Error: [ESCaml400] Function body cannot have a free variable occurrence `bigmap` with unpackable type. *)
open SCaml
let vote (k : string) bigmap =
let incr k =
match BigMap.get k bigmap with
| None -> BigMap.update k (Some (Nat 1)) bigmap
| Some n -> BigMap.update k (Some (n +^ Nat 1)) bigmap
in
[], incr k
```

The contract takes a candidate name `k`

to vote and increment the number of
votes for `k`

in the big map `bigmap`

. If there is no binding for `k`

,
it initializes with `Nat 1`

.

This definition is rejected by SCaml because the variable `bigmap`

of a non packable type `(string, nat) big_map`

is ocurring freely in the function body of `incr`

.

#### Fix 1: inline the function

You can avoid this problem by removing the function `incr`

by hand inlining:

```
open SCaml
let vote (k : string) bigmap =
let bigmap' = match BigMap.get k bigmap with
| None -> BigMap.update k (Some (Nat 1)) bigmap
| Some n -> BigMap.update k (Some (n +^ Nat 1)) bigmap
in
[], bigmap'
```

Without the function, the problem is also gone.

### Fix 2: parameterize the variable

You can also work around by abstracting the variable:

```
open SCaml
let vote (k : string) bigmap =
let incr (k : string) bigmap =
match BigMap.get k bigmap with
| None -> BigMap.update k (Some (Nat 1)) bigmap
| Some n -> BigMap.update k (Some (n +^ Nat 1)) bigmap
in
[], incr k bigmap
```

In this code, the occurrences of `bigmap`

in the function is bound
by the function, therefore they are no longer free.

You have to be careful of the ordering of the abstractions. The following code with a different order of arguments is rejected:

```
(* Error: [ESCaml400] Function body cannot have a free variable occurrence `bigmap` with unpackable type. *)
open SCaml
let vote (k : string) bigmap =
let incr bigmap (k : string) =
match BigMap.get k bigmap with
| None -> BigMap.update k (Some (Nat 1)) bigmap
| Some n -> BigMap.update k (Some (n +^ Nat 1)) bigmap
in
[], incr bigmap k
```

This is because `bigmap`

occurs freely inside the body of
the function abstraction of `(k : string)`

.

### Fix 3: uncurrying

If a function has a type `t1 -> t2 -> t3`

and `t1`

and `t2`

are not packable either, for example `operation list -> contract -> operation list`

you cannot work around the restriction by reordering them.
In this case, you can *uncurry* the arguments:

```
(* Error: [ESCaml400] Function body cannot have a free variable occurrence `bigmap` with unpackable type. *)
let add_transfer ops c =
Operation.transfer_tokens () (Tz 1.0) c :: ops
in
...
```

The above function takes 2 arguments and they are not packable. As far as the function is in curried form, you cannot compile it in SCaml.

In this case you can turn the function into uncurried form, which takes
1 argument of a pair of `ops`

and `c`

:

```
(* valid *)
let add_transfer (ops, c) =
Operation.transfer_tokens () (Tz 1.0) c :: ops
in
...
```

Now the code has only 1 function abstraction, and `ops`

and `c`

are both bound by it.

### Fix 4: Use uncurried primitives

This restriction is troublesome especially when you use higher order function primitives like `List.fold_left`

with non packable types. Here is an *invalid* example which tries to send tokens to each member of a contract list:

```
(* Error: [ESCaml400] Function body cannot have a free variable occurrence `bigmap` with unpackable type. *)
List.fold_left
(fun ops -> fun c -> Operation.transfer_tokens () (Tz 1.0) c :: ops)
[] contracts
```

Though this coding style with `List.fold_left`

is quite common in OCaml, this expression is rejected by SCaml, since the type `ops`

is `SCaml.operation list`

which is not packable and `ops`

is freely occurring in the inner function `fun c -> ..`

.

You cannot fix the issue by defining uncurried version of `List.fold_left`

, by yourself, since it requires recursion and polymorphism. To work around this specific problem, SCaml provides another version of list folding `List.fold_left'`

:

```
List.fold_left'
(fun (ops, c) -> Operation.transfer_tokens () (Tz 1.0) c :: ops)
[] contracts
```

Here, the two function abstractions in the previous example are “uncurried” i.e. squashed into one which takes a tuple `(ops, c)`

, thus making the occurrence of `ops`

is no longer free. SCaml provides this kind of uncurried foldings for `list`

, `set`

, and `map`

.