zax.io

A guide to the Zax programming language

View project on GitHub

Zax Programming Language

Meta-Types

Meta-types with omitted meta argument types

Meta-types are normal types except one or more types used within the meta-type is selected at compile-time. This allows a type to be variable.

MyType$(Type) :: type {
    value : $Type
}

myType1 : MyType$(Integer)
myType1.value = 3

myType2 : MyType$(String)
myType2.value = "hello"

myType3 : MyType$(String)
myType3.value = "goodbye"

// OKAY: the `myType2` is of the same type as `myType3` and thus will compile
myType2 = myType3

// ERROR: this will cause a compiler error since `myType` and `myType2` are
// not compatible
myType1 = myType2

Meta-types with multiple omitted meta argument types

More than one argument can be specified to a meta-type allowing for multiple types to be defined at compile-time.

MyType$(TypeA, TypeB) :: type {
    value1 : $TypeA
    value2 : $TypeB
}

myType1 : MyType$(Integer, String)
myType1.value1 = 3
myType1.value2 = "apple"

myType2 : MyType$(String, Integer)
myType2.value1 = "hello"
myType2.value2 = 7

myType3 : MyType$(String, Integer)
myType3.value1 = "goodbye"
myType3.value2 = -7

// OKAY: the `myType2` is of the same type as `myType3` and thus will compile
myType2 = myType3

// ERROR: this will cause a compiler error since `myType` and `myType2` are
// not compatible
myType1 = myType2

Meta-types with assumed meta argument types

Meta-types can be compile-time determined if the input argument passed into a constructor can be automatically determined based on called function’s signature. This can be done for both constructors and once declarations.

MyType$(Type) :: type {
    value : $Type

    +++ final : ()(input : $Type) = {
        value = input
    }

    func final once : ()(whatever : Integer, input : $Type) = {
        // ...
    }
}

// the `$Type` is automatically assumed based on the `input` to the constructor
myType1 : MyType = 5
myType1.value = 3

// the `$Type` is automatically assumed base on the `input` to the
// `once` function
MyType.func(5, "hello")

Meta-types with defaulted types

A meta-type can have types defaulted if the type cannot be assumed through other methods. This allows a type to be assumed without specification.

MyType$(Type = Integer) :: type {
    value : $Type

    +++ final : ()() = {
    }

    +++ final : ()(input : $Type) = {
        value = input
    }
}

// the `$Type` is automatically assumed based on the `input` to the constructor
myType1 : MyType = "hello"
myType1.value = "goodbye"

// the `$Type` is defaulted to `Integer` since it cannot be assumed based
// on a constructor that takes no arguments
myType2 : MyType
// OKAY: the `value` was assumed to be an `Integer` by default
myType2.value = 5

// the `$Type` is defaulted to `Integer` since it cannot be assumed based
// on a constructor that takes no arguments
myType2 : MyType
// ERROR: the `value` is a type of `Integer` by default and not a `String`
myType2.value = "not going to work"

Meta-types with compile-time constant values

A meta-type can can have arguments that are compile-time constants as an input to the definition of the meta-type.

MyType$(Value [[compile]] : Integer) :: type {
    value : Integer[$Value]
}

// the `$Value` is specified at compile-time 
myType : MyType$(5)

// OKAY: based on the compile-time definition this code will compile
myType.value[0] = 55
myType.value[1] = -43
myType.value[2] = 42
myType.value[3] = 117
myType.value[4] = 1009
// ERROR: `5` is out of range
myType.value[5] = 101

Meta-types with defaulted compile-time constant values

A meta-type can can have arguments that are compile-time constants as an input to the definition of the meta-type and these constants can be defaulted if not specified.

MyType$(Bits [[compile]] : Integer = size of Integer) :: type {
    bits : Boolean[$Bits]
}

// the `$Bits` is automatically assumed based on the default argument
myType : MyType

// OKAY: based on the compile-time definition this code will compile
myType.value[0] = true
myType.value[1] = false
myType.value[2] = true
// ERROR: `10000` is out of range
myType.value[10000] = false

Meta-function selection using the concept directive

For meta-functions, the [[concept]] directive can be used as a compile type mechanism to check if the function can be selected as a candidate for a given input, or output argument specified. If the code in the [[concept]] block fails to compile or returns false then the meta-function cannot be selected as a legal candidate by the caller. The executed code must evaluate to a true or false statement.

IsSelectable final : (result : Boolean)(ignored : ) [[concept]] = {
    if size of ignored > size of Integer
        return false
    // ...
    return true
}

MyType$(UseType [[concept=IsSelectable]] = Integer) :: type {
    valueA : $UseType
}

MyType$(UseType) :: type {
    valueB : $UseType
}

// the first `MyType` definition is the most specific and it is chosen
myType1 : MyType$(Integer)
myType1.valueA = 5

// the first `MyType` definition is most specific but this type
// fails the concept evaluation and thus the second definition is chosen
myType1 : MyType$(Integer[5])
myType1.valueB[0] = 5