Many languages have a rigid type system - that is, a type is finished being defined before the compiler even starts. Some languages use types as a suggestion, and the actual objects created from the types are free to vary from the plans at any time.
In Stardust, types are objects. They may be passed to and returned from functions. They may be stored in containers and they may be copied. The definition of a type is written in the same way that any other code is written.
But let's not get too extreme here. There need to be a few limitations. Namely, we don't want a type to change while we have instances of that type. To this end, a type may only be changed when it has no constructors. Once there are one or more constructors, the type is finished and may no longer be changed, aside from adding more constructors.
As a side effect of the way they are used, types are implicitly reference counted - if no variables holding the type exist and no instances created from the type exist, the type does not exist. This is important because types are easy to create all the time, and if they stuck around forever, applications would quickly run out of memory.
To this end types must be treated with respect. A function generally should not create and return a type each time it is invoked - instead it should cache the type and only create it on the first invocation. With types that depend on parameters, memoization is a well known design pattern that effectively solves this problem. This is effectively the same thing C++ compilers do with templates.
Another important note is that objects are strictly confined to their type. Unlike Python, you can't instantiate an object from a type and then add new members. However, in special cases where you know the fully derived type of an object, you can further derive the object in-place to a more derived type. The reverse operation - underiving - would be incredibly dangerous, and thus is not allowed.
In general, new instances of types should be obtained from functions, rather than directly using the type's constructors. This may be reminiscent of the static factory pattern in other languages, but to a much more detailed level - generally the type you will actually want to use will be accessible through a chain of type-modifying functions that act on existing types to create new types. You will almost never need to use the original type.
Many languages have a rigid type system - that is, a type is finished being defined before the compiler even starts. Some languages use types as a suggestion, and the actual objects created from the types are free to vary from the plans at any time.
In Stardust, types are objects. They may be passed to and returned from functions. They may be stored in containers and they may be copied. The definition of a type is written in the same way that any other code is written.
But let's not get too extreme here. There need to be a few limitations. Namely, we don't want a type to change while we have instances of that type. To this end, a type may only be changed when it has no constructors. Once there are one or more constructors, the type is finished and may no longer be changed, aside from adding more constructors.
As a side effect of the way they are used, types are implicitly reference counted - if no variables holding the type exist and no instances created from the type exist, the type does not exist. This is important because types are easy to create all the time, and if they stuck around forever, applications would quickly run out of memory.
To this end types must be treated with respect. A function generally should not create and return a type each time it is invoked - instead it should cache the type and only create it on the first invocation. With types that depend on parameters, memoization is a well known design pattern that effectively solves this problem. This is effectively the same thing C++ compilers do with templates.
Another important note is that objects are strictly confined to their type. Unlike Python, you can't instantiate an object from a type and then add new members. However, in special cases where you know the fully derived type of an object, you can further derive the object in-place to a more derived type. The reverse operation - underiving - would be incredibly dangerous, and thus is not allowed.
In general, new instances of types should be obtained from functions, rather than directly using the type's constructors. This may be reminiscent of the static factory pattern in other languages, but to a much more detailed level - generally the type you will actually want to use will be accessible through a chain of type-modifying functions that act on existing types to create new types. You will almost never need to use the original type.