I'm trying to implement a simple mutable set as a way to learn Swift, but the code below gives me the following compiler error for the add and remove methods:
Could not find an overload for 'subscript' that accepts the supplied arguments
What am I doing wrong?
class SwiftSet<T: Hashable> {
let _underlyingSet: Dictionary<T, Bool>
init() {
_underlyingSet = Dictionary<T, Bool>()
}
subscript(k: T) -> Bool {
if _underlyingSet[k] {
return true
}
else {
return false
}
}
func contains(k: T) -> Bool {
return self[k]
}
func add(k: T) {
_underlyingSet[k] = true
}
func remove(k: T) {
_underlyingSet[k] = nil
}
func allObjects() -> T[] {
return Array(_underlyingSet.keys)
}
}
Because you're trying to modify an immutable constant defined with let _underlyingSet in your add() and remove() methods.
If you want to modify a variable after initialization you should change it to var _underlyingSet, i.e:
class SwiftSet<T: Hashable> {
var _underlyingSet: Dictionary<T, Bool>
init() {
_underlyingSet = Dictionary<T, Bool>()
}
subscript(k: T) -> Bool {
if _underlyingSet[k] {
return true
}
else {
return false
}
}
func contains(k: T) -> Bool {
return self[k]
}
func add(k: T) {
_underlyingSet[k] = true
}
func remove(k: T) {
_underlyingSet[k] = nil
}
func allObjects() -> T[] {
return Array(_underlyingSet.keys)
}
}
You've declared _underlyingSet as a constant, so it doesn't have a defined setter for its subscript. Change its declaration to:
var _underlyingSet: Dictionary<T, Bool>
Related
This question already has answers here:
Use Type Erasure return Generic Type in a function with Swift (Cannot convert return expression of type…)
(3 answers)
Closed 2 years ago.
This is the real life code. https://gist.github.com/Terriermon/0fa20dae02fed0c39b4bfe54e7db50b8
This is new code. I think this code show the problem in my project.
protocol TestReturnTypeProtocol {
associatedtype T
func test(_ type: T)
}
protocol Testable {}
extension Int: Testable { }
extension String: Testable { }
class AnyTestReturnType<Type>: TestReturnTypeProtocol where Type: Testable {
init<P: TestReturnTypeProtocol>(_ p: P) where P.T == Type { }
func test(_ type: Type) { }
}
class IntReturnClass: TestReturnTypeProtocol {
func test(_ type: Int) { }
}
class StringReturnClass: TestReturnTypeProtocol {
func test(_ type: String) { }
}
func tesfFunction<T: Testable>(isInt: Bool) -> AnyTestReturnType<T> {
if isInt {
let intRet = AnyTestReturnType(IntReturnClass())
return intRet
} else {
let strRet = AnyTestReturnType<String>(StringReturnClass())
return strRet
}
}
This is the code.
And I do not want to use the as!,Because It can not work in some cases.
In my project ,if I use the as, It will complain Cast from 'AnyValidatorConvertible<Int>' to unrelated type 'AnyValidatorConvertible<T>' always fails
protocol TestProtocol { }
extension Int: TestProtocol { }
extension String: TestProtocol { }
class TestClass<T: TestProtocol> {
let value: T
init(value: T) {
self.value = value
}
}
func testFunction<T: TestProtocol>(isInt: Bool) -> TestClass<T> {
if isInt {
return TestClass(value: 0)
} else {
return TestClass(value: "")
}
}
This is the error message. Cannot convert value of type 'Int' to expected argument type 'T'.
Anyway, I think it should be the third case in your conditions.
protocol TestProtocol { }
extension Int: TestProtocol { }
extension String: TestProtocol { }
class TestClass<T: TestProtocol> {
let value: T
init(value: T) {
self.value = value
}
}
func testFunction<T: TestProtocol>(isInt: Bool) -> TestClass<T>? {
if isInt, let genericInt = 0 as? T {
return TestClass(value: genericInt)
} else if let genericString = "" as? T {
return TestClass(value: genericString)
}
return nil
}
Int, String and T conform to TestProtocol.
But all of three is not the same.
According to your codes,
You should put T.type into TestCalss(value: T) not TestProtocol.
So You are supposed to cast the argument
import Foundation
protocol TestProtocol { }
extension Int: TestProtocol { }
extension String: TestProtocol { }
class TestClass<T: TestProtocol> {
let value: T
init(value: T) {
self.value = value
}
static func makeTestClass(isInt: Bool) -> TestClass? {
switch isInt {
case true where 0 is T:
return TestClass(value: 0 as! T)
case false where "" is T:
return TestClass(value: "" as! T)
default:
return nil
}
}
}
Here's the code,
protocol TestType : AnyObject {
}
class Generic<TestType> : NSObject {
private let filterFunction : (TestType,String) -> Bool
init(filter: #escaping (TestType,String) -> Bool) {
filterFunction = filter
}
}
class Parent : UIViewController {
public var generic : Generic<TestType>!
}
class Child : Parent {
override func viewDidLoad() {
// ERROR THIS LINE
generic = Generic<Object>(filter: { (str1, str2) -> Bool in
return true
})
}
}
class Object : TestType {
}
The error is:
Cannot assign value of type 'Generic<Object>' to type 'Generic<TestType>!'
I tried many things, like typealias, but can't compile the code.
The problem is that i don't want a Parent<TestType> or Child<TestType> class, since i want to be able to use it in IB.
How can i store a reference of Generic in the Parent, and initialize it in Child (dynamically, by setting the concrete TestType like Object or another)
I finally succeed doing what i wanted!
Not perfect at all, feel free to comment for architecture improvements (especially on the asBaseProtocol() part...)
Here's my complete code (Swift 3.0)
DataFilter
protocol DataFilterDelegate : class {
func didFilter()
func didUpdateItems()
}
class DataFilter<T> {
public weak var delegate : DataFilterDelegate?
private var items : [SelectableItem<T>]?
private var filteredItems : [SelectableItem<T>]?
var source: [SelectableItem<T>]? {
get {
if filteredItems != nil {
return filteredItems
}
return items
}
}
var filter : (T,String) -> Bool
var populateCell : (T) -> UITableViewCell
init(filter : #escaping (T,String) -> Bool, populateCell: #escaping (T) -> UITableViewCell) {
self.filter = filter
self.populateCell = populateCell
}
func updateItems(_ items: [T]) {
self.items = [SelectableItem<T>]()
for item in items {
self.items?.append(SelectableItem(item))
}
delegate?.didUpdateItems()
}
func filterItems(text : String) {
filteredItems = (text == "") ? nil : items?.filter { item in
filter(item.item, text)
}
delegate?.didFilter()
}
func selectedItems() -> [T]? {
guard let items = items else {
return nil
}
var selectedItems = [T]()
for item in items {
if item.isSelected {
selectedItems.append(item.item)
}
}
return selectedItems
}
}
extension DataFilter where T : FIRDataObject {
func asBaseProtocol() -> DataFilter<FIRDataObject> {
return DataFilter<FIRDataObject>(filter: filterAsBaseProtocol(), populateCell: populateCellAsBaseProtocol())
}
private func filterAsBaseProtocol() -> ((FIRDataObject,String) -> Bool) {
return { (object, text) -> Bool in
self.filter(object as! T, text)
}
}
private func populateCellAsBaseProtocol() -> ((FIRDataObject) -> UITableViewCell) {
return { (object) -> UITableViewCell in
self.populateCell(object as! T)
}
}
}
ParentViewController Class
class ParentViewController : UIViewController {
public var dataFilter : DataFilter<FIRDataObject>? {
didSet {
dataFilter!.delegate = self
}
}
// Some Functions using dataFilter
}
ChildViewController Class
class ChildViewController : Parent {
// Stored as a variable to not have to cast objects to the good type everytime I access dataFilter
private var patientDataFilter = DataFilter<Patient>(filter: { patient, text in
patient.firstname.contains(text) ||
patient.lastname.contains(text)
}
, populateCell: { patient in
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Patient")
cell.textLabel?.text = patient.lastname + " " + patient.firstname
cell.detailTextLabel?.text = patient.postalCode + " " + patient.city
return cell
})
override func viewDidLoad() {
super.viewDidLoad()
dataFilter = patientDataFilter.asBaseProtocol()
}
func someFunc() {
let patient1 = patientDataFilter.source[0].item
// OR
let patient2 = dataFilter.source[0].item as! Patient
}
}
Here, layEgg() wants to reuse chickenFactory(Chicken.Type). The problem is that layEgg returns Self? so that I get an instance of whatever type this is or nil.
However, chickenFactory returns a Chicken, which needs to be cast to whatever type I am.
enum BiologicalGender : String {
case male = "male"
case female = "female"
}
class Chicken {
let gender : BiologicalGender
required init (_ gender : BiologicalGender) {
self.gender = gender
}
class func chickenFactory(_ chickenType : Chicken.Type) -> Chicken {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
func layEgg() -> Self? {
if (self.gender == .female) {
return Chicken.chickenFactory(type(of:self)) // need a cast here
} else {
return nil
}
}
}
How do I cast polymorphically?
The problem is that chickenFactory(_:) says that it takes a type of type Chicken.Type as an argument and outputs an instance of Chicken. The instance that is outputted need not be of type the type you passed in (for example, it could output an instance of Chicken when you input a type of ChickenSubclass.self).
What you want is not type-casting, but rather a way to say that the instance outputted is the same type as the type you input. To express this, you can use a generic placeholder:
class func chickenFactory<T : Chicken>(_ chickenType : T.Type) -> T {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
Now
func layEgg() -> Self? {
if (self.gender == .female) {
return Chicken.chickenFactory(type(of: self))
} else {
return nil
}
}
compiles just fine, as the compiler knows that an instance of type type(of: self) can be returned from a function returning Self?.
Although that all being said, the type argument to chickenFactory(_:) is seemingly redundant, you could just use the type that it's called on instead through the use of self at static scope:
class func chickenFactory() -> Self {
if (arc4random_uniform(2) == 0) {
return self.init(.male)
} else {
return self.init(.female)
}
}
func layEgg() -> Self? {
if (self.gender == .female) {
return type(of: self).chickenFactory()
} else {
return nil
}
}
Another solution for the problem would be this. Check this answer
func layEgg() -> Self? {
if (self.gender == .female) {
return makeEgg()
} else {
return nil
}
}
func makeEgg<T>()->T?{
return Chicken.chickenFactory(type(of:self)) as? T
}
This does not necessarily improve the code, but here is a class function wrapping the original factory that accomplishes the cast to Self that so many of you demonstrated.
The original, improved generic chickenFactory() is also included.
class Chicken {
let gender : BiologicalGender
required init (_ gender : BiologicalGender) {
self.gender = gender
}
class func chickenFactory<T:Chicken>(_ chickenType : T.Type) -> T {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
class func poorlyTypedChickenFactory(_ chickenType : Chicken.Type) -> Chicken {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
private class func chickenFromPoorlyTypedFactory<T>(_ chickenType : Chicken.Type) -> T?
{
let chicken = poorlyTypedChickenFactory(chickenType) as? T
return chicken
}
func layEgg() -> Self? {
if (self.gender == .female) {
return Chicken.chickenFromPoorlyTypedFactory(type(of:self))
} else {
return nil
}
}
}
I am following this Generic tutorial from Apple https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html.
But in the end of tutorial. I got some problem with this:
var myStack = Stack<String>()
myStack.push("a")
myStack.push("b")
myStack.push("c")
var arrayOfStrings = ["a", "b", "c"]
if allItemsMatch(myStack, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
at the line if allItemsMatch(myStack, arrayOfStrings), it says:
Cannot invoke 'allItemsMatch' with an argument list of type
'(Stack< String>, [String])'
Here is my code:
import UIKit
struct Stack<Element> {
var items = [Element]()
mutating func push(item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
mutating func append(item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
for (index, value) in array.enumerate() {
if value == valueToFind {
return index
}
}
return nil
}
let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
extension Array: Container {}
func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> (someContainer: C1, _ anotherContainer: C2) -> Bool {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
var myStack = Stack<String>()
myStack.push("a")
myStack.push("b")
myStack.push("c")
var arrayOfStrings = ["a", "b", "c"]
if allItemsMatch(myStack, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
Am I missing somewhere?
You never explicitly conform your Stack<Element> struct to your Container protocol. Therefore Swift's strict type safety will prevent you from passing it into a parameter that expects something that conforms to the Container protocol (even if it implicitly conforms).
You can explicitly conform your Stack to Container via an extension. For example:
extension Stack:Container {}
I've setup two protocols below in swift 2
Generative (for the lack of a better name) which holds an array of items and provides Datasource like functionality like count and subscript
public protocol Generative {
typealias GeneratedType
var elements: [GeneratedType] { get }
}
public extension Generative {
func count() -> Int {
return elements.count
}
subscript(index:Int) -> GeneratedType? {
if index >= count() {
return nil
}
return elements[index]
}
}
public protocol Selectable {
typealias SelectableType: Hashable
var selectedElements: Set<SelectableType> { get set }
}
extension Selectable {
public func isSelected(elem: SelectableType) -> Bool {
return selectedElements.contains(elem)
}
public mutating func addSelection(elem: SelectableType) {
selectedElements.insert(elem)
}
public mutating func removeSelection(elem: SelectableType) {
selectedElements.remove(elem)
}
public mutating func clearSelections() {
selectedElements.removeAll()
}
}
So in case an object implements both Generative and Selectable then I want it to be able to return the selected indices so I wrote this function:
func selectedIndices<S: Selectable where S: Generative, S.GeneratedType == S.SelectableType>(ds: S) -> [NSIndexPath] {
var selections: [NSIndexPath] {
return ds.selectedElements
.map{ (p: S.GeneratedType) -> NSIndexPath? in
if let idx = ds.elements.indexOf(p) { idx
return NSIndexPath(forRow: idx, inSection: 0)
}
return nil
}
.filter{ $0 != nil }
.map{ $0! }
}
return selections
}
for some reason the linker prints out:
Command failed due to signal: Segmentation fault: 11
Not sure why is that, I can't figure out another way to specify this function to work on objects which implement both protocols and their associated types match...
Any ideas ?
P.S. the code in a Gist: https://gist.github.com/edwardIshaq/715b0e134fb47d2e28cc
------- UPDATE
removing the computed property seemed to do the trick :
func selectedIndices<S: Selectable where S: Generative, S.GeneratedType == S.SelectableType>(ds: S) -> [NSIndexPath] {
return ds.selectedElements
.flatMap { (p: S.GeneratedType) -> NSIndexPath? in
if let idx = ds.elements.indexOf(p) { idx
return NSIndexPath(forRow: idx, inSection: 0)
}
return nil
}
}
The compiler should never crash, but it looks like the cause is simpler, seems to be to do with generic functions that use computed properties internally, this is as simple as I can get it:
// swiftc crashes when compiling this
func f<T>(t: T) -> Int {
var v: Int {
return 0
}
return v
}
so as a workaround, try refactoring the code to not use the computed property.
You could do that, and write this as an extension of the two protocols, like this:
extension Selectable
where Self: Generative,
Self.GeneratedType == NSIndexPath,
Self.SelectableType == NSIndexPath
{
func selectedIndices() -> [NSIndexPath] {
return self.selectedElements.flatMap {
self.elements.indexOf($0).map { NSIndexPath(index: $0) }
}
}
}