Using Swift protocol default implementation in Kotlin Multiplatform - swift

I try to use in Kotlin Multiplatform XCFramework with Swift code.
I have a protocol with extension for default implementation of this protocol
#objc protocol Greeting {
var something: String { get }
}
extension Greeting {
var something: String {
return "Hello from Swift"
}
}
And in Platform.kt I'm writing
class GreetingImpl: NSObject(), GreetingProtocol {
override fun something(): String {
return (this as GreetingProtocol).something()
}
}
actual class Platform actual constructor() {
val object = GreetingImpl()
val value = object.something() //Application builds but falls here
}
How can I use Swift protocol default implementation in Kotlin Multiplatform?

As far as I can see, there are two main problems:
The extension is missing an #objc annotation. While this is a Swift-side limitation, this prevents Kotlin from providing full interoperability(Kotlin/Native supports no direct interoperability with Swift, only through Objective-C [docs]).
Objective-C does not support protocol default implementation(see this related StackOverflow question).
So, I would say there is no option to use Swift protocol default implementation in Kotlin Multiplatform.

Related

Can not extend a protocol with another protocol in swift

Am trying to implement this piece of code in my project.
private protocol AnyOptional {
var isNil: Bool { get }
}
extension Optional: AnyOptional {
var isNil: Bool { self == nil }
}
I saw it on SwiftBySundell https://www.swiftbysundell.com/articles/property-wrappers-in-swift/.
But unfortunately am getting this error "Extension of protocol 'Optional' cannot have an inheritance clause". Although when I tried the same code on a playground it worked just fine. Any idea why?
Check to make sure that the Optional type name isn't being overridden by a third-party module (or your own module even). If it is, then you can use Swift.Optional instead to refer to the Optional enum built into Swift.

Combining testable code with static method dispatch in swift

I've been reading a lot about Swift's runtime lately, and became more and more interested in optimising my code using static method dispatch. This happens with the following methods:
struct methods
final class methods, i.e. declared with the final keyword, as private or in a final class
protocol methods that are defined in a protocol extension, without being declared in the protocol itself.
Problem is, non of these situations enables me to write testable code, at least not the way I do it now: injecting protocol entities that are replaced by mocks in unit testing.
So, is it possible to write testable code without giving up static method dispatch, and if so how does one go about it?
Thanks!
Generics is what you look for. You can abstract over a protocol, but the compiler still knows what exact type you are using, so there's no need for dynamic dispatch.
protocol Dependency {
func doSomething()
}
struct RealDependency: Dependency {
func doSomething() {
print("I'm doing real work")
}
}
struct MockDependency: Dependency {
func doSomething() {
print("I'm the mock, so I do nothing")
}
}
struct MyApp<D: Dependency> {
let dependency: D
func doSomething() {
dependency.doSomething()
}
}
let myAppReal = MyApp(dependency: RealDependency())
let myAppMock = MyApp(dependency: MockDependency())
myAppReal.doSomething() // Prints "I'm doing real work"
myAppMock.doSomething() // Prints "I'm the mock, so I do nothing"
However, note that in Swift, generics monomorphization is not guaranteed. So you might end with some form of dynamic dispatch anyway. See this link

Can a Kotlin class be extended to conform to an Interface (like Swift classes can)?

In Swift, I can create a protocol that does something like
protocol FoobarConvertible {
var foobar:String { get }
}
And then extend any class in the system with a conforming implementation
extension String : FoobarConvertible {
var foobar:String {
get {
return "foobar"
}
}
}
In Kotlin, I think Interfaces are similar to protocols(?), and I can declare one like this
interface FoobarConvertible {
val foobar: String
}
But what's not apparent to me from the documentation (which seem to be an exercise in brevity), is how I would extend Kotlin's String class so that it conformed to FoobarConvertible. Obviously, I could just add an extension method to a Kotlin String
val String.foobar:String
get() = "foobar"
But this does not allow Strings to then be used as parameters where a FoobarConvertible is the expected type.
Kotlin doesn't have this language feature, extension functions and extension properties are as far as the extension features go - these are available because they can be implemented via static helper methods that just get the receiver of the extension as their first parameter.
However, interfaces can not be added to existing classes that you might not be compiling yourself - that feature would be more than syntactic sugar. (On the JVM, at least.)

Swift protocol to only implemented by specific classes

I want to create a protocol which is only adopted by a specific class and its subClassses in swift.
I know i can use protocol extensions like this
protocol PeopleProtocol: class {
}
extension PeopleProtocol where Self: People {
}
But the method that will go in my protocol will be an init method which will be implemented by a class or its subClasess and will return only some specific type of objects.
some thing like this.
protocol PeopleProtocol: class {
init() -> People
}
or i can do some thing like this
extension PeopleProtocol where Self : People {
init()
}
But there are two problems,
In the first approach if i put an init method in the protocol it don't allow me to put a return statement there like -> People in the first approach.
In the second approach i have to provide a function body in the protocol extensions, so this thing will be out of question, as i don't know what specific type to return for this general implementation.
So any suggestions how i can call an init method and do either:
Let the protocol (not protocol extension) to be implemented by only specific classe and its subClasses.
Or return an instance of a certain from protocol extension method without giving its body.
You could add a required method that you only extend for the appropriate classes.
for example:
protocol PeopleProtocol
{
var conformsToPeopleProtocol:Bool { get }
}
extension PeopleProtocol where Self:People
{
var conformsToPeopleProtocol:Bool {return true}
}
class People
{}
class Neighbours:People
{}
extension Neighbours:PeopleProtocol // this works
{}
class Doctors:People,PeopleProtocol // this also works
{}
class Dogs:PeopleProtocol // this will not compile
{}
This could easily be circumvented by a programmer who would want to, but at least it will let the compiler warn you if you try to apply the protocol to other classes.

Deprecating protocols for Swift 3 upgrade

I have an iOS framework that I am upgradding to Swift 3. I would like the API's method signatures to follow the Swift 3 conventions of using a first named parameter for methods while maintaining backward compatibility. It's easy enough to add new API method signatures and deprecate the old ones. But what is the best way to handle this with protocols that are used in delegates?
API for Swift 2.x:
#objc(FooManager)
public class FooManager {
public var delegate: FooManagerDelegate?
public func saveFoo(foo: Foo) {
...
delegate?.didSaveFoo(foo)
}
...
}
#objc public protocol FooManagerDelegate {
#objc optional func didSaveFoo(foo: Foo)
}
New API for Swift 3.x:
#objc(FooManager)
public class FooManager {
public var delegate: FooManagerDelegate?
#available(*, deprecated, message: "use didSave(foo: foo)")
public func saveFoo(foo: Foo) {
...
delegate?.didSaveFoo(foo)
}
public func save(foo: Foo) {
...
delegate?.didSave(foo: foo)
}
...
}
#objc public protocol FooManagerDelegate {
#objc optional func didSaveFoo(foo: Foo)
#objc optional func didSave(foo: Foo)
}
The above solution will work, but it won't give any deprecation warnings to users for continuing to use the old delegate methods. I could create a new delegate and deprecate the old delegate class, but then I end up with having to have non-standard delegate class and property naming. I'd hate to have my FooManager look ugly like this:
public class FooManager {
#available(*, deprecated, message: "use swift3delegate")
public var delegate: FooDelegate?
public var swift3delegate: Swift3FooDelegate?
Are there any better solutions for migrating users to new protocol method signatures while maintaining backward compatibility?
Exactly what you are asking for is not possible in Swift (nor Objective-C?) to my knowledge. Quoting a response to a related question:
The primary problem with throwing a deprecation warning on any class which conforms to MyProtocol and implemented myOldFunction() is that there's nothing wrong with classes implementing functions and properties that are not part of your protocol.
That is, that the protocol's method is deprecated wouldn't necessarily mean that the method blueprint is universally to be avoided, it could just mean that for the purposes of conformance to that protocol, the method or property in question is now deprecated.
I totally see the point for this and I'd like this feature too, but to my knowledge Swift 3 at least does not offer it (neither does Objective-C to my knowledge).
One solution for this would be to deprecate the entire protocol, and produce a new protocol you need to declare conformance to in your Swift 3 code. So, this works:
#available(*, deprecated, message="use ModernX instead")
protocol X {}
class A: X {}
… and in your ModernX protocol simply include all the methods except for the deprecated method(s). Using a base protocol without the deprecated method could make this slightly less clunky, but it is a pretty boilerplate heavy workaround for sure:
protocol BaseX {
func foo()
func bar()
}
#available(*, deprecated, message: "Use ModernX instead")
protocol X: BaseX {
func theDeprecatedFunction()
}
protocol ModernX: BaseX {
func theModernFunction()
}
// you'll get a deprecation warning here.
class A: X {
func foo() {}
func bar() {}
func theDeprecatedFunction() {
}
}