Skip to content

Commit

Permalink
docs: explain type aliasing (#799)
Browse files Browse the repository at this point in the history
  • Loading branch information
hishamhm authored Sep 2, 2024
1 parent e5ee053 commit 6719333
Showing 1 changed file with 145 additions and 0 deletions.
145 changes: 145 additions & 0 deletions docs/aliasing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Type aliasing rules in Teal

## The general rule

In Teal we can declare new types with user-defined names. These are called
_nominal types_. These nominal types may be unique, or aliases.

The `local type` syntax produces a new _nominal type_. Whenever you assign to
it another user-defined nominal type, it becomes a _type alias_. Whenever you
assign to it a type constructor, it becomes a new unique type. Type
constructors are syntax constructs such as: block constructors for records,
interfaces and enums (e.g. `record` ... `end`); function signature
declarations with `function()`; applications of generics with `<>`-notation;
declarations of array, tuple or map types with `{}`-notation; or a primitive
type name such as `number`.

Syntax such as `local record R` is a shorthand to `local type R = record`, so
the same rules apply: it declares a new unique type.

Nominal types are compared against each other _by name_, but type aliases are
considered to be equivalent.

```lua
local record Point3D
x: number
y: number
z: number
end

local record Vector3D
x: number
y: number
z: number
end

local p: Point3D = { x = 1.0, y = 0.3, z = 2.5 }

local v: Vector3D = p -- Teal compile error: Point3D is not a Vector3D

local type P3D = Point3D

local p2: P3D

p2 = p -- ok! P3D is a type alias type Point3D
p = p2 -- ok! aliasing works both ways: they are effectively the same type
```

Nominal types are compared against non-nominal types _by structure_, so that
you can manipulate concrete values, which have inferred types. For example,
you can assign a plain function to a nominal function type, as long as the
signatures are compatible, and you can assign a number literal to a nominal
number type.

```lua
local type MyFunction = function(number): string

-- f has a nominal type
local f: MyFunction

-- g is inferred a structural type: function(number): string
local g = function(n: number): string
return tostring(n)
end

f = g -- ok! structural matched against nominal
g = f -- ok! nominal matched against structural
```

You can declare structural types for functions explicitly:

```lua
local type MyFunction = function(number): string

-- f has a nominal type
local f: MyFunction

-- h was explicitly given a structural function type
local h: function(n: number): string

f = h -- ok!
h = f -- ok!
```

By design, there is no syntax in Teal for declaring structural record types.

## Some examples

Type aliasing only happens when declaring a new user-defined nominal type
using an existing user-defined nominal type.

```lua
local type Record1 = record
x: integer
y: integer
end

local type Record2 = Record1

local r1: Record1
assert(r1 is Record2) -- ok!
```

This does not apply to primitive types. Declaring a type name with the same
primitive type as a previous declaration is not an aliasing operation. This
allows you to create types based on primitive types which are distinct from
each other.

```lua
local type Temperature = number

local type TemperatureAlias = Temperature

local type Width = number

local temp: Temperature

assert(temp is TemperatureAlias) -- ok!
assert(temp is Width) -- Teal compile error: temp (of type Temperature) can never be a Width
```

Like records, each declaration of a function type in the program source code
represents a distinct type. The `function(...):...` syntax for type
declaration is a type constructor.

```lua
local type Function1 = function(number): string

local type Function2 = function(number): string

local f1: Function1

assert(f1 is Function2) -- Teal compile error: f1 (of type Function2) can never be a Function1
```

However, user-defined nominal names referencing those function types can be
aliased.

```lua
local type Function1 = function(number): string

local type Function3 = Function1

local f1: Function1
assert(f1 is Function3) -- ok!
```

0 comments on commit 6719333

Please sign in to comment.