Differences between subscript and functions in Swift - swift

Is there any difference between subscript and a function in swift? Can someone explain me with a little example?

if you mean subscripts for custom classes, then no. looks like they are just syntactic sugar for computed properties
class IHaveASubscript<T> {
private var array: Array<T>
init() {
array = []
}
subscript (index: Int) -> T {
get {
return array[index]
}
set(newValue) {
array[index] = newValue
}
}
func elementAtIndex(index: Int) -> T {
return array[index]
}
func setElementAtIndex(index: Int, element: T) {
array[index] = element
}
}

Related

Extending a Collection where the Element type is generic (Swift)

It's simple to extend a Collection type in swift to have a custom function for particular Element types:
struct MyStruct {
let string: String
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
But suppose your Element type is generic?
protocol MyProtocol {}
struct MyGenericStruct<T: MyProtocol> {
let string: String
}
// error on next line:
// error: expected '>' to complete generic argument list
// extension Set where Element == MyGenericStruct<T: MyProtocol> {
// ^
extension Set where Element == MyGenericStruct<T: MyProtocol> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
// error on next line:
// error: use of undeclared type 'T'
// extension Set where Element == MyGenericStruct<T> {
// ^
extension Set where Element == MyGenericStruct<T> {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
It's unclear to me how to declare that my element is a generic.
Details
Swift 3.1, xCode 8.3.3
Solution
import Foundation
struct MyStruct:Hashable {
let string: String
static func == (lhs: MyStruct, rhs: MyStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == MyStruct {
func getFirstWith(string: String) -> Element? {
return filter({ $0.string == string }).first
}
}
var set = Set<MyStruct>()
set.insert(MyStruct(string: "123"))
set.insert(MyStruct(string: "231"))
print(String(describing:set.getFirstWith(string: "123")))
print(String(describing:set.getFirstWith(string: "231")))
///////////////////////////////////
protocol MyProtocol {}
struct MyType1: MyProtocol {}
struct MyType2: MyProtocol {}
struct MyGenericStruct<T: MyProtocol>: Hashable {
let string: String
static func == (lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.string == rhs.string
}
var hashValue: Int {
return string.hash
}
}
extension Set where Element == AnyHashable {
func getFirstWith(string: String) -> Element? {
return filter{ element -> Bool in
if let _element = element as? MyGenericStruct<MyType1> {
if _element.string == string {
return true
}
}
if let _element = element as? MyGenericStruct<MyType2> {
if _element.string == string {
return true
}
}
return false
}.first
}
}
var set2 = Set<AnyHashable>()
set2.insert(MyGenericStruct<MyType1>(string: "abc"))
set2.insert(MyGenericStruct<MyType2>(string: "cba"))
print(String(describing: set2.getFirstWith(string: "abc")))
print(String(describing:set2.getFirstWith(string: "cba")))
Result
Answering my own question here on request.
I was unable to figure out how to make this an extension on Set.
Instead, we wrote a little utility function. Not as clear as a extension, but gets the work done. It looks like this:
func getFirst<T: MyProtocol>(fromSet set: Set<MyGenericStruct<T>>, whereStringIs string: String) -> MyGenericStruct<T>? {
return set.first(where: { $0.string == string })
}
As others have noted, MyGenericStruct needs to be Hashable.
If I do understand the purpose, you probably need to have more implementation in your protocol and structure.
First, element's protocol has to be hashable and equitable.
protocol MyProtocol: Hashable, Equatable {
var string: String { get }
}
Therefore, MyGenericStruct will look like the following.
struct MyGenericStruct: MyProtocol {
let string: String
var hashValue: Int {
get {
return string.hashValue
}
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
Then, declare extension with constraints specified by a where clause for MyProtocol
extension Set where Element: MyProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
Finally, let's do a test and see its result.
// Example
let set: Set = [
MyGenericStruct(string: "Watermelon"),
MyGenericStruct(string: "Orange"),
MyGenericStruct(string: "Banana")
]
let output = set.getFirstWith(string: "Orange")
print(output)
In my playground with Xcode 8, I can get Optional(MyGenericStruct(string: "Orange")) in log.
[UPDATED1] To make an Extension on Set<MyGenericStruct> only:
extension Set where Element == MyGenericStruct {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
[UPDATED2] In case to keep MyGenericStruct<T: MyProtocol> declaration as stated is necessary, another approach to implement Set extension:
protocol MyProtocol {
}
struct BaseStruct1: MyProtocol {
}
struct BaseStruct2: MyProtocol {
}
protocol ContainStringProtocol: Hashable {
var string: String { get }
}
struct MyGenericStruct<T: MyProtocol>: ContainStringProtocol {
var string: String
var hashValue: Int {
get {
return string.hashValue
}
}
init(string: String) {
self.string = string
}
static func ==(lhs: MyGenericStruct, rhs: MyGenericStruct) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
extension Set where Element: ContainStringProtocol {
func getFirstWith(string: String) -> Element? {
return filter({$0.string == string}).first
}
}
// Example
let set1: Set = [
MyGenericStruct<BaseStruct1>(string: "Watermelon"),
MyGenericStruct<BaseStruct1>(string: "Orange"),
MyGenericStruct<BaseStruct1>(string: "Banana")
]
let output1 = set1.getFirstWith(string: "Orange")
print(output1!)
let set2: Set = [
MyGenericStruct<BaseStruct2>(string: "Watermelon"),
MyGenericStruct<BaseStruct2>(string: "Orange"),
MyGenericStruct<BaseStruct2>(string: "Banana")
]
let output2 = set2.getFirstWith(string: "Orange")
print(output2!)

Class extension typealias's property type constraint

Mission: I need to provide an Array extension method which would compare 2 arrays of raw representables whose raw type conforms to Equatable and say if the arrays contain the same elements by reusing the below pieces of code.
What I have at the moment:
public extension Array {
func containsTheSameElements(as array: [Element], condition: #escaping (Element, Element) -> Bool) -> Bool {
var localCopy = array
let countOfUncommonElements = reduce(0) { (uncommonElementsCount: Int, item: Element) -> Int in
if let index = localCopy.index(where: {condition(item, $0)}) {
localCopy.remove(at: index)
return uncommonElementsCount
} else {
return uncommonElementsCount + 1
}
}
return countOfUncommonElements == 0 && count == array.count
}
}
func enumComparisonClosure<T: RawRepresentable>(firstItem: T, secondItem: T) -> Bool where T.RawValue: Equatable {
return firstItem == secondItem
}
How I'm using it at the moment:
class Somewhere {
enum EnumType: String {
case first
case second
}
func method() {
let firstArray: [EnumType] = [.first, .second]
let secondArray: [EnumType] = [.second]
firstArray.containsTheSameElements(as: secondArray, condition: enumComparisonClosure)
}
}
How I would like to use it:
firstArray.containsTheSameElements(as: secondArray)
How I would like to be able to implement it:
public extension Array {
func containsTheSameElements<Element: RawRepresentable>(as array: [Element]) -> Bool where Element.RawValue: Equatable {
return containsTheSameElements(as: array, condition: enumComparisonClosure)
}
}
How can I constrain the Array's extension "Element" typealias to be a RawRepresentable with RawValue of Equatable type?
Or what would be another approach to make this comparison possible?
The constraints on the extension are separated by a comma, not
by &. The containsTheSameElements must take a [T] argument
where T is a RawRepresentable with the same RawValue
as the array elements.
Example:
extension Array where Element: RawRepresentable, Element.RawValue: Equatable {
func containsTheSameElements<T>(as array: [T]) -> Bool
where T: RawRepresentable, T.RawValue == Element.RawValue
{
return self.count == array.count &&
!zip(self, array).contains { $0.rawValue != $1.rawValue }
}
}
Update: It is simpler if you need it only for arrays
of the same type:
extension Array where Element: RawRepresentable, Element.RawValue: Equatable {
func containsTheSameElements(as array: [Element]) -> Bool
{
return self.count == array.count &&
!zip(self, array).contains { $0.rawValue != $1.rawValue }
}
}
or, reusing your existing method:
extension Array where Element: RawRepresentable, Element.RawValue: Equatable {
func containsTheSameElements(as array: [Element]) -> Bool
{
return containsTheSameElements(as: array, condition: enumComparisonClosure)
}
}

Iterating through an Enum in Swift 3.0

I have a simple enum that I would like to iterate over. For this purpose, I've adopted Sequence and IteratorProtocol as shown in the code below. BTW, this can be copy/pasted to a Playground in Xcode 8.
import UIKit
enum Sections: Int {
case Section0 = 0
case Section1
case Section2
}
extension Sections : Sequence {
func makeIterator() -> SectionsGenerator {
return SectionsGenerator()
}
struct SectionsGenerator: IteratorProtocol {
var currentSection = 0
mutating func next() -> Sections? {
guard let item = Sections(rawValue:currentSection) else {
return nil
}
currentSection += 1
return item
}
}
}
for section in Sections {
print(section)
}
But the for-in loop generates the error message "Type 'Sections.Type' does not conform to protocol 'Sequence'".
The protocol conformance is in my extension; so, what is wrong with this code?
I know there are other ways of doing this but I'd like to understand what's wrong with this approach.
Thanks.
Note that Martin’s solution can be refactored as a protocol:
import Foundation
protocol EnumSequence
{
associatedtype T: RawRepresentable where T.RawValue == Int
static func all() -> AnySequence<T>
}
extension EnumSequence
{
static func all() -> AnySequence<T> {
return AnySequence { return EnumGenerator() }
}
}
private struct EnumGenerator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
var index = 0
mutating func next() -> T? {
guard let item = T(rawValue: index) else {
return nil
}
index += 1
return item
}
}
Then, given an enum
enum Fruits: Int {
case apple, orange, pear
}
you slap the protocol and a typealias:
enum Fruits: Int, EnumSequence {
typealias T = Fruits
case apple, orange, pear
}
Fruits.all().forEach({ print($0) }) // apple orange pear
Update: As of Swift 4.2, you can simply add protocol conformance
to CaseIterable, see How to enumerate an enum with String type?.
You can iterate over a value of a type which conforms to the Sequence
protocol. Therefore
for section in Sections.Section0 {
print(section)
}
would compile and give the expected result. But of course that is not
really what you want because the choice of the value is arbitrary and the
value itself not needed in the sequence.
As far as I know, there is no way to iterate over a type itself, so that
for section in Sections {
print(section)
}
compiles. That would require that the "metatype" Sections.Type conforms
to Sequence. Perhaps someone proves me wrong.
What you can do is to define a type method which returns a sequence:
extension Sections {
static func all() -> AnySequence<Sections> {
return AnySequence {
return SectionsGenerator()
}
}
struct SectionsGenerator: IteratorProtocol {
var currentSection = 0
mutating func next() -> Sections? {
guard let item = Sections(rawValue:currentSection) else {
return nil
}
currentSection += 1
return item
}
}
}
for section in Sections.all() {
print(section)
}
Simply add to enum:
static var allTypes: [Sections] = [.Section0, .Section1, .Section2]
And than you can:
Sections.allTypes.forEach { (section) in
print("\(section)")
}
This looks so much simpler:
public protocol EnumSequence {
init?(rawValue: Int)
}
public extension EnumSequence {
public static var items: [Self] {
var caseIndex: Int = 0
let interator: AnyIterator<Self> = AnyIterator {
let result = Self(rawValue: caseIndex)
caseIndex += 1
return result
}
return Array(interator)
}
}
Iterated upon the solutions above, see below a protocol that can be implemented by enumerations to add the allValues sequence but also to allow the possibility to convert to and from string value.
Very convenient for String-like enumerations which need to support objective c (only int enumerations are allowed there).
public protocol ObjcEnumeration: LosslessStringConvertible, RawRepresentable where RawValue == Int {
static var allValues: AnySequence<Self> { get }
}
public extension ObjcEnumeration {
public static var allValues: AnySequence<Self> {
return AnySequence {
return IntegerEnumIterator()
}
}
public init?(_ description: String) {
guard let enumValue = Self.allValues.first(where: { $0.description == description }) else {
return nil
}
self.init(rawValue: enumValue.rawValue)
}
public var description: String {
return String(describing: self)
}
}
fileprivate struct IntegerEnumIterator<T: RawRepresentable>: IteratorProtocol where T.RawValue == Int {
private var index = 0
mutating func next() -> T? {
defer {
index += 1
}
return T(rawValue: index)
}
}
For a concrete example:
#objc
enum Fruit: Int, ObjcEnumeration {
case apple, orange, pear
}
Now you can do:
for fruit in Fruit.allValues {
//Prints: "apple", "orange", "pear"
print("Fruit: \(fruit.description)")
if let otherFruit = Fruit(fruit.description), fruit == otherFruit {
print("Fruit could be constructed successfully from its description!")
}
}
If your enum is an Int based one, you can do an effective but slightly dirty trick like this.
enum MyEnum: Int {
case One
case Two
}
extension MyEnum {
func static allCases() -> [MyEnum] {
var allCases = [MyEnum]()
for i in 0..<10000 {
if let type = MyEnum(rawValue: i) {
allCases.append(type)
} else {
break
}
}
return allCases
}
}
Then loop over MyEnum.allCases()..

Implementing CollectionType in Swift with forEach giving non Optional closure variable

class SelectableArray: CollectionType, MutableCollectionType {
private var elements = Array<Element>()
convenience init(elements: [Element]) {
self.init()
self.elements = elements
}
var startIndex: Int { return elements.startIndex }
var endIndex: Int { return elements.endIndex }
subscript (index: Int) -> Element? {
get {
return elements[index]
}
set {
elements[index] = newValue!
}
}
}
The above class forEach give the following:
let a = SelectableArray<String>(elements: ["a","b"])
a.forEach { (String?) -> () in
<#code#>
}
I would like to know why the Array forEach is (String) -> Void but mine is (String?) -> Void. How can I make it to (String) -> Void?
I figure it out, subscript (index: Int) -> Element? should be subscript (index: Int) -> Element.

protocol type constraint by two protocols

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) }
}
}
}