Is there a CustomStringConvertible equivalent for type in Swift? - swift

I want to implement a protocol similar to CustomStringConvertible for a given type but for instance.
My need is to display type properties values without creating an instance valuer for this purpose. Of course I can add CustomStringConvertible protocol to this type then create an instance value only to invoke description. But I wonder if there is such feature in Swift?

Overview:
type(of:) is a function that returns the type of an instance in a String
self can be used on the Type
Code:
struct Something {
}
print(type(of: Something.self))

Create your own protocol that will include a static var.
static var desc: String { get set }
on classes that conform to your protocol use it like this:
MyClass.desc

Related

Create a Swift extension with a where clause that filters on a struct that takes a generic

I'm trying to create an extension on Set that uses a where clause so that it only works on a struct I have that accepts a generic. But I keep running into errors about it the extension wanting the generic to be defined in the struct
In this example I'm getting the following error, with the compiler hint suggesting I use <Any>: Reference to generic type 'Test' requires arguments in <...>
struct Test<T> {
var value : T
func printIt() {
print("value")
}
}
extension Set where Element == Test {
}
However, when I use <Any> in the struct, I'm getting this error: Same-type constraint type 'Test' does not conform to required protocol 'Equatable'
extension Set where Element == Test<Any> {
}
Any suggestions on how to get the where clause to accept the Test struct for any type I'm using in the generic?
Thanks for your help
This is a limitation of Swift's type system. There's no way to talk about generic types without concrete type parameters, even when those type parameters are unrelated to the use of the type. For this particular situation (an extension for all possible type parameters), I don't believe there's any deep problem stopping this. It's a simpler version of parameterized extensions, which is a desired feature. It's just not supported (though there is an implementation in progress).
The standard way to address this today is with a protocol.
First, a little cleanup that's not related to your question (and you probably already know). Your example requires Test to be Hashable:
struct Test<T: Hashable>: Hashable {
var value : T
func printIt() {
print("value")
}
}
Make a protocol that requires whatever pieces you want for the extension, and make Test conform:
protocol PrintItable {
func printIt()
}
extension Test: PrintItable {}
And then use the protocol rather than the type:
extension Set where Element: PrintItable {
func printAll() {
for item in self { item.printIt() }
}
}
let s: Set<Test<Int>> = [Test(value: 1)]
s.printAll() // value
Just one more note on the error messages you're getting. The first error, asking you to add Any is really just complaining that Swift can't talk about unparameterized generics, and suggesting it's fallback type when it doesn't know what type to suggests: Any.
But Set<Any> isn't "any kind of Set." It's a Set where Element == Any. So Any has to be Hashable, which isn't possible. And a Set<Int> isn't a subtype of Set<Any>. There' completely different types. So the errors are a little confusing and take you down an unhelpful road.
This is not possible. The where clause requires a specific data type and simply passing a Test will not work unless I specify something more concrete like Test<String>.
Thank you to Joakim and flanker for answering the question in the comments
If you want to add extension for Set with where clause your Test must confirm to Hashable protocol.
Your Struct must look like this.
struct Test<T: Hashable> : Hashable {
var value : T
func printIt() {
print("value")
}
func hash(into hasher: inout Hasher) {
hasher.combine(value.hashValue)
}
}
So you can't use Any for your extension you must specify type that confirm to Hashable protocol.

How to define a protocol that specializes a generic protocol, so that it can be used in type declarations?

I'm an Android developer learning iOS development and I'm facing this issue that is trivial with Kotlin/Java interfaces, but I can't get through it with Swift protocols.
Say we have this protocol:
protocol ValueStore {
associatedtype Value
var value: Value? { get set }
}
In Kotlin/Java, if I want to use a generic abstraction to define a variable type, I just use a generic interface with type parameter:
val stringStore: ValueStore<String>
Since this is not possible in Swift, I tried to create a specialized sub-protocol that defines the associated type:
protocol StringStore: ValueStore where Value == String { }
with the intent to use the latter like this:
let stringStore: StringStore
The above declaration is what I'm trying to achieve. Yet the compiler tells me Protocol 'StringStore' can only be used as a generic constraint because it has Self or associated type requirements.
Although in type declarations I can use a specialized generic concrete implementation, i.e. UserDefaultsValueStore<String>, this is against the dependency inversion principle.
Is it possible to specialize a protocol with associated type and still maintaining the level of abstraction?
If I understand the question correctly... Try this:
protocol ValueStoreType {
associatedtype Value
var value: Value? { get set }
}
struct ValueStore<T>: ValueStoreType {
var value: T?
}
Then you will be able to do:
var stringStore: ValueStore<String>

Swift Extension to Observable with Generic Type Constraint

I'm trying to add an extension to Observable.
The code looks like this:
extension Observable where Element == ApiResponse<ItemsContainer<T>>, T:Codable
I'm receiving the following exception: Use of undeclared type T.
So apparently this doesn't work.
The only thing missing is to constrain the generic inside ItemsContainer to conform to Codable.
Could be as simple as a syntactical issue or maybe I'm just not good enough with generics. Any help is appreciated!
Edit: To give the idea - ApiResponse and ItemsContainer look like this
public struct ApiResponse<ApiModel> {
public let data: ApiModel?
}
struct ItemsContainer<Items>: Codable where Items: Codable {
let items: [Items]
}
Issue
You cannot constraint extensions to a Model Type which holds generic values, without specifying the Model Type of the generic value.
You only constrain protocols based on their associatedtypes or generics based on their generic type, on the extension signature. Therefore T is not recognized, because none of the protocols or generic declare it.
Solution
So by keeping in mind what I said above, a Model Type needs to be fully defined on the extension context. But wait that does not satisfy our requirement, we want it to be generic!
Then we do not need a Model Type, we need a protocol!
We have two Model Types (ApiResponse and ItemsContainer) which we need to know the generic type, therefore we need two protocols for each of them.
ApiResponse
Let's create one named ApiResponseProtocol
public protocol ApiResponseProtocol {
associatedtype Model
var data: Model? { get }
}
Cool, the associatedtype Model will play our role as the generic value for the ApiModel on the object. Let's make ApiResponse conform to ApiResponseProtocol
public struct ApiResponse<ApiModel>: ApiResponseProtocol {
public let data: ApiModel?
}
Generic ApiModel here can be defined as Model from the protocol.
ItemsContainer
Next steps would be the same for the ItemsContainer
public protocol ItemsContainerProtocol {
associatedtype Item
var items: [Item] { get }
}
public struct ItemsContainer<Items>: Codable, ItemsContainerProtocol where Items: Codable {
public let items: [Items]
}
Extension
Now since we can access each of the generic types from the protocol (associatedtypes), the output would become something like this:
// This would be for example ApiResponse<ItemsContainer<Model>> where Model is a Model Type conforming to Codable
extension Observable where Element: ApiResponseProtocol, Element.Model: ItemsContainerProtocol, Element.Model.Item: Codable {}

Why am I allowed to set a read only property of a protocol using a struct that inherits said protocol?

I'm following a tutorial on the protocol oriented programming paradigm in which I'm confused by something I thought was rather simple which is read only properties of protocols or getters and setters. My understanding is that a read only property is signified by using the keyword 'get' when declaring a variable within a protocol. I was excited so I quickly coded created a playground to see if my thinking was accurate however it appears that I can still change the property which I thought was read only. What am I doing wrong to make it a true read only property to where I can't set it?
protocol FullName {
var firstName: String {get set}
var lastName: String {get set}
var readOnlyProperty: String {get}
}
struct OuttaBeerOuttaHere: FullName {
var firstName: String
var lastName: String
var readOnlyProperty: String = "Jack! Jack!...Line from Titanic"
}
var leonardoDicaprio = OuttaBeerOuttaHere.init(firstName: "Leonardo", lastName: "Dicaprio", readOnlyProperty: "WTF")
print(leonardoDicaprio.readOnlyProperty) //prints "WTF"
leonardoDicaprio.readOnlyProperty = "what now"
print(leonardoDicaprio.readOnlyProperty) //prints "what now"
What am I doing wrong to make it a true read only property to where I can't set it?
There is a difference between a protocol (a set of rules) and the type (i.e. your struct) that adopts the protocol.
Your protocol rule says that readOnlyProperty should be readable.
Your struct obeys by making it readable, and also makes it writable. That is not illegal, so all is well — and readOnlyProperty in your struct is read-write.
What would have been illegal would be the inverse, i.e. for the protocol to declare a property read-write but the adopter to declare it read-only. That situation didn't arise in your example, but if it had, the compiler would have stopped you.
Your protocol doesn't declare readOnlyProperty as a read-only property. It only requires that implementations of that protocol have at least gettable readOnlyProperty property. To allow mutations of that property or not is up to implementation itself.
From Docs
Here’s an example of a protocol with a single instance property requirement:
protocol FullyNamed {
var fullName: String { get }
}
The FullyNamed protocol requires a conforming type to provide a
fully-qualified name. The protocol doesn’t specify anything else about
the nature of the conforming type—it only specifies that the type must
be able to provide a full name for itself. The protocol states that
any FullyNamed type must have a gettable instance property called
fullName, which is of type String
it's a requirement from the protocol not a define

Get the class or struct that conforms to a protocol for use in function using Generics

My question if you have an Array of objects that conforms to a protocol. I want to iterate over the array calling a method on each member in the array. However the method I want to call is static and uses generics. I need to get the class of the element in the array to do this. how do you get the class of that object? Is it possible?
I am writing a library of generic functions in Swift.
I have a protocol called DBAble which has as function:
static func get<T: DBable >(id:Int) -> T?
I have an array of objects that conform to DBAble:
let objs:[DBAble] = []
I want to iterate over the array and call:
for obj in objs {
obj.get(id: anInt)
}
however I am getting this message:
Static member 'get' cannot be used on instance of type 'DBable.Protocol'
Is there a way of finding the class (or type of struct) of the object that conforms to the protocol? I understand that I can do:
if obj is User {
}
however this is not the solution I am looking for.
The problem with the application approach it that the type T in the bellow method
static func get<T: DBable >(id:Int) -> T?
has to be known at compile time, whereas the the dynamicType will give you the type at run time.
For anyone else considering this question the answer is no it is not possible to find the type for use in a generic function at runtime. As explained in the comments by #hamish
"element.dynamicType is the actual type of a given element in your array. Your get(_:) method has a generic parameter T that must be known at compile time"