Unwrapping generic type - swift

Let's say I have some variable with type
let someVariable: SomeType<AnotherType?>
and I am sure that this concrete instance not contain any nil of AnotherType?. Is there is general way to convert it to SomeType<AnotherType>? For example, I need this convert for use someVariable in some function.

It could go along these lines:
protocol _Optional {
associatedtype _Wrapped
func unveil() -> _Wrapped?
}
extension Optional: _Optional {
typealias _Wrapped = Wrapped
func unveil() -> _Wrapped? { return self }
}
extension SomeType where T: _Optional {
func rewrap() -> SomeType<T._Wrapped>? {
guard let _value = value.unveil() else { return nil }
return SomeType<T._Wrapped>(value: _value)
}
}
struct SomeType<T> {
let value: T
}
let someValue = SomeType<Int?>(value: 42) // SomeType<Int?>
let rewrappedValue = someValue.rewrap() // SomeType<Int>?
let forceUnwrappedValue = someValue.rewrap()! // SomeType<Int>
Specifics depend on details of the particular implementation for SomeType (I use a simplest assumption in my example).

Related

A way to compare generics in Swift only if they conform to Equatable

Wondering if there's a good way to do this or not:
I have a #propertyWrapper named "Enhanced" that I use. I use the wrappedValue.set to do some actions, and I would also like to do some further actions if the property is Equatable.
Currently, the code looks like this:
#propertyWrapper
class Enhanced<T: Equatable>: Codable
{
private var value: T
var projectedValue: Enhanced<T> { self }
var wrappedValue: T
{
get { value }
set { set(newValue, notify: nil) }
}
func set(_ proposedValue: T, notify: Bool?)
{
let oldValue = value
let newValue = proposedValue
let changed = newValue != oldValue
if changed { /* more magic here */ }
value = newValue
}
}
Now I would like to remove the Equatable conformance over the generic T, but still be able to compare the old and new values IF the generic T conforms to Equatable.
I've tried a handful of techniques, all of which dead end somewhere. My latest was this:
let changed: Bool
switch T.self
{
case let equatableType as any Equatable.Type:
if
let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = newEquatableValue != oldEquatableValue
}
default:
changed = true
}
...but the error is an understandable Binary operator '!=' cannot be applied to two 'any Equatable' operands.
I tried different patterns to cast the generic type T into an Equatable and silently fail if the generic does not conform, but even if they do, the resulting "cast" types I get back aren't equatable themselves.
Any revelations to the proper pattern would be great!
After some deep web-sleuthing, I came across a snippet of code that does the magic I need:
private extension Equatable
{
func isEqualTo(_ rhs: Any) -> Bool
{
if let castRHS = rhs as? Self
{
return self == castRHS
}
else
{
return false
}
}
}
(HT to neonichu/equalizer.swift on GitHub)
With this bit of pseudo type-erasure, I can make this work:
let changed: Bool
if let oldEquatableValue = oldValue as? any Equatable,
let newEquatableValue = newValue as? any Equatable
{
changed = oldEquatableValue.isEqualTo(newEquatableValue) == false
}
else
{
changed = true
}
By using an extension on Equatable that does further casting of the values, this allows for these two values to be compared (and fail if they are not the same).
Hope this helps someone else!

Issue about extending Optional with Generic Type in Swift

I was trying to make an extension for safe unwrapping, and I was working in 2 version of it, one long code form, second short code! But unexpectedly they do not work! So far as I can see to my code, I just made all things correct! What I am missing to fix both version?
struct ContentView: View {
let test: String? = "Hello, World!"
var body: some View {
Text(test.safeUnwrapV1(defaultValue: "Empty!"))
Text(test.safeUnwrapV2(defaultValue: "Empty!"))
}
}
extension Optional {
func safeUnwrapV1<T>(defaultValue: T) -> T {
let wrappedValue: T? = (self as? T?) ?? nil
if let unwrappedValue: T = wrappedValue { return unwrappedValue }
else { return defaultValue }
}
func safeUnwrapV2<T>(defaultValue: T) -> T {
return (self as? T) ?? defaultValue
}
}
There's no need to define your own generic type parameter. Optional is already generic and its generic type parameter is called Wrapped. So you simply need to declare the type of the default value to be Wrapped.
extension Optional {
func defaultValue(_ value: Wrapped) -> Wrapped {
self ?? value
}
}
struct ContentView: View {
let test: String? = "Hello, World!"
var body: some View {
Text(test.defaultValue("Empty!"))
}
}
extension Optional {
func safeUnwrap(_ defaultValue: Wrapped) -> Wrapped {
switch self {
case let value?: return value
case nil: return defaultValue
}
}
}
Or even
extension Optional {
func safeUnwrap(_ defaultValue: Wrapped) -> Wrapped {
self ?? defaultValue
}
}
But as was pointed out, this is more wordy and less idiomatic than just using the ?? operator.
Make your extension like this.
extension Optional {
func safeUnwrapV1<T>(defaultValue: T) -> Wrapped {
guard let value = self else {
return defaultValue as! Wrapped
}
return value
}
}
EDIT: As #Rudedog suggest no need to define generic here
extension Optional {
func safeUnwrapV1(defaultValue: Wrapped) -> Wrapped {
guard let value = self else {
return defaultValue
}
return value
}
}
I would constrain Optional generic Wrapped type to LosslessStringConvertible:
extension LosslessStringConvertible {
var string: String { .init(self) }
}
extension Optional where Wrapped: LosslessStringConvertible {
var string: String { self?.string ?? "" }
func string(default value: Wrapped) -> String {
self?.string ?? value.string
}
}
Usage:
var double1 = Double("2.7")
var double2 = Double("a")
print(double1.string(default: 0))
print(double2.string(default: 0))
This would print:
2.7
0

Provide class metadata to the generic in swift (Codable)

I have a method that works on Codables and does, among other things, this:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
return nil // or whatever
}
Then i can get myName as the class name at run time to get the right data to create an instance of T.
Now some of my Codable need to provide a custom name for this.
So while i could edit ALL of my codables (a few hundred models) to conform to some protocol that provides name, i really want to avoid doing it.
Since there are no custom attributes in Swift, i concocted this;
protocol MetadataProvidingCodable {
static func customName() -> String
}
Then in my generic i can check whether the T conforms to it:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
if T.self is MetadataProvidingCodable.Type {
myName = ... // Get customName() from T without an instance???
}
return nil // or whatever
}
But my problem is that i need to be able to call my static func on the T type without having an instance of T. Is that possible?
You can type cast the T.self as MetadataProvidingCodable.Type like that:
func doWhatever<T>() -> T? where T: Codable {
var myName = String(describing: T.self)
if let type = T.self as? MetadataProvidingCodable.Type {
myName = type.customName()
}
return nil // or whatever
}
Edit: If you can somehow move the common logic to a separate function, you can override the doWhatever() function with another one that return a type that conforms to both Codable and MetadataProvidingCodable.
Then the compiler will figure out what function will call based on the return type:
func doWhatever<T>() -> T? where T: Codable {
print("doWhatever: Codable")
var myName = String(describing: T.self)
return nil
}
func doWhatever<T>() -> T? where T: Codable & MetadataProvidingCodable {
print("doWhatever: Codable & MetadataProvidingCodable")
var myName = T.customName()
return nil
}
struct Example1: Codable {}
struct Example2: Codable, MetadataProvidingCodable {
static func customName() -> String {
return "Example2"
}
}
let example1: Example1? = doWhatever()
let example2: Example2? = doWhatever()
// prints
// doWhatever: Codable
// doWhatever: Codable & MetadataProvidingCodable

Using swift Generic Types with protocols

I've tried to use generic type with protocol:
class Weak<T: AnyObject> {
weak var value: AnyObject?
init (value: AnyObject) {
self.value = value
}
}
protocol SomeProtocol: AnyObject {
func doSomething()
}
func createWeak(object: SomeProtocol) -> Weak<SomeProtocol> {
return Weak<SomeProtocol>(value: object)
}
class SomeClass: SomeProtocol {
func doSomething() {
print("Some 2")
}
}
let temp = SomeClass()
let weakObject = createWeak(object: temp)
weakObject.value?.doSomething()
And got the compiler error:
error: 'SomeProtocol' is not convertible to 'AnyObject'
return Weak(value: object)
But without AnyObject constraint it works fine
class Weak<T> {
var value: T?
init (value: T) {
self.value = value
}
}
protocol Protocol {
func doSomething()
}
class Class: Protocol {
func doSomething() {
print("This is class")
}
}
func createWeak(object: Protocol) -> Weak<Protocol> {
return Weak(value: object)
}
let temp = Class()
let weakObject = createWeak(object: temp)
weakObject.value?.doSomething()
Why I can't use protocols inherited form AnyObject in generic classes?
Swift protocols are incomplete types, which means that you can't use them in places like generic arguments, as the compiler needs to know the whole type details so it can allocate the proper memory layout.
Your createWeak function can still be used if you make it generic:
func createWeak<T: SomeProtocol>(object: T) -> Weak<T> {
return Weak<T>(value: object)
}
The above code works because the compiler will generate at compile time a function mapped to the concrete type you pass.
Even better, you can make the initializer generic, and convert Weak to a struct (value types are preferred Swift over reference ones):
struct Weak<T: AnyObject> {
weak var value: T?
init(_ value: T) {
self.value = value
}
}
which you can use it instead of the free function:
let weakRef = Weak(temp)

Swift Protocol as Generic Parameter

Given this class:
class ServiceRegistry {
var store = [String : AnyObject]()
var allRegisteredType: [String] {
return store.map { $0.0 }
}
func registerInstance<T>(instance:AnyObject, forType type: T.Type) {
store[String(type)] = instance
}
func instanceForType<T>(type: T.Type) -> T? {
return store[String(type)] as? T
}
}
Is there a way I can enforce that T must be a Protocol, without using the #obj?
This is a modified version of my type assertion technique. I added the "as? AnyClass" assert so that the type can only be of protocol type. There might be a more elegant way of doing this but going through my notes and research about class assertion this is what I came up with.
import Foundation
protocol IDescribable:class{}
class A:IDescribable{}
class B:A{}
let a = A()
let b = B()
func ofType<T>(instance:Any?,_ type:T.Type) -> T?{/*<--we use the ? char so that it can also return a nil*/
if(instance as? T != nil && type as? AnyClass == nil){return instance as? T}
return nil
}
Swift.print(ofType(a,A.self))//nil
Swift.print(ofType(a,IDescribable.self))//A
Swift.print(ofType(b,B.self))//nil