# Type Instances

The goal of type instances is not to permit Java-style reflection, but instead to unify the handling of parametric types and normal arguments. Special syntax for type parameters (generics) should be avoided and, ideally, types should be treated as one form of feature similar to the way that lambdas or choice types are features as well.

Type parameters currently use a special syntax in feature declarations and in feature calls, similar to generics in Java:

stack(T type, maxSize i32) is push(x T) is ... pop T is ... sp := stack point 300It would be nicer to have a uniform syntax as in

stack(T, maxSize i32) is push(x T) is ... pop T is ... sp := stack point 300

## Type instances

Every feature that defines a type should declare an implicit inner
feature `type`

that returns a unit-type value with information on its
type. The result is a subclass of Type:

Type ref is asString string is intrinsic byteSize is intrinsic AnyFeatureDefiningAType.type : Type is intrinsic

Then, we could declare a feature with type parameter as follows:

stack(T Type, maxSize i32) is push(x T) is ... pop T is ... sp := stack point.type 300

## Constraint type parameters

## Syntactic Sugar

In argument field declarations, a fully capitalized name could be used to
implicitly assume `Type`

as its type.

When passing an argument to a type parameter, the `.type`

could be added automatically.

So we get

stack(T, maxSize i32) is push(x T) is ... pop T is ... sp := stack point 300

## Inner features of types

### Defining Inner Features

Types could provide an environment to define global features associated to a
type but not requiring an instance such as special values
like `i32.type.one`

or monoids `string.type.concat`

.

i32.type.one => 1 string.type.concat : Monoid string is redef infix ∙ (a, b string) => a + b redef infix == (a, b string) => a == b redef e => ""

### Abstract Inner Features

For this to be most useful, types of (abstract) features such
as `numeric`

should be able to define features that can be inherited
and redefined by concrete heirs:

numeric(T numeric T) is type.zero is abstract type.one is abstract type.sum : Monoid T is redef infix ∙ (a, b T) T is a + b redef infix = (a, b T) bool is a == b redef e T is zero i32 : numeric i32 is redef type.zero => 0 redef type.one => 1 # type.sum is inherited from numeric.type.

So, the type instances should duplicate the inheritance relation of their underlying features.

### this.type in type instances

In the previous example, feature `numeric`

has a type
parameter `T`

that is used in `numeric.type`

. This type
parameter should be replaced by this.type, so
this should work for type parameters as well:

numeric is type.zero is abstract type.one is abstract type.sum : Monoid numeric.this.type is redef infix ∙ (a, b numeric.this.type) numeric.this.type is a + b redef infix = (a, b numeric.this.type) bool is a == b redef e T is zero i32 : numeric i32 is redef type.zero => 0 redef type.one => 1 # type.sum is inherited from numeric.type.

### Inner Fields

Inner fields of types would provide a mechanism similar to static fields in Java, with all the horror that static fields cause: When and in what order should they be initialized, what happens if they are modified, how are race conditions avoided, etc...

On the other hand, inner fields in types could define, e.g., default instances such as 'zero' and avoid overhead of re-creating these instances for every use. But then, default instances are typically cheap to create and if they were expensive, we need a means for memoization anyways to reuse results of expensive calls, so that could be applied to inner features of types as well.

For now, it seems reasonable to forbid fields as inner features for types and make sure type instances are unit values.

## Type instances and equality checks

Defining a comparator operation in a type instance might solve the problem of different equality operations along the inheritance chain discussed in the section on Equality.

The definition of *hasEquals* could look something like this:

hasEquals is type.equals(a,b hasEquals.this.type) bool is abstract infix = (b this.type) bool is this.type.equals hasEquals.this b

## Type instances and monads

Without type instances, Fuzion has problems implementing operations that
do not require an instance of a particular type. An example is the
function *monad.return* that wraps a value of the type parameter by the
monad, so there is no instance of the monad involved in this operation.

*monad.return* should really be *monad.type.return*, i.e., it is
not applied to an instance of *monad*, but to the unit
type *monad.type*.