I'm new to Swift. Making a pet project that works with Bluetooth Low Energy (BLE) devices. Thanks to Google found out how to run it (scan, connect etc). But still don't understand how it exactly works. The code is next:
class BLEManager: CBCentralManagerDelegate, OtherProtocols {
private var myCentral: CBCentralManager!
override init() {
super.init()
myCentral = CBCentralManager(delegate: self, queue: nil)
myCentral.delegate = self
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
// This one discover devices
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
// This one handles connection
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
// Does some stuff as well
}
}
The question is why do these methods have the same name? I see that they have different parameters (with pretty clear naming), but how Swift knows which method to call?
P.s. Maybe it doesn't fit my perception model because of JS background. Anyway, much appreciate any help
CodePudding user response:
Others are calling this "overloading," but it isn't. Overloading is when functions are distinguished only by their types (and Swift supports this). That's not what is happening here. The difference between these functions is their names, just like in "normal" functions. Swift is similar to Objective-C (and Smalltalk, but unlike most languages) in how it names functions. The names of these functions are (following the ObjC tradition):
centralManager(_:didDiscover:advertisementData:rssi:)
centralManager(_:didConnect:)
centralManager(_:didDisconnectPeripheral:error:)
As you can see, these are three completely different names, and so are three different functions without anything complex like overloads getting involved.
In most languages, the names of the parameters are not part of the functions name. But in Smalltalk, ObjC, and Swift, they are. This is not like "named parameters" in Python. The name of the function includes these parameter names, in order, and easily distinguish one from another. If Swift hadn't carried this over from ObjC, it would have been extremely difficult to bridge the two languages as well as they are.
Note that this kind of function naming, where the "base" part of the function name is the name of the caller ("centralManager"), is from the ObjC/Cocoa tradition. While it's common in Swift because of Cocoa (i.e. iOS), it is not actually common in "pure Swift," which generally doesn't use the delegate pattern like this (you never see this in SwiftUI, for example). So what you're really seeing here is ObjC automatically transliterated into Swift.
But distinguishing Swift functions by their full (including parameters) name is extremely common and "Swifty." You see it most commonly in init
methods, but it happens all over.
CodePudding user response:
Swift is a bit different from javascript as it's both compiled and typed.
This pattern is called method overloading (function overloading) and is a common pattern in many programming languages.
While in js you can call a function without sending the appropriate arguments to the function, this is not possible in swift. So swift knows which method to use based on which arguments you call it with.
CodePudding user response:
Statically typed languages (not just Swift, but others like C ) can do this because:
- They're aware of the argument types and counts, and
- The function names don't matter when you're running the code, so you can use "mangled" names to differentiate them for the program's purposes.
At compile time, the compiler just keeps track of all the methods with the same name, and when it sees that name called, it figures out which one matches the arguments provided best, and calls that one. Under the hood, the compiled code actually uses a different name for each function (mangled based on the different argument types accepted), so dynamic libraries can expose each function independently.
JavaScript can't do this because:
- It's dynamically typed; it has no idea what type the arguments are until it actually makes the call, and
- Function/method lookup is implemented as a string keyed hash under the hood, and without being able to name-mangle in advance for each type it could receive, it can't store multiple functions under that same name.
- It's legal to look up functions/methods by name without calling them, so you wouldn't know how it would eventually be called, even at the time you're looking up the function.
In theory, languages like JavaScript could allow this for different numbers of arguments by name-mangling each function to include the number of arguments it should be called with (handling #3 would add complexity as you'd need to have lookup produce a wrapper that dynamically selects the real function based on the arguments passed when it's eventually called). But JavaScript itself can't even do that, because all JavaScript functions can accept any number of arguments; if it's fewer than their prototypes declare, the rest become undefined
, and extra arguments are always accessible through the arguments
pseudo-array. There's no "true" count available to use for such mangling.