I am running into a compiler issue. It happens when I use SwiftTask, and Async, here is a sample:
//-- Generic Method
import Async
import SwiftTask
class AsyncTask {
func background<T>(job: (((Float -> Void), (T -> Void), (NSError -> Void), SwiftTask.TaskConfiguration) -> Void)) -> SwiftTask.Task<Float, T, NSError> {
return SwiftTask.Task<Float, T, NSError> { (progress: (Float -> Void), fulfill: (T -> Void), reject: (NSError -> Void), configure: SwiftTask.TaskConfiguration) -> Void in
Async.background {
job(progress, fulfill, reject, configure)
return
}
return
}
}
}
Now that compiles, but when I try to use the generic like so:
//-- Using the Generic Method
let task = AsyncTask.background<MyAwesomeObject> { progress, fulfill, reject, configure in
let obj = MyAwesomeObject()
//-- ... do work here
fulfill(obj)
return
}
I then get the following error Cannot explicitly specialize a generic function
The way you try to specialise a generic function is called explicit specialization.It’s not a syntax error, it’s a semantic error. At parse time, there’s no difference between
let x = foo<Int>()
and
let arr = Array<Int>()
But in the current version of Swift language which is 5.1 this is not permitted but in future versions it could be permited to use it.
Today, a type arguments of a generic function are always determined via type inference. For example, given:
func foo<T>()
let x = foo() as Int
// or
let x: Int = foo()
or T is determined via the argument's type. In that case an additional argument must be introduced into a method signature
func foo<T>(t: T)
let x = foo(Int.self)
Give the closure an explicit type to fix T:
let task = AsyncTask.background{ (progress: Float -> Void, fulfill: MyAwesomeObject -> Void, reject: NSError -> Void, configure: SwiftTask.TaskConfiguration) -> Void in
let obj = MyAwesomeObject()
//-- ... do work here
fulfill(obj)
}
Related
Let's say I have the following enums :
enum SomeEnum {
V1(i32),
V2(f32),
V3(String),
V4(Vec<i32>),
}
#[derive(Debug)]
enum SomeEnumConversionError {
OutOfTypeRange,
StringParse,
TooManyElements,
}
And I want the following trait to work for both values and references of the first enum; So I implement it for the reference to save some time and a few lines of duplicate code (Considering I have to do almost the same for all other variants and the real enum I'm working with has about 30 variants) :
impl TryFrom<&SomeEnum> for i32 {
type Error = SomeEnumConversionError;
fn try_from(value: &SomeEnum) -> Result<Self, Self::Error> {
match value {
SomeEnum::V1(v) => Ok(*v),
SomeEnum::V2(v) => {
let i = *v as i32;
if (i as f32) == *v {
Ok(i)
} else {
Err(SomeEnumConversionError::OutOfTypeRange)
}
}
SomeEnum::V3(v) => v
.parse::<i32>()
.map_err(|_| SomeEnumConversionError::StringParse),
SomeEnum::V4(v) if v.len() == 1 => Ok(v[0]),
SomeEnum::V4(v) => Err(SomeEnumConversionError::TooManyElements),
}
}
}
impl TryFrom<SomeEnum> for i32 {
type Error = SomeEnumConversionError;
fn try_from(value: SomeEnum) -> Result<Self, Self::Error> {
(&value).try_into()
}
}
Now, if I have the following code as an example usage :
fn some_func() {
let a = SomeEnum::V4(vec![4i32]);
let b: Result<i32, _> = a.try_into();
println!("{}", b.unwrap());
}
The question is, how is this (performance-wise, considering the conversion might be called in a loop) compared to when I implement the trait for both value and reference type (rather than just calling it by reference from value implementation) ?
Does the compiler do some optimization magic here that will eventually make it behave as if the variable a has been actually moved to the function implementation calls ?
Or do I need to also implement the whole conversion function for the value type to ensure this ?
If there are better alternatives to the whole plan, I'm all ears.
I am trying to make an extension for Alamofire in Swift, and have this code:
import Foundation
import Alamofire
protocol JsonResponse
{
init?(json : NSObject)
}
extension Request
{
func responseObject<T : JsonResponse, Error: ErrorType>(completionHandler : Result<T,Error> -> Void) -> Self
{
return responseJSON(completionHandler: {r in
let result = r.result
guard result.isSuccess else {
completionHandler(.Failure(result.error!))
return
}
let obj : T? = T(json : result.value as! NSObject)
let success : Result<T,Error> = .Success(obj!)
completionHandler(success)
})
}
}
Which gives me the compiler error:
Error:(21, 36) type of expression is ambiguous without more context
Interestingly, when I comment out this line, it compiles:
// completionHandler(.Failure(result.error!))
How do I give Swift enough type information to make this work ?
The problem is that is doesn't know the type of the Result type (.Failure(result.error!)) is. Being the failure case there is nothing that tells the compiler what T will be.
You can write it out in full Result<T,Error>.Failure(result.error!).
I made it compile with this:
completionHandler(Result<T,Error>.Failure(result.error! as! Error))
One problem is the type inferring and the other is that result.error is a optional NSError. I don't know if NSError can be cast to ErrorType tho..
extension Request
{
// this function declares return type Self (aka Request)
func responseObject<T : JsonResponse, Error: ErrorType>(completionHandler : Result<T,Error> -> Void) -> Self
{
// here you return ... I don't know, but the type
// is return type of the function responseJSON,
// probably Void too
return responseJSON(completionHandler: {r in
let result = r.result
guard result.isSuccess else {
completionHandler(.Failure(result.error!))
// here you return Void
return
}
let obj : T? = T(json : result.value as! NSObject)
let success : Result<T,Error> = .Success(obj!)
completionHandler(success)
})
}
}
i guess you need something like
func responseObject<T : JsonResponse, Error: ErrorType>(completionHandler : Result<T,Error> -> Void) -> Void
I'm trying to convert my app from Swift 1.2 to Swift 2.0 and I'm encountering the following error:
class B {
func test() -> Promise<A> {
return Promise<A> { (fulfill, reject) -> Void in
anotherPromise.then { _ -> Void in
return fulfill(A()) // Class declaration cannot close over value 'fulfill' defined in outer scope
}
}
}
}
How can I make B (or the then closure) capture fulfill properly?
PS: Promise comes from PromiseKit, and I'm running Xcode 7 beta 1.
You should be able to workaround this by assigning fulfill to a local that you capture instead.
class B {
func test() -> Promise<A> {
return Promise<A> { (fulfill, reject) -> Void in
let innerFulfill = fulfill // close on this instead
anotherPromise.then { _ -> Void in
return innerFulfill(A()) // Class declaration cannot close over value 'fulfill' defined in outer scope
}
}
}
}
Consider the following code:
class Test {
func func1(arg1: Int) -> Void {
println(arg1)
}
var funcArr: Array< (Int) -> Void > = [func1] // (!) 'Int' is not a subtype of 'Test'
}
I'm trying to store the method func1in an array, but as you can see, this doesn't seem to work because func1supposedly only takes an argument of type Test. I assume this has something to do with methods needing to be associated with an object.
For some more clarification, have a look at the following code where I let swift infer the type of the array:
class Test {
func func1(arg1: Int) -> Void {
println(arg1)
}
var funcArr = [func1]
}
Test().funcArr[0](Test()) // Compiles, but nothing gets printed.
Test().funcArr[0](1) // (!) Type 'Test' does not conform to protocol 'IntegerLiteralConvertible'
Test().func1(1) // Prints '1'
A possible workaround for this problem is moving func1outside of the class like so:
func func1(arg1: Int) -> Void {
println(arg1)
}
class Test {
var funcArr = [func1]
}
Test().funcArr[0](1) // Prints '1'
This works fine for this simple example, but is less than ideal when I actually need to operate on an Object of type Test in the function. I can of course add another parameter to the function to pass an instance of Testto the function, but this seems clunky.
Is there any way I can store methods in an array?
Ultimately, what I want to be able to do is testObject.funcArr[someInt](someParam) and have that function work as a method belonging to testObject. Any clever workarounds are of course also welcome.
Instance methods in swift are just curried functions, and the first argument is implicitly an instance of the class (i.e. self). And that's why these two are equivalent:
Test().func1(0)
Test.func1(Test())(0)
So when you try to put that function in the array, you're reveling its real nature: the method func1 on Test is actually this class method:
class func1(self_: Test)(arg1: Int)
So when you refer to simply func1 (without an "instance context") it has type Test -> Int -> Void, instead of the expected Int -> Void, and that's why you get the error
Int is not a subtype of Test
So the real issue is that when you store the methods in funcArr the instance is not known yet (or if you will, you're referring the function at a class level). You can work around this using a computed property:
var funcArr: [Int -> Void] { return [func1] } // use a computed property
Or another valuable option could be simply to acknowledge the real type of func1 and explicitly passing the instance. E.g.
...
var funcArr = [func1]
...
let test = Test()
let func1 = test.funcArr[0]
func1(test)(0) // prints 0
update
Freely inspired by this other Q/A (Make self weak in methods in Swift) I came up with a similar solution that stores the method references.
func weakRef<T: AnyObject, A, B>(weakSelf: T, method: T -> A -> B) -> A -> B {
return { [unowned weakSelf] in { a in method(weakSelf)(a) } }()
}
class Test {
var methodRefs: [Int -> Void] = []
init() {
methodRefs.append(weakRef(self, Test.func1))
}
func func1(arg1: Int) {
println(arg1)
}
}
In order to store a method, you should remember that the method is invoked on a class instance. What's actually stored in the array is a curried function:
(Test) -> (Int) -> Void
The first function takes a class instance and returns another function, the actual (Int) -> Void method, which is then invoked on that instance.
To make it more explicit, the array type is:
var funcArr: [(Test) -> (Int) -> Void] = [Test.func1]
Then you can invoke the method with code like this:
var test = Test()
var method = test.funcArr[0]
method(test)(1)
Suggested reading: Curried Functions
I recently updated to Xcode-Beta4. I'm working with a c api and there is a typedef enum like this:
typedef enum {
XML_ELEMENT_NODE= 1,
XML_ATTRIBUTE_NODE= 2,
...
} xmlElementType;
Now I have a xml node, which type I want to check. Therefore the right way would be:
if currentNode.memory.type != XML_ELEMENT_NODE {
In Beta 3 I had to replace XML_ELEMENT_NODE with 1. Now this does not work anmyore. In both cases I get the error xmlElementType is not convertible to UInt8
The simplest workaround is to find the header and replace the typedef enum with an typedef NS_ENUM(...). The problem with this solution is that everybody in your team has to make the changes.
The problem is caused by the fact that the C enum is converted into an opaque type (struct?) C.xmlElementType. This type has one single property value of type UInt32. Unfortunately, this property is not public. You can call it from the debugger but using it in compiled code results in an error.
I managed to do a workaround using reflect but it's a big hack:
extension xmlElementType : Equatable {
}
public func ==(lhs: xmlElementType, rhs: xmlElementType) -> Bool {
var intValue1 = reflect(lhs)[0].1.value as UInt32
var intValue2 = reflect(rhs)[0].1.value as UInt32
return (intValue1 == intValue2)
}
var elementType = currentNode.memory.type
if elementType == xmlElementType(1) {
println("Test")
}
I think this is a bug. Either the equality should be defined or some way to cast the struct to an integer.
EDIT:
Another option is to add an inline conversion function to your bridging header:
static inline UInt32 xmlElementTypeToInt(xmlElementType type) {
return (UInt32) type;
}
And then define equality as
public func ==(lhs: xmlElementType, rhs: xmlElementType) -> Bool {
return ((xmlElementTypeToInt(lhs) == xmlElementTypeToInt(rhs))
}
However, the most simple option I have found is to brutally cast the struct to an UInt32:
public func ==(lhs: xmlElementType, rhs: xmlElementType) -> Bool {
var leftValue: UInt32 = reinterpretCast(lhs)
var rightValue: UInt32 = reinterpretCast(rhs)
return (leftValue == rightValue)
}
Note this is less reliable because you have to make sure that the struct actually has 32 bytes and it is not an UInt8, for example. The C conversion function is more stable.