Property declares an opaque return type, but has no initializer expression from which to infer an underlying type
Asked Answered
O

1

5

I have a protocol

protocol doSomethingProtocol {
    associatedtype someType
}

then i have class that is implementing this protocol

class doSomethingClass : doSomethingProtocol {
    typealias someType = Int
}

Now i want to use this protocol as a reference in some other class

class someClass : ObservableObject {

    private var reference : doSomethingProtocol

}

Now i cannot do this as doSomethingProtocol has an associatedtype. So i decide to use some

class someClass : ObservableObject {

    private var reference : some doSomethingProtocol

    init(){
         reference = doSomethingClass()
    }

}

However this doesn't work. I get the error Property declares an opaque return type, but has no initializer expression from which to infer an underlying type. Why ? I am giving it initializer expression in the class init.

However when i do something like this

class someClass : ObservableObject {

    private var reference : some doSomethingProtocol = doSomethingClass()

    init(){}

}

I get no error messages and it compiles. Why, what is the difference between the two.

Olethea answered 4/9, 2021 at 15:50 Comment(2)
In first case type undefined (ie. generic) so concrete cannot be assigned to generic - error, in second case type is inferred during initialisation explicitly. Actually it is not clear what do you try to achieve - you cannot use doSomethingProtocol w/o associated type specialization.Hern
@Hern Sorry i didn't get what you are trying to say. Why the compiler cannot infer in first case after all i am explicitly assigning it an object in the initialiser.Olethea
A
12

Now i cannot do this as doSomethingProtocol has an associatedtype. So i decide to use some

This is where you went wrong. Opaque (some) types solve a completely different problem than protocols with associated types. An opaque type is concrete. It is one, specific type, known at compile time, returned by a function. It just is not known to the caller of the function. It is completely known to the compiler.

var reference : some DoSomethingProtocol

Given this information, what concrete type is reference? It's not known. It's hinted at by the behavior of init, but it's not known to always be that. (Even more so since this is a class that could override its init and assign some other type.)

What you're trying to do is done this way:

private var reference : DoSomethingClass

This defines SomeType == DoSomethingClass, and allows DoSomethingClass to conform to DoSomethingProtocol.

If you're trying to avoid nailing down the type that DoSomethingClass uses here, that's not possible. To conform to a protocol with an associated type, you must provide a concrete type that can be determined at compile time.

Given the problems your running into, I suspect that DoSomethingClass is incorrectly designed, and you don't really want a PAT (protocol with associated type) here. You probably want a generic, or composition, or possibly closures. It is possible (though unlikely) that you want a type eraser. But you don't want opaque types.

(Please capitalize your types. Having leading lowercase for a type is very confusing in Swift.)

Airburst answered 4/9, 2021 at 18:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.