swift-aws-lambda-runtime
swift-aws-lambda-runtime copied to clipboard
Lambda.run cannot be used without explicit types
Steps to reproduce
- setup a basic project that uses
AWSLambdaRuntime
- in your main file, define an
Input
andOutput
type that should be used for the Lambda - use the
Lambda.run
function with the non-Void callback - the body of the
run
closure MUST have at least one line of code other than invoking thecallback
Observed behavior
I get a compiler error: Cannot convert value of type 'Output' to expected argument type 'Void'
.
There are 2 overloaded run
functions: One takes a closure of type @escaping (Result<Void, Error>) -> Void
and the other of type @escaping (Result<Output, Error>) -> Void
. I expect the compiler to know that I am using the second function.
Example: Not compiling
import AWSLambdaRuntime
struct Input: Codable {
let foo: String
}
struct Output: Codable {
let bar: String
}
Lambda.run { (context, input: Input, callback) in
context.logger.info("foo bar")
callback(.success(Output(bar: input.foo.capitalized)))
}
Compiler Error: Cannot convert value of type 'Output' to expected argument type 'Void'
Notice that the order of those lines in the run
body is not important, the following yields the same compiler error:
import AWSLambdaRuntime
struct Input: Codable {
let foo: String
}
struct Output: Codable {
let bar: String
}
Lambda.run { (context, input: Input, callback) in
callback(.success(Output(bar: input.foo.capitalized)))
context.logger.info("foo bar")
}
Example: Compiling
import AWSLambdaRuntime
struct Input: Codable {
let foo: String
}
struct Output: Codable {
let bar: String
}
Lambda.run { (context, input: Input, callback) in
callback(.success(Output(bar: input.foo.capitalized)))
}
As long as the body of run
does not contain more than one line I don't get any compiler error. Might be trivial but: Using lines of comments does not result in a compiler error, e.g. the following compiles as well:
import AWSLambdaRuntime
struct Input: Codable {
let foo: String
}
struct Output: Codable {
let bar: String
}
Lambda.run { (context, input: Input, callback) in
// call the callback
callback(.success(Output(bar: input.foo.capitalized)))
}
Another way to work around this problem is of course just specifying the type of callback
. The following compiles without errors:
import AWSLambdaRuntime
struct Input: Codable {
let foo: String
}
struct Output: Codable {
let bar: String
}
Lambda.run { (context, input: Input, callback: @escaping (Result<Output, Error>) -> Void) in
context.logger.info("foo bar")
callback(.success(Output(bar: input.foo.capitalized)))
}
[EDIT 1: edited the code examples to make them compile if copy&pasted] [EDIT 2: reworked the examples and explanation to better reflect the problem (now more directed to the compiler error rather than the styling of the code)]
cc @jckarter since most of this is compiler related
Overloading is a bad idea to begin with in general, so if there's a way to get the intended API effect with only one overload, I would suggest that no matter what. The compiler isn't going to do type inference across statements, so you're not going to be able to get it to infer the callback argument from the body of a multi-line closure.
+1 on not overloading, especially if there are closures involved.
This will be resolved with https://github.com/apple/swift/pull/32223
I believe this could be closed.
Swift 5.7 will enable such syntax, but we’re not using closures any more🤷♂️