Swift protocol and return types on global functions
This question has the same form as the copy one, and the same solution. Make mutation an initializer rather than a method.
protocol Copyable {
init(copy: Self)
}
protocol Mutatable : Copyable {
init(byMutating: Self)
}
class C : Mutatable {
var a = 0
required init(_ a: Int) {
self.a = a
}
required init(copy: C) {
a = copy.a
}
required convenience init(byMutating: C) {
self.init(copy: byMutating)
self.a++
}
}
// These are purely for convenience
func copy<T : Copyable>(x: T) -> T {
return x.dynamicType(copy: x)
}
func mutated<T: Mutatable>(x: T) -> T {
return x.dynamicType(byMutating: x)
}
But to reiterate Mattt's point in the linked article, you can have a C(copy: x)
syntax fairly conveniently, and you can have a copy(x)
syntax pretty conveniently, and there is always x.dynamicType(copy: x)
. But you can't have a x.copy()
syntax without some annoying work. You either have to duplicate func copy() -> Self { return copy(self) }
in every class, or you have to create some concrete class that implements this method and C
ultimately inherits from. This is currently a basic limitation of Swift. I agree with Mattt's diagnosis of possible solutions, and suspect that some kind of trait system, possibly along the lines of Scala's, will probably be added in the future.
It's worth focusing on Mattt's comment that "all of this highlights a significant tension between methods and functions in Swift." This is another way of saying that there are tensions between the object-oriented paradigm and the functional paradigm, and moving between them can create some disconnects. Languages try to paper-over that issue with various features, but there are important differences between objects with messages and properties, vs functions with data and combinators, and "getting the best of both worlds" can sometimes create some rough edges.
It's easy to forget, when comparing Swift to other languages, that there is a big difference between v0.9 and v2.11. Many things we take for granted in our favorite languages did not exist in their v1 either.
To your comment, you may be thinking that mutated
is of type Self
. But it's of type C
, as your autocomplete indicates. As before, C
is not the same as Self
unless you can promise that there are no subclasses (C
being either final
or a struct). Swift types are resolved at compile-time, not runtime, unless you use dynamicType
.
To be a little more specific, Swift looks at this line:
let mutated = copy(self)
It notes that copy
is generic on the type of its parameter, and it must construct a version of copy
at compile-time to call. There is no type Self
. It's just a placeholder, and must be resolved at compile-time. The type of self
in this lexical scope is C
. So it constructs copy<C>
. But if you subclassed C
, this could be the wrong function (and in this case, would be). This is very closely related to: https://stackoverflow.com/a/25549841/97337.
The fact that type autocomplete says (C)
rather than C
is a minor side-effect of how Swift functions and tuples work, and comes up pretty regularly, but I've yet to encounter a case where it really mattered. A Swift function like func f(x: Int, y:Int)
does not actually have two parameters. It has one 2-tuple parameter of type (Int, Int)
. This fact is important to how the currying syntax works (see the Swift Programming Language for more on currying in Swift). So when you specialize copy
, you specialized it with a 1-tuple of type (C)
. (Or possibly, the compiler is just trying to do that as one of various attempts, and that's just the one it reports on.) In Swift any value can be trivially exchanged for a 1-tuple of the same type. So the return of copy
is actually the 1-tuple of C
, written (C)
. I suspect that the Swift compiler will improve its messages over time to remove the extraneous parentheses, but that's why they show up sometimes.
How to define a Protocol with generic function and some View as return type
This is explicitly disallowed by the Associated Type Inference section of the Opaque Result Types proposal. From the proposal:
Associated type inference can only infer an opaque result type for a non-generic requirement, because the opaque type is parameterized by the function's own generic arguments. For instance, in:
protocol P {
associatedtype A: P
func foo<T: P>(x: T) -> A
}
struct Foo: P {
func foo<T: P>(x: T) -> some P {
return x
}
}there is no single underlying type to infer A to, because the return type of foo is allowed to change with T.
To make this more specific to your question, in order to conform to Test
, there must be exactly one type that can be assigned to Result
. However, your return type is generic, so it depends on the what is passed. The actual (non-opaque) return type of navigate
is:
_ConditionalContent<NavigationLink<T, Text>, EmptyView>
But T
is a type parameter and changes depending on how navigate
is called. So there is no one type that can be assigned to Result
.
You'll need something that can return a single, non-parameterized type. For the example you've given, that's probably AnyView, which is annoying.
That said, what you've written here doesn't really feel like a protocol. It looks a lot like just a function. I'd think a lot about how many different ways navigate
could be written. If everyone would implement it the same way, that's just a function. (If you give another example of a conforming type, it might help to design a better approach.)
Why must a protocol operator be implemented as a global function?
UPDATE
From the Xcode 8 beta 4 release notes:
Operators can be defined within types or extensions thereof. For example:
struct Foo: Equatable {
let value: Int
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.value == rhs.value
}
}
Such operators must be declared as
static
(or, within a class,class final
), and have the same
signature as their global counterparts. As part of this change, operator requirements declared in
protocols must also be explicitly declaredstatic
:protocol Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool
}
ORIGINAL
This was discussed on the swift-evolution list recently (2016-01-31 through 2016-02-09 so far). Here's what Chris Lattner said, regarding declaring operators in a struct or class scope:
Yep, this is a generally desirable feature (at least for symmetric operators). This would also be great to get dynamic dispatch of operators within class declarations. I don’t think we have a firm proposal nailing down how name lookup works with this though.
And later (replying to Haravikk):
What are the name lookup issues? Do you mean cases where an operator for Foo == Foo exists in more than one location?
Yes. Name lookup has to have a well defined search order, which
defines shadowing and invalid multiple definition rules.Personally I’d just stick with what we have now, i.e- treat operator implementations within a specific class/struct as being globally
defined anyway and throw an error if the same signature is declared
more than once.
We need multiple modules to be able to define instances of an
operator, we need operators in extensions, and we need retroactive
conformance to work, as with any other member.
Swift protocol defining class method returning self
Self
in a protocol is a requirement that implementations of the protocol use their own type. Since Invoice
is the type you're adopting the protocol in, your implementation of FromJson
should have a return type of Invoice
.
How do I define generic typealias for Swift to return specific types of objects?
As mentioned in the comments, T
is not defined at class-scope. You need to specify the generic type with the class declaration so it can be used across your class.
Try this:
class PersistentStoreCoordinatorMock<T: NSManagedObject>: Storageable {
var objects = [T]() // here I need to define return array
func findAll(of type: T.Type, predicate: NSPredicate) -> [T] {
findAllWasCalled = true
return objects //here I need to return this when that function was called
}
}
Is there a way to call a global function within a class that has a method whose name is the same as the global function?
Yup, there is. If you app's name were, for instance, "myApp", then you could call the global function, which has the same name and number of argument as the one in your class B
, like so:
func b()
{
print(myApp.a(100))
}
Related Topics
Swift - Avaudioplayer, Sound Doesn't Play Correctly
Arkit - Viewport Size VS Real Screen Resolution
Xcode 8.3 Can't Support Swift 2.3
Xcode Beta 6 "Type of Expression Is Ambiguous Without More Context" Navigationlink
Inconsistent Scenekit Framerate
Swift 4.2 Setter Getter, All Paths Through This Function Will Call Itself
Difference Between String Interpolation and String Initializer in Swift
Adding Local Dependencies in Xcode11 Using Spm
App Delegate Accessing Environment Object
Parsing a Iso8601 String to Date in Swift
Difference Between Associated and Raw Values in Swift Enumerations
How to Cache Images Using Urlsession in Swift
What Determines Whether a Swift 5.5 Task Initializer Runs on the Main Thread
Swift 5.5: Asynchronously Iterating Line-By-Line Through a File
Value of Optional Type Cgfloat Not Unwrapped Error in Swift
Working with C Strings in Swift, Or: How to Convert Unsafepointer<Cchar> to Cstring