Swift Xcode 7 Beta 5 Type Cannot Refer to Itself as a Requirement

Swift Xcode 7 beta 5 type cannot refer to itself as a requirement

I have no idea why this should be wrong. But it's fairly easy (though annoying) to work around it: declare another protocol for Flier to adopt and use that as the constraining type:

protocol Superflier {}
protocol Flier : Superflier {
typealias Other : Superflier
func flockTogetherWith(f:Other)
}

It makes the code really tortured but at least it gets it past the compiler.

EDIT: Response on the dev forum from SevenTenEleven:

Having this kind of constraint isn't inherently unreasonable, but in some cases it would lead to compiler crashes. We decided to lock down on this for now. Your workaround of using a second protocol is a reasonable one.

So the change is probably to be regarded as deliberate if regrettable, and the workaround I've given is the way to go for now.

error: type may not reference itself as a requirement associatedtype Suffix: SuffixableContainer where Suffix.Item == Item

protocol SuffixableContainer: Container {
associatedtype Suffix: SuffixableContainer
// ...
}

uses a “recursive constraint” on the associated type: The associated
type Suffix is constrained to the enclosing protocol SuffixableContainer.

Recursive constraints on associated types were were implemented in Swift 4.1, i.e. that code requires Xcode 9.3 (currently in beta).

From the Swift CHANGELOG:

Swift 4.1

...

SE-0157 is implemented. Associated types can now declare "recursive" constraints, which require that the associated type conform to the enclosing protocol.

Protocol doesn't conform to itself?

EDIT: Eighteen more months of working w/ Swift, another major release (that provides a new diagnostic), and a comment from @AyBayBay makes me want to rewrite this answer. The new diagnostic is:

"Using 'P' as a concrete type conforming to protocol 'P' is not supported."

That actually makes this whole thing a lot clearer. This extension:

extension Array where Element : P {

doesn't apply when Element == P since P is not considered a concrete conformance of P. (The "put it in a box" solution below is still the most general solution.)


Old Answer:

It's yet another case of metatypes. Swift really wants you to get to a concrete type for most non-trivial things. [P] isn't a concrete type (you can't allocate a block of memory of known size for P). (I don't think that's actually true; you can absolutely create something of size P because it's done via indirection.) I don't think there's any evidence that this is a case of "shouldn't" work. This looks very much like one of their "doesn't work yet" cases. (Unfortunately it's almost impossible to get Apple to confirm the difference between those cases.) The fact that Array<P> can be a variable type (where Array cannot) indicates that they've already done some work in this direction, but Swift metatypes have lots of sharp edges and unimplemented cases. I don't think you're going to get a better "why" answer than that. "Because the compiler doesn't allow it." (Unsatisfying, I know. My whole Swift life…)

The solution is almost always to put things in a box. We build a type-eraser.

protocol P { }
struct S: P { }

struct AnyPArray {
var array: [P]
init(_ array:[P]) { self.array = array }
}

extension AnyPArray {
func test<T>() -> [T] {
return []
}
}

let arr = AnyPArray([S()])
let result: [S] = arr.test()

When Swift allows you to do this directly (which I do expect eventually), it will likely just be by creating this box for you automatically. Recursive enums had exactly this history. You had to box them and it was incredibly annoying and restricting, and then finally the compiler added indirect to do the same thing more automatically.

How to solve Protocol 'Result' as a type cannot conform to the protocol itself error in swift 5.6

The function processResult shouldn't be generic, a generic will require a concrete type that conforms to Result at compile time.

func processResult(_ result: Result)

Working around the lack of recursive protocol constraints in Swift 3

By some reason / language shortcomings you have to use explicitly cast when assigning the delegate in View.foo: viewModel.delegate = self as? VM.D

But why do you use structs and not classes? I think you want classes, expecially you don't want all those View/ViewModel variables being copied around while modified - instead of being referenced - when you do something like

var vm = ViewModel() // Type: ViewModel
let v = View(viewModel: vm) // Type: View<ViewModel>
vm.delegate = v

Especially

func foo() {
viewModel.delegate = self
}

doesn't work unless you declare View.foo as mutating, and this would require almost everything (including the ViewDelegate.foo and ViewModel.bar) to be made mutating and v = View(viewModel: vm) cannot be a constant any more.

Although the solution below would also work with structs, I just changed everthing to classes:

protocol ViewModelType {
associatedtype D: Any // Compromise to avoid the circular protocol constraints.
var delegate: D? { get set }
}

protocol ViewType {
associatedtype VM: ViewModelType
var viewModel: VM { get }
}

protocol ViewDelegate {
func foo()
}

class ViewModel: ViewModelType {
typealias D = ViewDelegate
var delegate: D?

func bar() {
delegate?.foo() // Access to delegate methods
}
}

class View<VM: ViewModelType>: ViewType, ViewDelegate {
var viewModel: VM

// initializer needed, because we are no struct any more
init(viewModel vm:VM) {
self.viewModel = vm
}

func foo() {
viewModel.delegate = self as? VM.D
}
}

var vm = ViewModel() // Type: ViewModel
let v = View(viewModel: vm) // Type: View<ViewModel>
v.foo() // View<ViewModel>
vm.delegate // View<ViewModel>

There's just one more thing: Why don't you assign the delegate in the initializer of your view class, like:

// initializer needed, because we are no struct any more
init(viewModel vm:VM) {
self.viewModel = vm
self.viewModel.delegate = self as? VM.D
}

Then you could skip the call to v.foo() in order to set the delegate.

UIViewControllerRepresentable - Protocol cannot be satisfied by a non-final class - SwiftUI

class VideoAnswerWrapper: UIViewControllerRepresentable {

typealias UIViewControllerType = VideoAnswerViewController

The above intended to present a SwiftUI View so MUST be a struct as below

struct VideoAnswerWrapper: UIViewControllerRepresentable {

typealias UIViewControllerType = VideoAnswerViewController

Swift 2.0 beta: are protocols kinda broken in Xcode beta 5?

The first error can be solved if you add the modifier mutating before the extension func declaration like this:

mutating func someFunction(someString: String) {

I suspect that's a change in the language.

The other one puzzles me as well. At least, here's a work-around:

var c = someInstance.returnInterface()
c.someBool = true

Class does not implement its superclass's required members

From an Apple employee on the Developer Forums:

"A way to declare to the compiler and the built program that you really
don't want to be NSCoding-compatible is to do something like this:"

required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}

If you know you don't want to be NSCoding compliant, this is an option. I've taken this approach with a lot of my SpriteKit code, as I know I won't be loading it from a storyboard.


Another option you can take which works rather well is to implement the method as a convenience init, like so:

convenience required init(coder: NSCoder) {
self.init(stringParam: "", intParam: 5)
}

Note the call to an initializer in self. This allows you to only have to use dummy values for the parameters, as opposed to all non-optional properties, while avoiding throwing a fatal error.


The third option of course is to implement the method while calling super, and initialize all of your non-optional properties. You should take this approach if the object is a view being loaded from a storyboard:

required init(coder aDecoder: NSCoder!) {
foo = "some string"
bar = 9001

super.init(coder: aDecoder)
}


Related Topics



Leave a reply



Submit