Issue with generic conversion method using RxSwift - swift

I have this result datatype called πŸ’ which wraps a type and a progress
public enum πŸ’<T> {
case Success(T)
case Progress(CGFloat)
}
class func rx_request(router: Router) -> Observable<πŸ’<AnyObject>>
This AnyObject needs to be transformed into a Mappable structure (ObjectMapper), so because I have several of these Mappable structs, I wanted to achieve something like this, a generic map that I can use:
class func rx_convert<T : Mappable>(value: πŸ’<AnyObject>) -> Observable<πŸ’<T>> {
return Observable.create { observer in
switch value {
case .Success(let object):
guard let convertedObject = Mapper<T>().map(object) else {
observer.onError(NetworkError.IncorrectDataReturned)
return NopDisposable.instance
}
observer.on(.Next(πŸ’<T>.Success(convertedObject)))
observer.on(.Completed)
case .Progress(let progress):
observer.on(.Next(πŸ’<T>.Progress(progress)))
break
}
return NopDisposable.instance
}
}
It seems the above definition is wrong because this cannot be compiled: Cannot explicitly specialize a generic function
.flatMapLatest({ _ in
🐯.rx_request(Router.Pipeline)
})
.flatMapLatest({ result -> Observable<πŸ’<ResponsePipeline>> in
🐯.rx_convert<ResponsePipeline>(result)
// Cannot explicitly specialize a generic function
})
What am I doing wrong here?

.flatMapLatest({ result -> Observable<πŸ’<ResponsePipeline>> in
return 🐯.rx_convert(result)
})
Because the closure passed to flatMapLatest is already typed to return an Observable<πŸ’<ResponsePipeline>>, compiler can infer the type for rx_convert to be πŸ’<AnyObject> -> Observable<πŸ’<ResponsePipeline>> so you can drop <ResponsePipeline> from the call.

Related

Returning the Concrete Type Based on Protocol in Swift

I have following code:
protocol Vehicle {
func start()
}
class Car: Vehicle {
func start() {
print("Start car")
}
}
class MotorCycle: Vehicle {
func start() {
print("Start MotorCycle")
}
}
let vehicles: [Vehicle] = [Car(), MotorCycle()]
func get<T: Vehicle>() -> some Vehicle {
let result = vehicles.first {
$0 === T.self
}
return result!
}
// so I should be able to do this!
let car = get<Car>().start()
Inside the get function I want to go iterate through vehicles and return the concrete type of the Vehicle, which is either Car or MotorCycle. Finally, I want to call start on the returned type. How can I achieve it?
This is how get should be written:
func get<T: Vehicle>(_ type: T.Type) -> T? {
vehicles.first(where: { $0 is T }) as? T
}
There might not be any Ts in vehicles, so we should return an optional T.
For the implementation, you should use is to check the type in the first(where:) closure. Then, cast to T.
You can't directly pass type arguments like <Car> to a function in Swift. Type arguments must always be inferred. So I used a formal parameter type to help Swift infer what T is.
Caller:
get(Car.self)?.start()
You can not compare an instance value with a type like this: $0 === T.self. You can use $0 is T instead.
And, when calling a generic function, you cannot explicitly specialize a generic function. The type has to be inferred, like #Sweeper said.

Cannot convert value of type 'Result<Data, Error>' to closure result type 'Result<T, E>'

I need help with generics and return types after conversion of older (not mine) code from swift 2 to swift 4
let cryptedJsonData = packet.encodeJSON()
.flatMap { $0.gzippedData() } //here I am getting error
Cannot convert value of type 'Result<Data, Error>' to closure result type 'Result<T, E>'
flatmap function
extension Result {
func map<U>( _ function: #escaping (T) -> U ) -> Result<U, E> {
return flatMap { .success( function( $0 ) ) }
}
func flatMap<U>( _ function: (T) -> Result<U, E> ) -> Result<U, E> {
switch self {
case .success(let value): return function(value)
case .failure(let error): return .failure(error)
}
}
}
gzippedData()
private let CHUNK_SIZE: Int = 2 ^ 14
func gzippedData() -> Result<Data, Error> {
var data = Data(count: CHUNK_SIZE)
return .success( data as Data)
}
Result
enum Result<T, E> {
case success(T)
case failure(E)
}
If you defined your own Result type, I suspect the problem stems from a type incompatibility between two definitions of Result in different modules.
Note that there is a Result type already defined in the Swift's standard library (see https://developer.apple.com/documentation/swift/result), whose implementation is pretty close to what you've posted. If you actually defined your own type, it is then possible that the Result returned by encodeJSON() differ from the Result returned by gzippedData(). Unfortunately, Swift handles clashing names very poorly, especially when those occur with names from the standard library.
Here's a way to replicate your problem:
// This enum is defined in my own source.
enum Result<T, E> {
case success(T)
case failure(E)
}
// This is an dummy error type, with the sole purpose of specializing `Result`.
enum SomeError: Error {}
// This extension has for sole purpose to add a method to `String` that returns
// an instance of *my* `Result` type.
extension String {
func foo() -> Result<String, SomeError> {
return .success(self)
}
}
// Now assume this function comes from a third party library that uses Swift's
// `Result` type, from the standard library.
func bar() -> Swift.Result<String, SomeError> {
return .success("Hello, World!")
}
// The following line will trigger the exact same error as yours, because the
// `Result` type that expects `flatMap`'s argument is not *my* `Result` type,
// but that of Swift's standard library.
bar().flatMap { $0.foo() }
Notice that this example will compile just fine if you replace Swift.Result by simply Result on bar's codomain (assuming you also provide a definition for flatMap).
If you defined your own Result type, I suggest you either use Swift's one, which I guess behaves exactly as you intended, or rename your own so that its definition no longer clashes with that in Swift's standard library.

Disambiguate a complex closure return type (foo -> _)

I'm using Alamofire's Result class. I've boiled Result down to a simple subset for presentation here.
public enum Result<Value> {
case success(Value)
case failure(Error)
}
extension Result {
/// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
public func mapError<T: Error>(_ transform: (Error) -> T) -> Result {
switch self {
case .failure(let error):
return .failure(transform(error))
case .success:
return self
}
}
}
I can't get a call to mapError to compile.
I make a simple Error class and a couple of results:
class MyError: Error { }
let s: Result<Bool> = .success(true)
let f: Result<Bool> = .failure(MyError())
Now I have something to call mapError on! Maybe I'll print any error before passing it along unchanged:
f.mapError() {
print($0)
return $0
}
Here Swift tells me "error: unable to infer complex closure return type; add explicit type to disambiguate". It doesn't seem that complex to me; mapError passes an Error into the closure, and expects one (or T:Error) returned, but I try placating Swift anyway:
f.mapError() { (e: Error)->Error in
print(e)
return e
}
Now Swift says, "error: cannot convert value of type '(Error) -> Error' to expected argument type '(Error) -> _'".
What is this _ return type? And how should I be writing the closure?
(I realize I can avoid calling mapError, but whatever, I can’t seem to call it. If I really wanted to, how would I even do so?)
You cannot pass a closure of type (Error) -> Error to mapError
because a protocol does not conform to itself, i.e. Error is not
a valid T for the constraint <T: Error>.
Making mapError non-generic
public func mapError(_ transform: (Error) -> Error) -> Result
makes both of your usage examples compile.
What is this _ return type [in the error]?
This means the compiler cannot determine a type, which might give a further clue as to what's going on...

Declare a function in Swift that returns a closure with a generic T.Type

we are trying to make a function in Swift , that returns a closure. The return type is as follows:
func completionBlock() -> (Response<T, NSError>) -> ()
where Response itself is a struct with 2 generics. The second will be always NSError, but the first depends on a switch.
Declaration of Response:
public struct Response<Value, Error: ErrorType> { ...
What we want to achieve is a function that will return a closure with a type that depends on a value of variable.
Depending on this value, and with a switch, it specifies one type or another, the only requirement for the generic parameter is that it must conform to a specific protocol, but we can't find a solution.
What we got so far is:
class BaseClass {
var endpoint: Int
...
func completionBlock() -> (Response<T, NSError>) -> () {
switch endpoint
{
case 1:
return getHandleResponseClosure(Car.self)
case 2:
return getHandleResponseClosure(Truck.self)
}
}
func getHandleResponseClosure<T: Mappable>(_: T.Type) -> (Response<T, NSError>) -> () {
let closure = { (_: Response<T, NSError>) -> () in
// ...
}
return closure
}
}
But this don't compile: "Use of undeclared Type T" at func completionBlock(), the type at this point is generic, it only requires to conform to protocol Mappable, but we don't know how to specify this.
Thanks!!, Greetings
While there are other problems with your code, the fundamental one is that generic types in method signatures must be declared directly after the name of the method. Take a look at completionBlock below. This code compiles and works.
struct Response<T, E: Error> {
}
struct Car {}
struct Truck {}
class BaseClass {
func completionBlock<T>() -> ((Response<T, NSError>) -> ()) {
return { response in /* What goes here? */ }
}
}
let c = BaseClass()
let r: (Response<Car, NSError>) -> () = c.completionBlock()
On a side note, I would replace struct Response<T, E: Error> with…
enum Response<T> {
case success(T)
case error(Error)
}

Implement an Equatable Void (None) type

I am implementing result objects using Result, it defines a boxed result like an Optional with an enum:
public enum Result<T, Error>: Printable, DebugPrintable {
case Success(Box<T>)
case Failure(Box<Error>)
...
}
The Equatable protocol defined for Result is as follows:
public func == <T: Equatable, Error: Equatable> (left: Result<T, Error>, right: Result<T, Error>) -> Bool
So, T must conform Equatable.
I would like to be able to have a Success that boxes a Void alike type. But, Void is not Equatable as it's defined as an empty tuple:
typealias Void = ()
The purpose is to be able to have Result types where I do not care about the a value when succeeds.
Is it possible to have an Equatable Void (or no value)?
As quick thoughts, there's the possibility to create an empty struct, but I am looking (if possible) for a more elegant solution.
Why not make Success contain an Optional? (Box<T?> or Box<t>?)?
The you could return nil. The downside is you would be left unwrapping your result
Trying again in Swift 2.0, it seems that Void can be initialized as Void():
public enum Result<T, Error: ErrorType> {
case Success(T)
case Failure(Error)
var value: T? {
switch self {
case .Success(let v):
return v
case .Failure(_):
return nil
}
}
/// Constructs a success wrapping a `value`.
public init(value: T) {
self = .Success(value)
}
/// Constructs a failure wrapping an `error`.
public init(error: Error) {
self = .Failure(error)
}
}
enum MyError: ErrorType {
case AnError
}
let result = Result<Void, MyError>(value: Void())
let success = result.value != nil // returns true
let error = result.value == nil // returns false
My solution to this issue is as you suggest to make a new struct that contains no members. I'll post it here for others who need a working solution.
Make it Decodable and Equatable. Now you can treat "Void" like a real type. You can just map to this value wherever you need it or map back out.
typealias VoidDecodableResult = ((Result<VoidDecodable, Error>) -> Void)
struct VoidDecodable: Decodable, Equatable {}
One thing is in your success block in a generic function you can just try to cast to VoidDecodable and return an instance.
if T.self is VoidDecodable.Type {
completion(.success(VoidDecodable() as! T))
return
}
Add a helper to make mapping out easier:
struct VoidDecodable: Decodable, Equatable {
var orVoid: Void {
()
}
}