how the ambiguity can be resolved in this case provided that I can't change the name Static and the name SOMECONST for each class (to keep a consistent convention across the API classes)
it might or might not work in playgrounds but the error AMBIGUOUS USE OF SOMECONST appears during compilation in Xcode.
If it's not possible then I'm going to revert to getters, any person got an idea if Apple will implement static for classes or it's only designed for struct and enum???
public class A {
public struct Static {
public static let SOMECONST = 1
}
init(val: Int) {
println(val)
}
}
public class B: A {
public struct Static {
public static let SOMECONST = 2
}
init() {
super.init(val: B.Static.SOMECONST)
}
}
B()
The program (unsurprisingly) can't compile because it found two candidates for the SOMECONST symbol:
error: ambiguous use of 'SOMECONST'
super.init(val: B.Static.SOMECONST)
^
note: found this candidate
static let SOMECONST = 2
^
note: found this candidate
static let SOMECONST = 1
^
Using nested types for storing constants like this is generally a bad idea, because nested types can't be overriden by subclasses. You should declare the constants directly as part of your class.
Now, ideally you would do something like this:
class A {
class let SOMECONST = 1
}
class B: A {
override class let SOMECONST = 2
}
But, unfortunately, this is not supported by the current Swift compiler. The only way you can override a class (static) variable is to make it computable:
class A {
class var SOMECONST: Int {
return 1
}
}
class B: A {
override class var SOMECONST: Int {
return 2
}
}
That's a little bit uglier, but it works. You can now create your B's initializer:
init() {
super.init(val: B.SOMECONST) // prints "2"
}
Related
I have the script below written in Swift 5 and I am doing something wrong to configure the generics.
Basically it's a Foo protocol with a function with has an argument with a generic type and it's implemented in both Fez and Foz, where the type of the bar function is defined in the class definition. By using associatedtype is possible to fix this?
Any idea of what could be and how to solve it? Am I doing something wrong with the setup of generics? I need to support both Int and String.
protocol Foo {
func bar<T>(zed: T)
}
class Fez: Foo {
private var zed: Int = 0
func bar<Int>(zed: Int) {
self.zed = zed //Cannot assign value of type 'Int' to type 'Swift.Int'
}
}
class Foz: Foo {
private var zed: String = ""
func bar<String>(zed: String) {
self.zed = zed //Cannot assign value of type 'String' to type 'Swift.String'
}
}
Thank you very much.
For the downvoter: I hope you have a nice day.
A generic like this says that the caller can choose any type to pass to bar, and the implementation will handle it. You mean that the implementation gets to decide what type it can be passed, and that's an associatedtype as you suggest.
protocol Foo {
associatedtype Zed
func bar(zed: Zed)
}
class Fez: Foo {
private var zed: Int = 0
func bar(zed: Int) {
self.zed = zed
}
}
class Foz: Foo {
private var zed: String = ""
func bar(zed: String) {
self.zed = zed
}
}
I have a abstract base class (DataSource, in my simplified scenario below) and a handful of subclasses (IntSource and StringSource). The base class is using generics.
I want to have a variable (say, currentDataSource) typed as the base class so it can refer to an instance of any of the subclasses. I can't figure out how to declare it, though. The declaration requires a concrete type which immediately breaks the abstraction.
class DataSource<Element> where Element:Equatable {
var elements = [Element]()
func description() {
print("must override")
}
}
class IntSource: DataSource<Int> {
override func description() {
print("Ints!")
}
}
class StringSource: DataSource<String> {
override func description() {
print("Strings!")
}
}
let a = IntSource()
let b = StringSource()
var current: DataSource<???> // this is where I'm stuck
current = a
print(current.description())
current = b
print(current.description())
enum Type {
case A
case B
func do() {
}
}
I would like do for available for case A
I don't think what you want is possible with enums.
However, it can be done with tricks.
First, create a class called Type:
class Type { private init() {} }
And create two classes, AType and BType to inherit Type:
// Put this in the same file as Type
class AType: Type { private init() {} }
class BType: Type { private init() {} }
The private initializer is to prevent external code to create AType and BType objects.
In Type, add these static properties:
static let A = AType()
static let B = BType()
Then you're basically done!
To add a method that only Type.A is accessible, just add it in the AType class!
This way, just like an enum, Type.A and Type.B can still be assigned to a Type object!
The question is better explained in code:
class A {
class func thefunc() -> String {
/* Can I here know if thefunc was called using
A.thefunc() or
B.thefunc()?
*/
return "A" /* or "B"= */
}
}
class B: A {
}
You can use self in a static method to refer to the type (as compared to the instance for using self in an instance method)
class A {
class func thefunc() -> A.Type {
return self
}
}
class B: A { }
let metaTypeA = A.thefunc() // A.Type
let metaTypeB = B.thefunc() // B.Type
Similarly, you can use runtime introspection, specifically the subjectType property of the Mirror representation of self.
Instance Variables
...
var subjectType: Any.Type
The static type of the subject being reflected.
From the swiftdoc.org reference of Mirror structure.
E.g.:
class A {
class func thefunc() {
print(Mirror(reflecting: self).subjectType)
}
}
class B: A { }
A.thefunc() // A.Type
B.thefunc() // B.Type
Alternatively, if you needn't actually make use of the meta-type (just differ between the "static caller"), you could use the String representation of self.
class A {
class func thefunc() -> String {
return String(self)
}
}
class B: A { }
print(A.thefunc()) // A
print(B.thefunc()) // B
According to Apple's documentation Swift does not necessary require override of initializer. In a following code example Bar inherits initializer of Foo:
class Foo {
let value: Int
init(value: Int = 5) {
self.value = value
}
}
class Bar: Foo {
}
As soon as we add some generic into Foo such as class Foo<T> { Xcode provides us a error Initializer does not override a designated initializer from its superclass. Is there a documentation or swift evolution discussion that explains why it is happening?
Update. It seems that generic is not a major cause for override requirement. Here are an option how to define a class with generic that does not require override of designated initializer:
protocol FooProtocol {
associatedtype T
}
class Foo<U>: FooProtocol {
typealias T = U
let value: Int
init(value: Int, otherValue: T) {
self.value = value
self.otherValue = otherValue
}
}
class Bar: Foo<Int> {
}
However there is another interesting observation of behavior. Defining initializer like following cause override requirement:
init(value: Int = 5) {
self.value = value
}
The funny thing thing that adding one more parameter as following into such designated initializer cause this override requirement to disappear:
init(value: Int = 5, otherValue: T) {
self.value = value
}
Update 2. I can not find a logical explanation to this behavior, at this point I reported it as Compiler bug — https://bugs.swift.org/browse/SR-1375
I actually filled a bug report for inheriting from generic class:
It was back in November last year and didn't get an answer yet, so ¯_(ツ)_/¯
It's clearly a bug. Moreover, although the bug is elicited by subclassing a generic, its proximate cause is the default value. This compiles just fine:
class Foo<T> {
let value: Int
init(value: Int) {
self.value = value
}
}
class Bar: Foo<String> {
}
But this does not:
class Foo<T> {
let value: Int
init(value: Int = 5) {
self.value = value
}
}
class Bar: Foo<String> {
}
That sort of arbitrary distinction without a difference is a sure indication that this is a compiler bug.