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:
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.
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:
You can specify multiple Generic parameters, separating them with commas as you would with normal parameters as well.
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.
{
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.
{
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 {
}
}
```
{
impl Foo has Example {
}
}
```
This, of course, works with generic implementations that specify multiple generics.
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 FooMulti-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 FooGeneric 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