I am seeing codes like below:
public class Signal<T> {
...
}
what does <T> mean?
That's what's known as a Generic. It means that the Signal class can operate on multiple types. For instance, you could instantiate an object of type Signal<String>, or perhaps of Signal<Foo>, or any other type.
Generics allow the same code to work with lots of different types of data, and still retain type safety.
Related
I am very confused around the concept of "metatype" in the Swift language.
Suppose I have:
class SomeClass {
class func callClassMethod() {
print("I'm a class method. I belong to my type.")
}
func callInstanceMethod() {
print("I'm an instance method. I belong to my type instance.")
}
}
According to the definition:
A metatype type refers to the type of any type, including class types,
structure types, enumeration types, and protocol types.
SomeClass is already a type called SomeClass, then what exactly is the type of SomeClass?
I can create a SomeClass.Type variable:
let var1 : SomeClass.Type = SomeClass.self
var1.doIt();//"I'm a class method. I belong to my type."
but I can also call the static/class function this way:
SomeClass.doIt();//"I'm a class method. I belong to my type."
Are they the same?
They are the same because the compiler guarantees that class names are unique (Swift is name spaced by module), so there is only one thing that is of SomeClass.Type and that is the class SomeClass. The meta type is often useful when you just want to pass the type of something to a function but you don't want to pass an instance. Codable does this for instance:
let decoded = try decoder.decode(SomeType.self, from: data)
If you could not pass the meta type here then the compiler could still infer the return type based on an annotation on the left, but it would be less readable:
let decoded: Sometype = try decoder.decode(data)
Some libraries do use the type inference style instead, although the Apple preference seems to be to use the meta type as its clearer what the right side of the assignment is on its own, without relying on type inference from the left side of the assignment.
I'm trying to figure out how to implicitely set a Generic (type of a argument) in a class without changing the type of the whole class to something like SomeTestClass< SomeType>, where the owner of an object has to know the type of the generic.
Example
This example DOESNT work! This is how I would like it to work
protocol SomeTestProtocol {
associatedtype T
init(arg: T)
}
Don't want to use SomeTestClass< T>
because the class, which holds this class
wont know the type of the generics used
class SomeTestClass: SomeTestProtocol {
required init(arg: T) {
}
// Use T outside the init-scope
}
Note: The Protocol is just a try for a work-around! It isn't necessary for the final solution
So the main question is: How can I use T outside the init-scope in the class below without using a class-generic, which must be known when owning an object
class SomeTestClass2/*< T>*/ {
init(arg: T) {
}
// Use T outside the init-scope
}
Thanks for your help!
Important note, the T from associatedtype T and the T from init<T> can be different types. They are both defining a generic type with different scopes an could be different. If you want them to be the same, the init should be
init(arg: T)
If SomeTestClass is always going to use the same type, you can add
typealias T = Int // or something
or implement the init as
required init(arg: Int)
It works if you get rid of the associatedtype T from the protocol. Though this removes SomeTestClass.T form existence.
If you declare an associated type in a protocol, that type will become generic over different implementations of the protocol, but each conforming class will need to assign a concrete type to that associate type as a typealias (which can be done implicitly by declaring all variables/functions using the associated type with the same concrete type), so your conforming types won't be generic.
If you want to have generic methods in your conforming classes, you'll need to make the classes themselves generic.
If you only want access to T outside of init, then you just store T in a property:
class S {
let theType: Any.Type
init<T>(arg: T) {
theType = T.self
}
}
I suspect you actually want something different than what you've said you want. I suspect you want to store arg. But if so, what do you plan to do with arg if you have no idea what its type is? What methods can you call? What function could it be the return value of? Without resorting to as?, there's nothing you can do with T (and reliance on as? generally means you've misunderstood your types).
So you need to start with how you want T and SomeTestClass to be used. Without that, it's impossible to discuss how T should be stored (the storage is irrelevant if you never use it).
In Swift, if I declare a class based on generic type:
class BasicRequest<T>{
}
class StartRequest: BasicRequest<BasicPayload> {
}
And then try to use generic method:
class SocketClient {
public func send(request: BasicRequest<Any>){
}
}
It does not compile:
SocketClient.shared.send(request: StartRequest())
with message
Cannot convert value of type 'StartRequest' to expected argument
type 'BasicRequest'
Why actually? The type info should be available across the inheritance chain.
Generics are invariant in Swift, which in your case means that BasicRequest<Any> is not compatible with BasicRequest<BasicPayload>, even if BasicPayload is compatible with Any. This is how invariants work, there's little you can do in this direction.
What you can do, is to make send generic, thus allowing any kind of BasicRequest instances to be passed:
public func send<T>(request: BasicRequest<T>){
}
I have to pass an interface as a parameter to a function. Interface is generic a.k.a. has a associated type. I couldn't find a good way to do that. Here is my code:
protocol IObserver : class {
typealias DelegateT
...
}
class Observer: IObserver {
typealias DelegateT = IGeneralEventsDelegate // IGeneralEventsDelegate is a protocol
...
}
func notify(observer: IObserver) { ... } // here I need a type for observer param
I found that this will work:
func notify<T: IObserver where T.DelegateT == IGeneralEventsDelegate>(observer: T) { ... }
, but come on that is too complicated. What if I want to save this param in class variable, should I make the whole class generic, just because of this function.
It is true that I'm C++ developer and I'm new to the Swift language, but the way the things are done are far too complicated and user unfriendly ... or I'm too stupid :)
If you use typealias in a protocol to make it generic-like, then you cannot use it as a variable type until the associated type is resolved. As you have probably experienced, using a protocol with associated type to define a variable (or function parameter) results in a compilation error:
Protocol 'MyProtocol' can only be used as a generic constraint because it has Self os associated type requirements
That means you cannot use it as a concrete type.
So the only 2 ways I am aware of to use a protocol with associated type as a concrete type are:
indirectly, by creating a class that implements it. Probably not what you have planned to do
making explicit the associated type like you did in your func
See also related answer https://stackoverflow.com/a/26271483/148357
This isn't a compiler bug, except the last example (Outer3), because the language reference doesn't say you can do it. But why can't you declare a nested type within a protocol? It would be a useful way to group related types. If you try, you get the following errors in beta 4:
protocol Outer1 {
protocol Inner1 {} // Type not allowed here
}
protocol Outer2 {
struct Inner2 {} // Type not allowed here
}
protocol Outer3 {
class Inner3 {} // No error, looks promising - BUT!
}
class Test : Outer3 {} // Type 'Test' does not conform to protocol 'Outer3'
The last example, class within protocol, is intriguing because it hints at a partial implementation where the protocol accepts the nested class but then the protocol cannot be implemented. Does this hint that nested types within protocols are on the cards for Swift 2.0?