spool-lang / Spool-Legacy-Repo

Legacy repo for the Spool programming language.
3 stars 0 forks source link

Generics #9

Open RedstoneParadox opened 5 years ago

RedstoneParadox commented 5 years ago

Overview

Generics are types that are types that are to be specified later, which can either be a primitive type or a programmer-defined type. These types are specified in Generic parameters and then called like so:


func example<T>(t : T) {

}

main {
    example<Foo>(new Foo())
}

You can specify multiple Generic parameters, separating them with commas as you would with normal parameters as well.


func exampleTwo<T, U>(t : T, u : U) {

}

main {

    exampleTwo<Foo, Bar>(new Foo(), new Bar())

}

Generic Multitype

Generic types in parameters can have the `multitype` keyword to specify that mutliple types can be passed into that parameter, similar to `varargs` parameters in functions (#5). Any parameters that use a `multitype` generic must be a `varargs` parameter and the number of arguments passed to the parameter using that type must be the same as the number of types specified. ```Silicon func genericMultitype(varargs t : T) { } main { genericMultitype(new Foo()) genericMultitype(new Foo(), new Bar()) //This last one will fail genericMultitype(new Foo(), new Bar()) } ``` In the above example, the first two calls succeed because the number of arguments being passed to the function is the same number of types specified. The last one fails because there is a mismatch between the number of types specified and the number of arguments passed.

Generic Implementations

**NOTE: This section is being moved to its own issue as Implementation blocks will be used for more than just generics.** When working with generics, it may be desirable to have a function do something different depending on the type that the generic type is later specified to be. You can declare special implementations for classes, traits and functions using the `impl` keyword: ```Silicon class Foo { func FooThing() { } impl class Foo { func GenericBar() { } } func Magic() { } impl func Magic() { } } ``` In the above example, any class Foo where T is specified as type Bar also has the function GenericBar and the second Magic function is called instead of the first is T is specified as type Red.

Multi-Generic Implementations

When using an `impl` for something that has multiple generic parameters, you need to use the `is` keyword to specify which generic parameters you are talking about if you do not wish to specify all of them. ```Silicon class Foo { impl class Foo { } impl class Foo { } impl class Foo { } } ``` Alternatively, if you do not want to specify the type for the `impl` block, you can use the `anytype` keyword instead. ```Silicon class Foo { impl class Foo { } } ``` When specifying a type from a `varargs` generic parameter, you may also use the `anytype` keyword to specify one possible type passed to that parameter or simply specify all the types. ```Silicon class Foo { impl class Foo { } impl class Foo { } } ```

Generic Implementation with Traits

When creating an generic implementation for a class, one can also specify additional traits to implement. In the below example, Foo has trait Bar if T is an instance of Example. ``` class Foo { impl Foo has Example { } } ``` This, of course, works with generic implementations that specify multiple generics.