-
-
Notifications
You must be signed in to change notification settings - Fork 4
type
The concepts class and type are synonymous and represent prototypic schematics of data.
data in angle is a tree of nodes. A node has a type, which is itself a node.
Types in angle can be added to variables with these syntaxes:
i is 7 as integer
i as integer is 7
i of integer = 7
integer i=7
i:integer=7
The as
keyword eventually adds a cast to the guaranteed type.
The as
keyword also denotes return types of functions, which is no coincidence:
philosophically charged variables are just closures without parameters.
lists in angle can be typed with these syntaxes:
letters : chars
letters = chars
letters = char[]
letters = [char]
upcases = 26 * char
friends = 3 * person
letters = char[3]
arguments have an additional syntax in which the type and the variable name conincides
fibonacci number = if number<2 : 0 else fibonacci(number - 1) + fibonacci it - 2
Types can have aliases and cast operators to keep the forest of types clean.
Note how number simulataneously acts as type and variable name.
This is called matching by type name.
When scripting or writing small projects, developers may chose to omit types thanks to type-inference. Otherwise adding types is encouraged, though never obligatory:
fib int i = if i<2 : 0 else fib(i - 1) + fib i - 2
type Human = {
name: string;
age: number;
}
Angle is an optionally typed language meaning types are allowed but not strictly required. Types on variables and parameters are encouraged and often helpful for the compiler and humans, but mostly optional due to type inference.
Even though sounding similar, optional types and optional values are different concepts: Optional values means that the developer can express the fact that a value may be absent or on the other hand: required.
Example:
contact {
name required,
phone number,
email optional
}
Here the field name must always have a provided value, but the type of name is not specified, inferred to be Name by type matching, which is compatible to String, as all node_pointer in angle.
Here phone number on the other hand has a provided type of Number (through syntax and inference rules) but the field is not marked as required, making it semi optimal by default.
Here email has inferred type Email but optional values:
It can be absent or missing or empty, which is internally expressed by different kinds of typed null:
A missing person can never be handed to a function which expects numbers.
Similar to c# 10 namespaces, per file classes can be declared as declarations to get rid of unnecessary indentation:
namespace test; //applies to the whole file
class Foo; //applies to the whole file
int bar (){ 42 }
...
int boom (){ -1 } // declares test.Foo.boom
IDE support to display the current context is desirable
By the way an alias for class is type, and for namespace is context
Angle and wasp have internal types which should mostly be isolated from users,
as well as exposed types which should be the ones used by developers:
- number
- string
- any object, implicit default type
-
lists and maps often don't need their type exposed:
x=[1 2 3];y={a:1 b:2 c:3}
Having lists and maps as universal builtin types with no explicit type may come as surprise, but this is one of them main premises if not inventions of wasp.
How can any, list and map be the default type at the same time?
Any node can have arbitrary children and thus act as a list.
Any node can have arbitrary properties and thus act as a map.
Any list can contain pairs and thus act as a map.
In fact map are just lists of pairs under the hood.
While every node is any node, there are specializations:
A node has these different internal primitive types(kinds),
all aligning to 64 bits in the form of smart pointers:
- nils : Null types
- objects : {…} block data with children denoted by {}, closures
- groups : (…) meta params parameter attributes lists denoted by ()
- patterns : […] selectors matches, annotations! [public export extern] function mul(x,y){x*y}
- strings
- longs : also for storing ints and bools
- reals : for storing floats and doubles
- pointers : internal wasm pointer
Adding children to primitive types is allowed yet usually discouraged. Since mostly primitive are held by references (in variable pairs), this is a non-issue as properties can be added to references freely:
x=4
x.even=true // meta information
This will internally be represented as (psydocode:)
{node name="x" value=4 kind=long children=[{even=true}]}
NodeTypes.h and NodeValues.h To avoid name clashing, all type names end with s:
There are three types of type in Angle: wasm types (i32u etc) wasp types (kind of node) number, strings etc primitives angle types (classes of node objects) Date, Time, etc
When speaking of type in the context of Angle one usually refers to the last type of type, as they are the only ones that can be user defined:
class person{name, email?, address{street,city?}}
While classes are product types, enums and unions are classical sum types. This concept is extended in languages like rust:
type WebData = NoRequest | Loading | Failure HttpError | Success MyData
Which allows for great safe pattern matching
Advanced algebraic types would be
- Finite limits: a generalisation of finite products (i.e. the ADT product type), where we additionally require intersection types.
- Finite colimits: generalisation of finite sums (i.e. the ADT union type), where we additionally require quotient types
Functions are exponential types
(A^B)^C = A^(B*C): (f) => (b, c) => f(c)(b) (f) => c => b => f(b, c)
Obviously not part of the MVP angle implementation
By default all data and all classes in Angle that dont define their own equality method are records: Records are distinct from classes in that record types use value-based equality. Two variables of a record type are equal if the record type definitions are identical, and if for every field, the values in both records are equal. For data the equality comparison descends into children with other children, but value focussed: a:{x=3.0} and b:{x=3} are equal, because the root name is considered the variable name and the fields x=3.0 and x=3 are compatible.
Record types in Angle are the same as other class types, as all methods live outside classes, just like in julia, via multi-dispatch:
to kill a person{ tell him: "BYE!"}
to kill a dog{ tell it: "WUF!"}
The register for functions including their properties exists separately in memory.
Internal value kind
The internal value type known as node “kind” corresponds losely with the node “type” which is a pointer to another
node.
Example pseudocode:
node{
value.longy=1
kind=longs,
type=BoolType
}
node{
value.longy=1
kind=longs,
type=Integer
}
Hereby enums and other complex data with the same primitive value can still be differentiated unless the emitted wasm is optimized.
Typed lists / arrays
Internal representation
Typed arrays have Node kind Type::arrays
and any Node type.
person{
age in years
name as string
}
In object space types are just references to Node of internal Type (NodeTypes.h) classe.