In out and _ Generics

When I want to abstract a generic away from a generic type, I currently need to create a base class.

protocol A {}
protocol B {}

class AnyC: {}
class C<T>: baseC {}

func f(anyC: AnyC)
f(anyC: C<Int>())

I feel that the base class should be built into the generic system. The base generic type could be specified by C<>. This syntax similar to switch statements of enum value with associated values. case e():
All C's can be safely and automatically casted to C<_> regardless of the generics.

In order for this to occur, any function or variable of the C that uses the generics would be striped away. use of these functions or variables would produce an error.

I also propose "in" and "out" generics similar to how functions can have inout parameters.

C strips away all functions and variables that have an output of G. With all outputs of G striped away, C can be automatically and safely casted to C<in {something that inherits G including G}>

C strips away all functions and variables that have an input of G. With all inputs of G striped away, C can be automatically and safely casted to C<out {anything that G inherits from including G}>

//given:
protocol A {}
protocol B: A {}
struct S<T>

//Then:
S<in A>: S<in B>, S<_>
S<out B>: S<out A>, S<_>
S<A>: S<in A>, S<out A>, S<in B>, S<_>
S<B>: S<in B>, S<out B>, S<out A>, S<_>

"in", "out", and "_" would also apply to generics with multiple types.

C<in A, out B>: C<in B, out A>

A generic type could restrict its generics to restrict in and out on the declaration of a type.

protocol Type {}
class Sender<T: in Type> {}
class Receiver<T: out Type> {}

When this is the case, defining a function or variable that uses the type in the wrong direction should produce an error for example:

protocol Type {}
class Sender<T: in Type> {
    func send(t: T) {} //no error
    func receive() -> T {} //Should error as T is restricted to in.
}
class Receiver<T: out Type> {
    func send(t: T) {} //Should error as T is restricted to out.
    func receive() -> T {} //no error
}

Since initializers create new objects, they would not need to conform the the in/out restriction.

"inout" could also be added in the same way "in" and "out" are, but since this is the current and functionality, it would be the default and probably add little or no value.

This feature would allow allow more flexibility of Generics types.

1 Like