Enum parameter for function - swift

enum FooEnum: Int {
case fooEnumCase = 13512
case fooEnumCase2 = 425156
}
class FooClass {
public func myFunction(chosenEnumCase: fooEnum) -> String {
/* Logic */
}
}
fooClass.myFunction(fooEnum.fooEnumCase)
I am getting the error:
FooEnum is not convertible to FooClass
What is wrong with this code?

First of all the code is very hard to read with lowercase class names.
Two issues:
With this syntax the method is supposed to be a class function.
public static func myFunction(chosenEnumCase: FooEnum) -> String
Which raises a new error
Missing argument label 'chosenEnumCase:' in call
and you have to add the parameter label:
enum FooEnum: Int {
case fooEnumCase = 13512
case fooEnumCase2 = 425156
}
class FooClass {
public static func myFunction(chosenEnumCase: FooEnum) -> String {
//logic
}
}
FooClass.myFunction(chosenEnumCase: FooEnum.fooEnumCase)

To explain the error message let's consider fooClass.myFunction:
let f: (fooClass) -> ((fooEnum) -> String) = fooClass.myFunction
It's a function that expects an instance of fooClass, and returns another function ((fooEnum) -> String). Whereas in your code it is fed an instance of type fooEnum.
Call that function on a instance:
let myInstance = fooClass()
myInstance.myFunction(chosenEnumCase: fooEnum.fooEnumCase)
Or make myFunction a class function:
public class func myFunction(chosenEnumCase: fooEnum) -> String
PS: To conform to the Swift naming conventions use FooEnum and FooClass.

Related

Type override in generic protocol giving "explicitly specify the generic arguments to fix this issue" error

I am trying to change the default associated type to String. but getting this error
explicitly specify the generic arguments to fix this issue.
Below code works fine for type Int but not for String. Am i missing something?
//override/Change the associated Type of Protocol
protocol Familiable{
associatedtype FamilyType = Int
func getName()->[FamilyType]
}
class NumberFamily:Familiable{
func getName() -> [Int] {
return [1,2,3,4,5]
}
}
let numRef = NumberFamily()
print(numRef.getName())
type(of: numRef)
struct NormalFamily<T:ExpressibleByStringLiteral>: Familiable{
func getName() -> [T] {
return ["name1","name2"]
}
}
let normalRef = NormalFamily()
normalRef.getName()

Using protocol with associated type inside a generic function in Swift

Hi I'm trying to create a function which accepts a generic type that conforms to a specific protocol, and this protocol has a static builder that return a new instance of the same class (using associated type), after that he returns the new object that was created.
The generic function will return a list of the generic type.
In my efforts to make it compile, I found a solution, but I feel like I cheated, please see the following code:
import UIKit
protocol SomeRougeProtocol {
associatedtype U
static func convert(id: String) -> U
}
class FirstRougeClass: SomeRougeProtocol {
typealias U = FirstRougeClass
let value: String
init(value: String = "") {
self.value = value
}
static func convert(id: String) -> FirstRougeClass {
return FirstRougeClass(value: id)
}
}
class SecondRougeClass: SomeRougeProtocol {
typealias U = SecondRougeClass
let value: String
init(value: String = "") {
self.value = "special \(value)"
}
static func convert(id: String) -> SecondRougeClass {
return SecondRougeClass()
}
}
/// Takes type and generate an array from it.
func superConvert<T: SomeRougeProtocol>(class: T) -> [T.U] {
return [T.convert(id: "1"), T.convert(id: "2"), T.convert(id: "3")]
}
// *** This is the cheasty part, I have to create a disposable object to pass as input, it won't compile otherwise.
let disposableObject = FirstRougeClass()
let a: [FirstRougeClass] = superConvert(class: disposableObject)
a[0].value // Generates "1" in the playground, success!
My question is, if there is a better way to achieve what I done? without using a disposable object would be a big plus haha
Thanks!

how to solve "Protocol ... can only be used as a generic constraint..."

Consider this fragment of code:
public protocol Evaluable {
typealias ReturnType
func eval(s: State) -> ReturnType
}
protocol AlgebraicExpr : Evaluable {
}
public struct Const : AlgebraicExpr {
var value: Int = 0
public func eval(s: State) -> Int {
return value
}
}
public struct Add : AlgebraicExpr {
let a, b: AlgebraicExpr
public func eval(s: State) -> Int {
return a.eval() + b.eval()
}
}
it is invalid because Add cannot have an AlgebraicExpr variable.
But I really need Add to store two AlgebraicExprs. How would you solve this in Swift?
For completeness, State is just a struct, for example:
public struct State {
var env = Dictionary<String, Int>()
init(_ d: Dictionary<String, Int> = [:]) {
env = d
}
subscript(s: String) -> Int? {
get {return env[s]}
set {env[s] = newValue}
}
}
You can't store two protocols that rely on Self, or a typealias because when abstracted as a protocol, the functionality is undetermined. Type Evaluable has no real meaning without understanding the value of ReturnType, so it's not possible for the system to function logically and understand what should be returned.
Take for instance something like this (not valid)
let thing: Evaluable = ...
let result = thing.eval(state) // What should return type be?
The return type can't be inferred through the protocol alone, it requires an implementation by a specified type that gives more knowledge about its behavior by defining the typealias ReturnType
The reason these can function as generic constraints is that the implementation can be inferred through the generic parameters.
func genericConstrained<T: Evaluable>(evaluable: T, state: State) -> T.ReturnType {
return evaluable.eval(state)
}
In this example, when we call genericConstrained on a particular conforming object, all of its other functionality can be inferred.
tl;dr
If however, you also constrain your package, you could do as you wish:
public struct Add<ExpressionType : AlgebraicExpr> : AlgebraicExpr {
let a, b: ExpressionType
public func eval(s: State) -> ExpressionType.ReturnType {
return a.eval() + b.eval()
}
}
Then use like
let add: Add<SomeConformingType> = ...

Swift generic function calling function with return type overload

just a quick question. I have the following code, which works just fine:
class obA: Printable {
var description: String { get { return "obA" } }
}
class obB: Printable {
var description: String { get { return "obB" } }
}
func giveObject() -> obA { return obA() }
func giveObject() -> obB { return obB() }
var a: obA = giveObject()
var b: obB = giveObject()
println(a)
println(b)
The right variant of giveObject is being called and all is well. Of course this is just a simplified case, in reality in my project there are several dozens of overloads of 'giveObject', all differing in return type. Now, I want to make a generic function to parse all these things. So, next step:
func giveGeneric<T>() -> T {
return giveObject()
}
var c: obA = giveGeneric()
println(c)
And this complains about ambiguous use of giveObject. I can understand where the error comes from, but I don't see right away how I can solve it and use a construct like this...
First of all just a note.
If the generic type of giveGeneric is simply T, then it can be anything (a String, an Int, ...). So how should giveObject() react in this case?
I mean, if you write:
let word : String = giveGeneric()
internally your generic function calls something like:
let result : String = giveObject() // Ambiguous use of giveObject
My solution
I declared a protocol as follow:
protocol MyObject {
init()
}
Then I made your 2 classes conform to the protocol
class obA: Printable, MyObject {
var description: String { get { return "obA" } }
required init() {}
}
class obB: Printable, MyObject {
var description: String { get { return "obB" } }
required init() {}
}
Finally I can write this
func giveGeneric<T:MyObject>() -> T {
return T()
}
Now I can use it:
let a1 : obA = giveGeneric()
let b1 : obB = giveGeneric()
You decide if this is the solution you were looking for or simply a workaround.
That cannot work, even if you implement a giveObject function for any possible type. Since T can be any type, the giveGeneric method cannot determine the correct overload to invoke.
The only way I can think of is by creating a huge swift with as many cases as the number of types you want to handle:
func giveGeneric<T>() -> T? {
switch "\(T.self)" {
case "\(obA.self)":
return giveObject() as obA as? T
case "\(obB.self)":
return giveObject() as obB as? T
default:
return .None
}
}
But I don't think I would use such a solution even with a gun pointed at my head - it's really ugly.
If in all your cases you create instances using a parameterless constructor, then you might create a protocol and constraint the T generic type to implement it:
protocol Instantiable {
init()
}
func giveGeneric<T: Instantiable>() -> T {
return T()
}
You can use with built-in as well as new types - for instance:
extension String : Instantiable {
// `String` already implements `init()`, so nothing to add here
}
let s: String = giveGeneric()
Alternatively, if you prefer you can make the protocol declare a static giveObject method rather than a parameterless constructor:
protocol Instantiable {
static func giveObject() -> Self
}
func giveGeneric<T: Instantiable>() -> T {
return T.giveObject()
}
extension String : Instantiable {
static func giveObject() -> String {
return String()
}
}
let s: String = giveGeneric()

Swift println() does not display anything in a let in

Why I can't see the output of println() when it is called inside an in statement? And how I can see this output in Xcode?
I have done this dummy test code:
public class TestClass {
public var testType: String = ""
public func test(test:((TestClass) -> Void)!){
testType = "TEST"
}
}
var request = TestClass()
request.test({(response: TestClass) in
println("Test: \(response.testType)")
})
In your example you are calling method test() takes as parameter function of type TestClass -> Void. However, in implementation of test() method you never call passed function, thus println() is never executed.
You could try
public func test(testFunction:((TestClass) -> Void)!){
testType = "TEST"
testFunction(self)
}
You don't call the closure inside TestClass.test
Change it to
public func test(test:((TestClass) -> Void)!){
testType = "TEST"
test(self)
}