duemunk / Async

Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch
MIT License
4.59k stars 316 forks source link

Implementing parameters and return between blocks #94

Closed BrunoMazzo closed 8 years ago

BrunoMazzo commented 8 years ago

Implementing issue #3 .

The Async is a generic struct with two types: In, Out.

Chain blocks can receive the Out parameters from previous block or ignore it and return a new type if needed.

All previous code should work without any change.

Usage example:

Async.background { () -> Int in
            return 10
        }.main { (i: Int) -> (String) in
            //Do something with i
                return "Test"
        }.background { (s: String) -> (Double) in
            //Do something with s
                return 10
        }.main { (d: Double) -> () in
            //Do something with d
        }

The only problem is that we have to specify the types on the blocks because I didn't find how to constraint a method to not accept Void type as parameter.

Problem example:

Async.background { () -> Int in
            return 10
        }.main { (i) -> (String) in
            //Do something with i
                return "Test"
        }

Error because the compiler can not choose between type Int or Void to parameter i

I'm waiting for your feedback and available to try fix anything that you find wrong.

duemunk commented 8 years ago

Great work! Really good to see some progress on this.

I'll try to have a deeper look at it this week and I'll get back to you.

BrunoMazzo commented 8 years ago

I was trying to fix the compiler inference. If we remove the methods with ()->(R) and ()->() the compiler will start infer the input types for the chain but we will need to explicitly ignore the input when we have a block that don't need the input value. Example:

This will work

Async.background {
            return 10
        }.main { i -> String in
            //Do something with i
                return "Test"
        }

But this don't:

Async.background {
            return 10
        }.main { () -> (String) in
                return "Test"
        }

But we still can do:

Async.background {
            return 10
        }.main { (_) -> String in
                return "Test"
        }
duemunk commented 8 years ago

This is truly awesome @BrunoMazzo!

I've been giving it a go, and it seems to be working as expected.

In my testing this does work:

Async.background {
    return 10
}.main { () -> (String) in
    return "Test"
}

That is, even though .background does return something, it's safe to ignore it in .main. I don't know if we can enforce that though. A returned value probably should be used.

BrunoMazzo commented 8 years ago

Ops, sorry I did not pushed the changes to disable implicitly ignore params. However, your example will work but I believe it's a compiler bug. When we do:

Async.background {
    return 10
}.main { () -> (String) in
    return "Test"
}

the compiler is inferring the first block to ()->(). But if we to

let asyncCall = Async.background {
    return 10
}
asyncCall.main { () -> (String) in
    return "Test"
}

will not compile

duemunk commented 8 years ago

I've added support for this in the Swift 3.0 branch now. https://github.com/duemunk/Async/tree/feature/Swift_3.0

This couldn't have been done without the work in this PR, so big thanks to @BrunoMazzo. I don't think it has any bad issues, but sometimes might need help by using explicit argument and return types.

BrunoMazzo commented 8 years ago

Ow, great!! I'm glad I helped! Thanks for the feedback and the great work!

duemunk commented 8 years ago

@BrunoMazzo Let me know if I missed something. Some minor tweak or some edge case that gives horrible Swift compiler warning!

duemunk commented 8 years ago

I'll close this PR. Again, thanks for your great work!