Overloading methods in Swift works as expected, but when I try to overload nested functions, such as
func foo() {
func bar(param: Int) {
// do stuff
}
func bar(param: Double) {
// do stuff
}
// call functions here
}
I get an error saying Definition conflicts with previous value. Why does this happen?
IMHO this is clearer if you consider this variation:
func foo() {
let bar: (param: Int) -> () = { p in
// do stuff
}
func bar(param: Double) {
// do stuff
}
// call functions here
}
With your first bar function definition you are just declaring a constant of type (param: Int) -> ().
Thus with your second declaration you are declaring another constant of different type (param: Double) -> () but having the same name as the already declared bar.
In short it's just like you wrote:
let bar: Int = 0
let bar: Double = 0.0
In which case compiler will complain as well.
Hope this helps.
Good question.
Note that this behaviour/restriction is not documented and the answer is my best guess.
Consider this following piece of code:
func foo() -> (param:Int)->() {
func bar(param: Int) {
// do stuff
}
return bar
}
The function will return the closure bar. If you were to have another closure named bar within the same function, like this...
func foo() -> (param:Int)->() {
func bar(param: Int) {
// do stuff
}
func bar(param: Float) {
// do stuff
}
return bar
}
...they would have conflicting names and the compiler doesn't know what to return. This is same as the following piece of code which you would readily agree to be wrong:
func foo() -> Int {
let a:Int = 0
let a:Int = 0 //Error
return a
}
More observation
The behaviour of a similar set of functions inside a class is weird.
class Test {
func foo(param:Float) {
let bar = { (param:Int) -> () in
//do stuff
}
}
func foo(param:Int) {
let bar = { (param:Int) -> () in
//do stuff
}
}
func anotherFoo() {
println(self.foo) //Compile time error - Ambiguous use of foo
}
}
All though...
class Test {
func foo(param:Float) {
let bar = { (param:Int) -> () in
//do stuff
}
}
func anotherFoo() {
println(self.foo) //Compiles
}
}
Interesting.
Related
I just came across this curious cookie and can't figure out if I'm more surprised by the fact that this doesn't work as expected or that this the first time I'm seeing this in the past five years using Swift every day.
Now, I expected Bar type to be accessible from Baz, but it isn't:
class Foo<Bar> {
func bar() -> Bar? { nil }
}
class Baz: Foo<String> {
override func bar() -> Bar? { nil } // 💥 Use of undeclared type 'Bar'…
}
It's easily solved with typealias:
class Foo<Bar> {
typealias Bar = Bar // This just feels so wrong…
func bar() -> Bar? { nil }
}
class Baz: Foo<String> {
override func bar() -> Bar? { nil } // 👌 That's it…
}
My questions is: is this mentioned or explained anywhere in the official docs? What's the benefit of hiding Bar from inheriting classes?
One of the reasons this is a rare case is probably because we often pass down the generic type:
class Foo<Bar> {
func bar() -> Bar? { nil }
}
class Baz<Bar>: Foo<Bar> {
override func bar() -> Bar? { nil } // 👌 No problems…
}
And use protocols with associatedtype, which does the same job as typealias above:
protocol P {
associatedtype Bar
}
class Foo<Bar>: P {
func bar() -> Bar? { nil }
}
class Baz: Foo<String> {
override func bar() -> Bar? { nil } // 👌 All good…
}
P.S. I'm not asking how to fix this. I want to know if the current behaviour is mentioned anywhere in the official documentation or, otherwise, if there's a credible article explaining the reasons why this works the way it does.
Foo<Bar> Bar is just a typealias of your 'generic' type (I mean what type you want Int, Double etc.). So if you give String to Foo like (Foo<String>) now Bar alias of the String. And the Bar alias only recognizes from Foo.
class Foo<Bar> {
func bar() -> Bar? { return nil }
}
Incorrect
class Baz: Foo<String> {
override func bar() -> Bar? { return nil } // `Bar` is `String` now so you should use `String?` in your return type
}
Correct
class Baz: Foo<String> {
override func bar() -> String? { return nil }
}
BONUS
hackingwithswift article about Swift Generics
I have a function similar to the following
class Bar {
deinit {
print("Do some cleanup")
}
}
func foo() -> Bar {
return Bar()
}
The scope of Bar is clear when calling it like this:
func useFoo() {
let bar = foo()
runFunctionA()
// bar goes out of scope: "Do some cleanup" is printed
}
However, what happens when the return value is ignored, will it go immediately out of scope?
func useFoo() {
let _ = foo()
// "Do some cleanup" is printed here?
runFunctionA()
// "Do some cleanup" is printed here?
}
Also, does it make a difference if let _ = foo() is used or only _ = foo()?
In second case, there is no one taking the ownership of returned object and hence ARC releases the object immediately. So, you must see Do some cleanup, before runFunctionA() call.
Also, let _ = foo() is similar to _ = foo
Now, you must be thinking what crap I am writing when you must be looking at different results in your playground.
The thing is, playgrounds are not meant for checking memory related code. Refer this.
If you don't trust me, just check your code in an actual project. I sure did.
Bar:
class Bar {
deinit {
print("Do some cleanup")
}
class func foo() -> Bar {
return Bar()
}
}
ViewController:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
useFoo()
useFooAgain()
}
func useFoo() {
let bar = Bar.foo()
print("inside useFoo")
}
func useFooAgain() {
let _ = Bar.foo()
print("inside useFooAgain")
}
}
Output:
inside useFoo
Do some cleanup
Do some cleanup
inside useFooAgain
struct System {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() {
curMethod = 1
}
mutating func method2() {
curMethod = 2
}
}
var sys = System()
sys.method = System.method1
sys.method!()
I get an error cannot assign value of type (inout System) -> () -> ()' to type '(() -> ())?. What am I doing wrong?
First of all, your line sys.method = System.method1 is wrong, as it would require method1 to be a static function (like a class function) rather than an instance function, so it should be changed to sys.method = sys.method1. But this isn't allowed - the error is "error: partial application of 'mutating' method is not allowed".
If you make System a class (rather than a struct), it will work if you replace the System.method1 with sys.method1.
The reason for this is that a mutating func is actually quite a lot more than a simple function under the hood - it is a curried function (curried with a compiler generated function) that effectively creates a new copy of the struct with the "new" value - hence, you A) can't access it it directly ("partial application is not allowed") and B) you can't assign it to a ()->() variable.
So, there're 3 variants suggested by participants. Everything is working, and using class instead of struct seems to me less complicated.
struct System1 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
struct System2 {
var method: ((inout System2) -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
mutating func callCurrentMethod() { method?(&self) }
mutating func method1() { curMethod = 1 }
mutating func method2() { curMethod = 2 }
}
class System3 {
var method: (() -> ())?
var curMethod: Int
init() {
method = nil
curMethod = 0
}
func method1() { curMethod = 1 }
func method2() { curMethod = 2 }
}
var struct1 = System1()
var struct2 = System2()
var class1 = System3()
print(struct1.curMethod)
let curried = System1.method1
let unsafe = curried(&struct1)
unsafe()
print(struct1.curMethod)
print(struct2.curMethod)
struct2.method = { $0.method1() }
struct2.callCurrentMethod()
print(struct2.curMethod)
print(class1.curMethod)
class1.method = class1.method1
class1.method!()
print(class1.curMethod)
I am trying to create a couple of objects which are dependent one to each other and they mush have a method to downcast directly the concrete class of the other object. Something like this:
protocol aProt
{
var bVar:bProt! { get set }
}
protocol bProt
{
var aVar:aProt! { get set }
}
class a: aProt
{
var bVar: bProt!
func bConcrete() -> b {
return bVar as! b
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete() -> a {
return aVar as! a
}
Now, the problem is that I want this behavior (func aConcrete(),func bConcrete()) to be inherited by the subclasses of a and b. Then I thought the perfect way of doing this was using generics, but... There's no way of doing this.
class a: aProt
{
var bVar: bProt!
func bConcrete() -> T {
return bVar as! T
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete<T>() -> T {
return aVar as! T
}
You can do it but when you have to use it you must downcast the variable anyway, so there is no way of doing it in a clean manner:
let aObject = a()
let bSubclassObject = a.bConcrete() // The compiler complains it cannot infer the class of T
let bSubclassObject = a.bConcrete() as! bSubclass // this works, but this is exactly which I wanted to avoid... :(
Define the generic function and add where to T:
protocol aProt {
var bVar: bProt! { get set }
}
protocol bProt {
var aVar:aProt! { get set }
}
class a: aProt {
var bVar: bProt!
func bConcrete<T: b>(_ type: T.Type) -> T? {
return bVar as? T
}
}
class b: bProt {
var aVar: aProt!
func aConcrete<T: a>(_ type: T.Type) -> T? {
return aVar as? T
}
}
class a1: a { }
class b1: b {
var fullName: String = "new object"
}
let aObj = a()
aObj.bVar = b1()
let bObj = aObj.bConcrete(b1.self)
bObj?.fullName
According to your requirement, calls bConcrete(b1.self) might still not good enough, but at least you need to know what type of data you are expecting to return.
Supposing to have this three classes with this simply hierarchy:
class A {
func foo() {
print("A")
}
}
class B: A {
override func foo() {
super.foo()
print("B")
}
}
class C: B {
override func foo() {
// *******
print("C")
}
}
In class C, in overrided method foo I want to call a method foo: is it possible?
In C++ this can be achieved with C->A::foo(), but how do I do this in Swift?
super.foo() should be sufficient, since B prints "B" and calls super to print "A".
class C: B {
override func foo() {
super.foo()
print("C")
}
}
let c = C()
c.foo()
Output:
A
B
C
If you want to intentionally expose A's foo() from B, you need to create a new accessor:
class B: A {
override func foo() {
super.foo()
print("B")
}
func exposeFoo() {
super.foo()
}
}
class C: B {
override func foo() {
super.exposeFoo()
print("C")
}
}
Or, use NSObject and the power of the Objective-C runtime:
class A: NSObject { // make sure your base class inherits from NSObject
func foo() {
print("A")
}
}
// ...
class C: B {
override func foo() {
guard let superSuper = self.superclass?.superclass() else {
return; // no super super
}
let fooImp = class_getMethodImplementation(superSuper, "foo")
typealias MyCFunction = #convention(c) (AnyObject, Selector) -> Void
let curriedImplementation = unsafeBitCast(fooImp, MyCFunction.self)
curriedImplementation(self, selector) // prints A
}
}