A Swift Tour, compiler error around public property in Protocol and Extensions section - swift

I'm new to Swift and am going through the playground for the official A Swift Tour tutorial. I'm executing the code as-is, but am getting a compiler error when running the following block:
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
The protocol is defined as follows:
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
The compiler error is:
error: Protocols and Extensions.xcplaygroundpage:41:9: error: property 'simpleDescription' must be declared public because it matches a requirement in public protocol 'ExampleProtocol'
var simpleDescription: String {
^
Protocols and Extensions.xcplaygroundpage:41:9: note: mark the property as 'public' to satisfy the requirement
var simpleDescription: String {
^
public
I've tried adding public in front of simpleDescription but then I get an unexpected pattern error.
Anyone know what's going on here?

Turns out although my Xcode version was correctly 12.1, my local Swift version was 5.2.4 (the tutorial assumes 5.3). I installed the Command Line Tools for Xcode 12 package, which updated my Swift to 5.3 and now the code compiled as expected. I used xcrun swift -version to see which version of Swift Xcode was using.

Related

Using Swift protocol default implementation in Kotlin Multiplatform

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.

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.

How do I declare that a computed property 'throws' in Swift?

class SomeClass {
var someProperty: Int {
throw Err("SNAFU")
}
}
For code like the above, the swift binary complains 'error is not handled because the enclosing function is not declared 'throws'.
How do I declare that 'someProperty' 'throws' in the above?
class SomeClass {
var someProperty throws: Int {
}
}
and
class SomeClass {
var someProperty: throws Int {
}
}
and
class SomeClass {
var someProperty: Int throws {
}
}
don't seem to work.
This functionality is added for read-only computed properties in Swift 5.5 as part of SE-0310 (included in Xcode 13).
Based on SE-0310, the syntax would be:
class SomeClass {
var someProperty: Int {
get throws {
throw Err("SNAFU")
}
}
}
Here is the previous answer for versions of Swift prior to 5.5:
You cannot throw from a computed property. You must use a function if you want to throw. The Declarations section of the Language Reference part at the end of The Swift Programming Language only lists throws (and rethrows) as a keyword for function and initializer declarations.
While it's not possible (yet) to throw from computed properties in Swift, I found Chris Lattner himself adresses this very same question on one of Apple Developer Forums threads:
We agree that you should be able to mark the getters and setters as "throws" in subscripts and computed properties, but haven't gotten there yet. We are likely to support this at some time, but it isn't clear if it will make it in time for Swift 2.
Let me suggest a workaround: a property can be declared as having type of Result<DesiredPropertyType, Error>. This way it can be accessed like this:
do {
try self.failableProperty.get()
} catch {
...
}
get() is a built-in method of Swift's Result.
UPDATE: this is getting addressed in Swift 5.5 with "effectful read-only properties": https://github.com/apple/swift-evolution/blob/main/proposals/0310-effectful-readonly-properties.md.

hash() and description() not allowed in Xcode 6.3 for NSObject

In my Swift library EVCloudKitDao I do a lot with reflection. Because of that I have set my base class of my data objects to NSObject. Now after the upgrade to Xcode 6.3 I get an error on the 2 functions for getting the hash and the description of the object. The description function was a nice to have, but i do need the hash to make my objects working with a Set.
Here is the code that I have
public class EVCloudKitDataObject : NSObject, NSCoding, Printable, Hashable, Equatable {
public func hash() -> Int {
return self.hashValue
}
public func description() -> String {
return EVReflection.description(self)
}
}
The errors that I get is:
/Users/evermeer/Desktop/dev/GitHub/EVCloudKitDao/AppMessage/AppMessage/CloudKit/EVCloudKitDataObject.swift:106:17:
Method 'hash()' with Objective-C selector 'hash' conflicts with getter
for 'hash' from superclass 'NSObject' with the same Objective-C
selector
/Users/evermeer/Desktop/dev/GitHub/EVCloudKitDao/AppMessage/AppMessage/CloudKit/EVCloudKitDataObject.swift:86:17:
Method 'description()' with Objective-C selector 'description'
conflicts with getter for 'description' from superclass 'NSObject'
with the same Objective-C selector
Does anyone know how I could solve this?
You can not use override.
As the error says, in both cases there's a naming conflict between a property and a method. The most obvious way to fix is by turning your 2 methods into properties:
public override var hash: Int {
return self.hashValue
}
public override var description: String {
return EVReflection.description(self)
}
which can also be written as:
public override var hash:Int {
get {
return self.hashValue
}
}
public override var description : String {
get {
return EVReflection.description(self)
}
}
The reason why it worked in the previous version is most likely because of this:
Swift now detects discrepancies between overloading and overriding in the Swift type system and the effective behavior seen via the Objective-C runtime.
Read more in the release notes (search for 18391046 and 18383574)

Array extension called from other module

Array extension methods are unavailable from other modules (for example the XCTest project)
For the sake of simplicity the code below does nothing but it can be used to reproduce the error
import Foundation
extension Array {
mutating func myMethod(toIndex: Int) -> Int! {
// no real code, it's here only to show the problem
return 0
}
}
Calling it from the same module works as expected but from a test class don't
class MyProjectTests: XCTestCase {
func testMoveObjectsFromIndexes1() {
var arr = ["000", "001", "002", "003"]
arr.myMethod(0)
}
}
I think this is correct because the method visibility is restricted to its own module, indeed I obtain the error '[String]' does not have a member named 'myMethod'
I've tried to define the extended method as public as shown below
extension Array {
public mutating func myMethod(toIndex: Int) -> Int! {
// no real code, it's here only to show the problem
return 0
}
}
But I get the compile error 'Extension of generic type 'Array<T>' from a different module cannot provide public declarations'
Until Beta 7 using public solved the problem but under XCode 6.1 (6A1046a) I obtain this error
How can I fix it to run under other modules/projects?
Swift does not allow public extensions currently so you will need to include that extension swift file in your project and put it part of the target.
While not entirely solving the original question, I did find that I could test extension methods in Swift 2.0 (Under XCode 7.0) by importing the module with the #testable directive:
#testable import MyGreatModule