Call function with empty variadic param - swift

I have a function with one variadic param (tuple) like this:
func conditions<T>(conditions: ([String : T], LogicalOperator)...) -> [AnyObject]?
Is there any way how to call it without that param? Somehow pass an empty array of variadic params? I just want to be able to support an option when there are no conditions at all.

You can do it, but not as a generic function. Why? Because it can't infer the type, so the compiler doesn't know what T is, even tho your tuple will be optional. So code below in theory would work, but the execution will fall:
struct Test<T> {
func conditions<T>(conditions: ([String : T], String)?...) -> [AnyObject]? {
return nil
}
}
var t = Test<Int>()
t.conditions() // Error infering type
However, this one does work (if it does satisfy your needs):
struct Test<T> {
typealias testAlias = ([String : T], String)
func conditions(conditions: testAlias...) -> [AnyObject]? {
return nil
}
}
var t = Test<Int>()
t.conditions()

You can accomplish what you want with function overloading.
You could overload your function definition to accept no arguments...
func conditions() -> [AnyObject]?
or, you could overload it to accept an array of your type...
func conditions<T>(conditions: [([String : T], LogicalOperator)]) -> [AnyObject]?
or you could make it accept optional values and pass nil.
func conditions<T>(conditions: ([String : T], LogicalOperator)?...) -> [AnyObject]?

Related

Cannot convert value type... when using generics and polymorphism in Swift 3

In my simplified example I'm getting the error: Cannot convert value of type 'Foo' to expected argument type BaseItem<Any>
But the class Foo extends BaseItem<String>.
This is the example code:
class BaseItem<T> {
var param: T?
}
class Foo: BaseItem<Int> {
}
func checkItem(item: BaseItem<Any>) -> Bool{
return item.param != nil;
}
I get the error when calling
checkItem(item: Foo())
What am I missing?
You need to define your checkItem function in terms of generics too:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Gotta define checkItem function with generics too.
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
The problem is that generics are invariant – consider if your checkItem(item:) function had said:
func checkItem(item: BaseItem<Any>) {
item.param = "foo"
}
That would be illegal for a BaseItem<Int>, as you cannot possibly assign a String instance to an Int? property – which is why it (an instance of Foo) cannot be typed as a BaseItem<Any>.
The solution, as other answers have said, is to use a generic placeholder for the function:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Now, rather than saying that you're taking a BaseItem<Any>, that has a param of type Any? (can be assigned a value of any type) – you're now saying that you're taking a BaseItem with any specific placeholder type; which will be satisfied at the call-site of the function.
The function implementation itself therefore cannot make any assumptions about this type, and will disallow the assignment of an arbitrary value to param. The compiler will only allow an assignment of a value of type T.
The signature of checkItem function should be: checkItem<T>(item: BaseItem<T>) -> Bool, as follows:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Usage:
checkItem(item: Foo()) // false
let myFoo = Foo()
myFoo.param = 0
checkItem(item: myFoo) // true
The reason of why the compiler complains about
Cannot convert value of type 'Foo' to expected argument type
BaseItem
is that you are trying to pass BaseItem<Int> instance as BaseItem<Any> which is invalid (Any data type is not T generic type).

How to pass closure with argument as argument and execute it?

Initializer of class A takes an optional closure as argument:
class A {
var closure: ()?
init(closure: closure()?) {
self.closure = closure
self.closure()
}
}
I want to pass a function with an argument as the closure:
class B {
let a = A(closure: action(1)) // This throws the error: Cannot convert value of type '()' to expected argument type '(() -> Void)?'
func action(_ i: Int) {
//...
}
}
Class A should execute the closure action with argument i.
I am not sure about how to write this correctly, see error in code comment above. What has to be changed?
Please make your "what-you-have-now" code error free.
Assuming your class A like this:
class A {
typealias ClosureType = ()->Void
var closure: ClosureType?
init(closure: ClosureType?) {
self.closure = closure
//`closure` would be used later.
}
//To use the closure in class A
func someMethod() {
//call the closure
self.closure?()
}
}
With A given above, you need to rewrite your class B as:
class B {
private(set) var a: A!
init() {
//initialize all instance properties till here
a = A(closure: {[weak self] in self?.action(1)})
}
func action(i: Int) {
//...
}
}
The problem is that closure()? is not a type. And ()? is a type, but it is probably not the type you want.
If you want var closure to have as its value a certain kind of function, you need to use the type of that function in the declaration, e.g.
var closure: (Int) -> Void
Similarly, if you want init(closure:) to take as its parameter a certain kind of function, you need to use the type of that function in the declaration, e.g.
init(closure: (Int) -> Void) {
Types as Parameters
In Swift, every object has a type. For example, Int, String, etc. are likely all types you are extremely familiar with.
So when you declare a function, the explicit type (or sometimes protocols) of any parameters should be specified.
func swallowInt(number: Int) {}
Compound Types
Swift also has a concept of compound types. One example of this is Tuples. A Tuple is just a collection of other types.
let httpStatusCode: (Int, String) = (404, "Not Found")
A function could easily take a tuple as its argument:
func swallowStatusCode(statusCode: (Int, String)) {}
Another compound type is the function type. A function type consists of a tuple of parameters and a return type. So the swallowInt function from above would have the following function type: (Int) -> Void. Similarly, a function taking in an Int and a String and returning a Bool would have the following type: (Int, String) -> Bool.
Function Types As Parameters
So we can use these concepts to re-write function A:
class A {
var closure: (() -> Void)?
init(closure: (() -> Void)?) {
self.closure = closure
self.closure()
}
}
Passing an argument would then just be:
func foo(closure: (Int) -> Void) {
// Execute the closure
closure(1)
}
One way to do what I think you're attempting is with the following code:
class ViewController: UIViewController {
override func viewDidLoad() {
let _ = A.init(){Void in self.action(2)}
}
func action(i: Int) {
print(i)
}
}
class A: NSObject {
var closure : ()?
init(closure: (()->Void)? = nil) {
// Notice how this is executed before the closure
print("1")
// Make sure closure isn't nil
self.closure = closure?()
}
}

Generic function taking a type name in Swift

In C#, it's possible to call a generic method by specifying the type:
public T f<T>()
{
return something as T
}
var x = f<string>()
Swift doesn't allow you to specialize a generic method when calling it. The compiler wants to rely on type inference, so this is not possible:
func f<T>() -> T? {
return something as T?
}
let x = f<String>() // not allowed in Swift
What I need is a way to pass a type to a function and that function returning an object of that type, using generics
This works, but it's not a good fit for what I want to do:
let x = f() as String?
EDIT (CLARIFICATION)
I've probably not been very clear about what the question actually is, it's all about a simpler syntax for calling a function that returns a given type (any type).
As a simple example, let's say you have an array of Any and you create a function that returns the first element of a given type:
// returns the first element in the array of that type
func findFirst<T>(array: [Any]) -> T? {
return array.filter() { $0 is T }.first as? T
}
You can call this function like this:
let array = [something,something,something,...]
let x = findFirst(array) as String?
That's pretty simple, but what if the type returned is some protocol with a method and you want to call the method on the returned object:
(findFirst(array) as MyProtocol?)?.SomeMethodInMyProtocol()
(findFirst(array) as OtherProtocol?)?.SomeMethodInOtherProtocol()
That syntax is just awkward. In C# (which is just as strongly typed as Swift), you can do this:
findFirst<MyProtocol>(array).SomeMethodInMyProtocol();
Sadly, that's not possible in Swift.
So the question is: is there a way to accomplish this with a cleaner (less awkward) syntax.
Unfortunately, you cannot explicitly define the type of a generic function (by using the <...> syntax on it). However, you can provide a generic metatype (T.Type) as an argument to the function in order to allow Swift to infer the generic type of the function, as Roman has said.
For your specific example, you'll want your function to look something like this:
func findFirst<T>(in array: [Any], ofType _: T.Type) -> T? {
return array.lazy.compactMap { $0 as? T }.first
}
Here we're using compactMap(_:) in order to get a sequence of elements that were successfully cast to T, and then first to get the first element of that sequence. We're also using lazy so that we can stop evaluating elements after finding the first.
Example usage:
protocol SomeProtocol {
func doSomething()
}
protocol AnotherProtocol {
func somethingElse()
}
extension String : SomeProtocol {
func doSomething() {
print("success:", self)
}
}
let a: [Any] = [5, "str", 6.7]
// Outputs "success: str", as the second element is castable to SomeProtocol.
findFirst(in: a, ofType: SomeProtocol.self)?.doSomething()
// Doesn't output anything, as none of the elements conform to AnotherProtocol.
findFirst(in: a, ofType: AnotherProtocol.self)?.somethingElse()
Note that you have to use .self in order to refer to the metatype of a specific type (in this case, SomeProtocol). Perhaps not a slick as the syntax you were aiming for, but I think it's about as good as you're going to get.
Although it's worth noting in this case that the function would be better placed in an extension of Sequence:
extension Sequence {
func first<T>(ofType _: T.Type) -> T? {
// Unfortunately we can't easily use lazy.compactMap { $0 as? T }.first
// here, as LazyMapSequence doesn't have a 'first' property (we'd have to
// get the iterator and call next(), but at that point we might as well
// do a for loop)
for element in self {
if let element = element as? T {
return element
}
}
return nil
}
}
let a: [Any] = [5, "str", 6.7]
print(a.first(ofType: String.self) as Any) // Optional("str")
What you probably need to do is create a protocol that looks something like this:
protocol SomeProtocol {
init()
func someProtocolMethod()
}
And then add T.Type as a parameter in your method:
func f<T: SomeProtocol>(t: T.Type) -> T {
return T()
}
Then assuming you have a type that conforms to SomeProtocol like this:
struct MyType: SomeProtocol {
init() { }
func someProtocolMethod() { }
}
You can then call your function like this:
f(MyType.self).someProtocolMethod()
Like others have noted, this seems like a convoluted way to do what you want. If you know the type, for example, you could just write:
MyType().someProtocolMethod()
There is no need for f.

What is the syntax for a closure argument in swift

In Swift headers, the isSeparator: argument accepts a closure
public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, #noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
But in the documentation, it lists closure syntax differently
{ (parameters) -> return type in
statements
}
How are you supposed to know that (Self.Generator.Element) throws -> Bool rethrows refers to a closure / requires a closure? Are there other ways that the headers/docs might list argument as meaning a closure?
The "thing" giving away that this is a closure is the ->. The full type is
(Self.Generator.Element) throws -> Bool
It means that the closure takes a variable of type Self.Generator.Element and has to return a Bool upon some calculation based on the input. It may additionally throw some error while doing so - that is what the throws is for.
What you then write
{ (parameters) -> return type in
statements
}
would be an actual implementation, a value of some generic closure type.
The type of a closure is for example (someInt:Int, someDouble:Double) -> String:
var a : ((someInt:Int, someDouble:Double) -> String)
Once again the thing giving away that a is actually a closure is the -> in the type declaration.
Then you assign something to a via some code snippet following your second code block:
a = { (integer, floating) -> String in
return "\(integer) \(floating)"
}
You can tell by the argument's type. Everything in Swift has a type, including functions and closures.
For example, this function...
func add(a: Int, to b: Int) -> Int { return a + b }
...has type (Int, Int) -> Int. (It takes two Ints as parameters, and returns an Int.)
And this closure...
let identity: Int -> Int = { $0 }
...has type Int -> Int.
Every function and closure has a type, and in the type signature there is always a -> that separates the parameters from the return value. So anytime you see a parameter (like isSeparator) that has a -> in it, you know that the parameter expects a closure.
the isSeparator definition means (Self.Generator.Element) throws -> Bool that you will be given an Element and you should return a Bool. When you will call split, you then can do the following :
[1,2,3].split(…, isSeparator : { element -> Bool in
return false
})
This is a pure silly example but that illustrates the second part of your question

Generic within a generic in Swift

Trying to make sense of the code below.
I understand that T is passed by when instantiating the Optional, as in Optional, but what about the U type in map. What type does that assume?
enum Optional<T> : LogicValue, Reflectable {
case None
case Some(T)
init()
init(_ some: T)
/// Allow use in a Boolean context.
func getLogicValue() -> Bool
/// Haskell's fmap, which was mis-named
func map<U>(f: (T) -> U) -> U?
func getMirror() -> Mirror
}
The type U comes from the f parameter to the map function. So if you pass a closure that returns a Int, then map returns a Int?. If you pass a closure that returns a Array<Int>, then map returns a Array<Int>?.
For example, try this:
var opt1: Optional<Int> = .Some(1)
var opt2 = opt1.map { (i: Int) -> String in return "String: \(i)" }
You'll find that opt1 is an Int? and opt2 is a String?.
When calling the map function the caller must provide a single argument which is a closure that:
Has a single argument that is the same type as the one used to
instantiate Optional, i.e. T
Has a return value of some type.
U will then be the type of said return value.