Consider the following code:
type Intf interface {
Method()
}
type TypeA struct {
TypeBInst Intf
}
func (*TypeA) Method() {
log.Println("TypeA's Method")
}
func (t *TypeA) Specific() {
t.TypeBInst.Method() // Call override from TypeB
log.Println("Specific method of TypeA")
}
type TypeB struct {
*TypeA
}
func (*TypeB) Method() {
log.Println("TypeB's Method")
}
Is there another way to call func (*TypeB) Method() from inside func (t *TypeA) Specific() than storing a pointer to a TypeB's instance inside the embedded TypeA instance of TypeB? Is it against golang principles?
Working example: playground
Is there another way to call func (*TypeB) Method() from inside func (t *TypeA) Specific() than storing a pointer to a TypeB's instance inside the embedded TypeA instance of TypeB?
Yes, there is:
package main
import "log"
type TypeB struct{}
func (*TypeB) Method() {
log.Println("TypeB's Method")
}
func main() {
(*TypeB).Method(nil)
}
But it only works for nilable receivers (without requiring an instance of the receiver).
Is it against golang principles?
Not that I know of, but I personally have never required this in any project ever.
Related
I have two classes, Object and SubObject. A protocol, MyProtocol, has an associatedtype of type Object. In two extensions, I have provided implementations of the save function. When I create an instance of TestClass with either of the classes, they both result in a call to the least specific extension implementation, while it would be expected to call the most specific one.
class Object {}
class SubObject: Object {}
protocol MyProtocol {
associatedtype T: Object
func save()
}
extension MyProtocol {
func save() {
print("Object")
}
}
extension MyProtocol where T == SubObject {
func save() {
print("SubObject")
}
}
class MyClass<T: Object>: MyProtocol {
}
class TestClass<T: Object> {
typealias U = MyClass<T>
func test() {
let myClass = U()
myClass.save()
}
}
let testClass1 = TestClass<Object>()
testClass1.test() // returns "Object"
let testClass2 = TestClass<SubObject>()
testClass2.test() // returns "Object" (should be "SubObject")
How can I solve this, so that the TestClass calls the correct implementation of save? Or is this not currently possible in Swift? Any help would be appreciated!
I've got 3 protocols and a function which has to determine the most specialized protocol
protocol Super {}
protocol Sub1: Super { associatedtype T }
protocol Sub2: Super {}
func test(_ s: Super) { ... do stuff }
Now I've tried it with type erasure
class AnySub<E>: Sub1 {
typealias T = E
// ... standard type erasure init
}
with following changes:
protocol Super {
func tryAsSub1() -> AnySub? {}
}
extension Sub1 {
func tryAsSub1() -> AnySub<T> { return AnySub<T>() }
}
extension Sub2 {
func tryAsSub1() -> AnySub { return nil }
}
func test(_ s: Super) {
if let sub1 = s.tryAsSub1() { ... do stuff for Sub1 }
else let sub2 = s as? Sub2 { ... do stuff for Sub2 }
}
But that obviously does not work, because I don't have any generic parameter in Super and Sub2.
Does anybody have an idea, how I can solve this?
Since Sub1 uses associated types, you cannot determine at runtime if a certain variable is of that type. Type erasers help to a certain degree, however it's hard to use multiple eraser types. My recommendation would be to overload the test method for every type you need to handle. This also adds more type safety to you code.
func test<S: Sub1, T>(_ s: S) where S.T == T
func test(_ s: Sub2)
The above solution won't work however for the scenario where you have a collection of Super elements, and you need to execute some actions based on the actual type. For this scenario a possible approach is to move the test method at the protocol level, and override in the child protocols.
protocol Super {
func test()
}
protocol Sub1: Super { associatedtype T }
protocol Sub2: Super {}
extension Sub1 {
func test() { ... do stuff for Sub1 }
}
extension Sub2 {
func test() { ... do stuff for Sub2 }
}
The downside is that conformers can override test, thus you'd loose the original implementation.
In swift, an instance func can't call a static/class func without prefixing the method call with the class name. OR you can use type(of: self), e.g
class Foo {
static func doIt() { }
func callIt() {
Foo.doIt() // This works
type(of: self).doIt() // Or this
doIt() // This doesn't compile (unresolved identifier)
}
}
My question is, what's the difference here?
Is it just a matter of coding style, or is there some difference e.g. static or dynamic dispatch going on?
If it is just coding style, what's the preferred style?
There are two main differences.
1. The value of self inside the static method
The metatype that you call the static method on is available to you in the method as self (it's simply passed as an implicit parameter). Therefore if you call doIt() on type(of: self), self will be the dynamic metatype of the instance. If you call it on Foo, self will be Foo.self.
class Foo {
static func doIt() {
print("hey I'm of type \(self)")
}
func callDoItOnDynamicType() {
type(of: self).doIt() // call on the dynamic metatype of the instance.
}
func classDoItOnFoo() {
Foo.doIt() // call on the metatype Foo.self.
}
}
class Bar : Foo {}
let f: Foo = Bar()
f.callDoItOnDynamicType() // hey I'm of type Bar
f.classDoItOnFoo() // hey I'm of type Foo
This difference can be really important for factory methods, as it determines the type of instance you create.
class Foo {
required init() {}
static func create() -> Self {
return self.init()
}
func createDynamic() -> Foo {
return type(of: self).create()
}
func createFoo() -> Foo {
return Foo.create()
}
}
class Bar : Foo {}
let f: Foo = Bar()
print(f.createDynamic()) // Bar
print(f.createFoo()) // Foo
2. The dispatching of the static method
(Martin has already covered this, but I thought I would add it for the sake of completion.)
For class methods that are overridden in subclasses, the value of the metatype that you call the method on determines which implementation to call.
If called on a metatype that is known at compile time (e.g Foo.doIt()), Swift is able to statically dispatch the call. However, if you call the method on a metatype that isn't known until runtime (e.g type(of: self)), the method call will be dynamically dispatched to the correct implementation for the metatype value.
class Foo {
class func doIt() {
print("Foo's doIt")
}
func callDoItOnDynamicType() {
type(of: self).doIt() // the call to doIt() will be dynamically dispatched.
}
func classDoItOnFoo() {
Foo.doIt() // will be statically dispatched.
}
}
class Bar : Foo {
override class func doIt() {
print("Bar's doIt")
}
}
let f: Foo = Bar()
f.callDoItOnDynamicType() // Bar's doIt
f.classDoItOnFoo() // Foo's doIt
For a class method it makes a difference if the method is
overridden in a subclass:
class Foo {
class func doIt() {
print("Foo doit")
}
func callViaClassname() {
Foo.doIt()
}
func callViaTypeOf() {
type(of: self).doIt()
}
}
class Bar: Foo {
override class func doIt() {
print("Bar doit")
}
}
Bar().callViaClassname() // Foo doit
Bar().callViaTypeOf() // Bar doit
This is also documented in "Types" in the Swift Language Reference:
You can use a type(of:) expression with an instance of a type to access that instance’s dynamic, runtime type as a value, ...
I don't know a difference for a static method (which is final
and cannot be overridden in a subclass).
Correction: See Hamish's answer for the difference
in both static and class methods.
What I tried to do:
protocol HasElement {
associatedtype ItemType
func getElement() -> ItemType
func setElement(element: ItemType)
}
class Element {}
class BarElement: Element {}
class Foo: NSObject, HasElement {
typealias ItemType = Element
func getElement() -> Element { ... }
func setElement(element: Element) { ... }
}
class Bar: Foo {
typealias ItemType = BarElement
override func getElement() -> BarElement { ... } // This works.
override func setElement(element: BarElement) { ... } // This fails.
}
The error is:
Method does not override any method from its superclass
If I try to use ItemType instead:
override func setElement(element: ItemType) { ... } // Still fails.
The error is:
'ItemType' is ambiguous for type lookup in this context
Is there a way to make this work?
Here's a way to do what you want:
protocol HasElement {
associatedtype ItemType
func getElement() -> ItemType
func setElement(element: ItemType)
}
class Element {}
class BarElement: Element {}
class Foo: HasElement {
// no need for typealias, the associated type is inferred
func getElement() -> Element { return Element() }
func setElement(element: Element) { }
}
class Bar: Foo {
// no need for typealias, the associated type is inferred
override func getElement() -> BarElement { return BarElement() }
// hide the parent class method
#available(*, unavailable, message: "Use setElement(element: BarElement)")
override func setElement(element: Element) { }
// comply with protocol in this class
func setElement(element: BarElement) { }
}
// can't do this now:
let myElement = Element()
let myBar = Bar()
myBar.setElement(element: myElement) // Error: 'setElement(element: BarElement)' is unavailable: Use setElement(element: BarElement)
The problem here isn't associated types, it's that method inputs are contravariant. Therefore you cannot override a method that expects a given superclass instance input with a method that expects a subclass instance input.
In fact, you can simply boil your code down to:
class Element {}
class BarElement : Element {}
class Foo {
func setElement(element: Element) { }
}
class Bar : Foo {
// error: Method does not override any method from its superclass
override func setElement(element: BarElement) { }
}
You simply cannot override an (Element) -> Void method with a (BarElement) -> Void method. The reasons for this should be fairly obvious if you consider what would happen if you created a Bar instance and upcast it to Foo. You're now able to pass an Element instance to a method that expects a BarElement instance, which is illegal.
The reason it works for your getElement method is that method outputs are covariant. Therefore overriding a () -> Element method with a () -> BarElement method is perfectly legal, as even if you upcast a Bar instance to Foo, the BarElement instance returned from getElement can be freely upcast to Element.
As for solutions, it rather depends on your exact use case. It may well be that what you're trying to do doesn't require inheritance at all, and instead you can just conform Foo and Bar to HasElement separately.
This works:
override func getElement() -> BarElement { ... }
using override keyword is when function signature does not change (BarElement is still Element). You copy and paste function from super class with same function name, same parameter name and same return value type.
But
override func setElement(element: BarElement) { ... }
fails because when you change parameter type (with same parameter name).
This case is overloading not overriding.
I have the following protocol defined in Swift:
protocol RecordingObserver {
func aFunc()
}
Somewhere I have to compare two objects that implement this protocol, to check if they are the same. The problem I'm facing is that apparently Swift doesn't allow us to do this:
func areEqual(a:RecordingObserver,b:RecordingObserver){
if a === b {
println("Equal")
}
}
Any idea why this is happening? And how I can do this in another way?
=== is the identical to operator and is used to test whether two object references both refer to the same object instance. It can be applied
only to reference types (i.e. instances of a class).
=== is different from the "equal to" operator == (which is required in the Equatable protocol).
Therefore, assuming that
the actual observers are instances of a class, and
your intention is to check if a and b refer to the same instance,
you have to define the protocol as a class protocol:
protocol RecordingObserver : class {
// ...
}
Then
func areEqual(a:RecordingObserver,b:RecordingObserver){
if a === b {
println("a and b refer to the same object instance")
}
}
compiles (and works as expected) because the compiler knows that a and b are reference types.
Your class needs to support the Equatable protocol to use ==
https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/Equatable.html
Or if you want to use === something like this...
protocol RecordingObserver {
func aFunc()
}
class MyClass: RecordingObserver {
func aFunc() {
// Do something
}
}
func areEqual(a: MyClass, b: MyClass){
if a === b {
println("Equal")
}
}
I believe there is an 'isEqual' method on NSObject. If your custom objects are both subclassed from that you should be able to compare a.isEqual(b).
It is because you said that you objects implement only RecordingObserver. So compiler don't know if he can compare them.
Try this:
func areEqual<T where T: Equatable, T: RecordingObserver>(a: T,b: T) {
}
You can just copy this code into single view project to test:
protocol RecordingObserver {
}
class SomeClass: NSObject, RecordingObserver {
}
class ViewController: UIViewController {
func areEqual<T where T: Equatable, T: RecordingObserver>(a: T,b: T) -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
let a = SomeClass()
let b = SomeClass()
NSLog("\(areEqual(a, b: b))")
}
}