Best way to test mutual membership for set of enums - swift

Is there a good way to group different enums into sets to test for mutual membership, without resorting to a lot of code duplication?
For example, below, when I get a .coldBeverage I get [.cola, .milk, .wine] , and likewise if I get either .cola, .milk, or .wine I get .coldBeverage.
enum BeverageType {
case coldBeverage
case hotBeverage
}
enum Beverage {
case cola
case milk
case wine
case coffee
case tea
case hotChocolate
}
Of course, I could always create a var on each enum, and enter the reciprocal relationship for each type. Was just curious if there was some other structure.
i.e.
extension BeverageType {
var associatedBeverages: [Beverage] {
switch self {
case .coldBeverage:
return [.cola, .milk, .wine]
case .hotBeverage:
return [.coffee, .tea, .hotChocolate]
}
}
}
extension Beverage {
var beverageType: BeverageType {
switch self:
case .cola:
return .coldBeverage
case .milk:
return .coldBeverage
//etc...
}
}

You could avoid the duplication using a static dictionary in one of the enums:
extension BeverageType
{
var associatedBeverages:[Beverage] { return Beverage.associatedBeverages[self]! }
}
extension Beverage
{
var beverageType:BeverageType { return Beverage.beverageTypes[self]! }
static var beverageTypes:[Beverage:BeverageType]
= [
.cola : .coldBeverage,
.milk : .coldBeverage,
.wine : .coldBeverage,
.coffee : .hotBeverage,
.tea : .hotBeverage,
.hotChocolate : .hotBeverage
]
static var associatedBeverages:[BeverageType:[Beverage]] =
{
var beveragesByType:[BeverageType:[Beverage]] = [:]
Beverage.beverageTypes.forEach
{beveragesByType[$0.1] = (beveragesByType[$0.1] ?? []) + [$0.0]}
return beveragesByType
}()
}
This approach does not require duplicating the list of enum entries (in addition to the mapping, which you have to do somewhere). It is also more efficient than a sequential search which could become significant for large or frequently used enums.
The static variables are evaluated only once, so from the second use onward, you benefit from the O(1) performance of dictionaries in both direction of the relationship.
Note that you could build the dictionaries the other way around (i.e. from [BeverageType:[Beverage]] to [Beverage:BeverageType]) and you could also place the static variables in each enum or all in the BeverageType enum.
I felt that beverages should know their BeverageType and are more likely to be expanded to new drinks so I chose to define the relationship in that (many to one) direction.
This could even be generalized further by defining a bidirectional Dictionary (generic) class to use in these situations so that the boiler plate code for the inverted dictionary doesn't pollute the extension.
[EDIT] With a bidirectional dictionary for the relation, the definition becomes even cleaner:
extension BeverageType
{
var associatedBeverages:[Beverage] { return Beverage.beverageTypes[self] }
}
extension Beverage
{
var beverageType:BeverageType { return Beverage.beverageTypes[self]! }
static var beverageTypes = ManyToOne<Beverage,BeverageType>(
[
.coldBeverage : [.cola, .milk, .wine],
.hotBeverage : [.coffee, .tea, .hotChocolate]
])
}
struct ManyToOne<M:Hashable,O:Hashable>
{
var manyToOne:[M:O] = [:]
var oneToMany:[O:[M]] = [:]
init( _ m2o:[M:O] )
{
manyToOne = m2o
for (many,one) in m2o { oneToMany[one] = (oneToMany[one] ?? []) + [many] }
}
init( _ o2m:[O:[M]])
{
oneToMany = o2m
for (one,many) in o2m { many.forEach{ manyToOne[$0] = one } }
}
subscript(many:M) -> O? { return manyToOne[many] }
subscript(one:O) -> [M] { return oneToMany[one] ?? [] }
}

You can use one membership to define the other:
extension Beverage {
static var beverages: [Beverage] {
return [.cola, .milk, .wine, .coffee, .tea, .hotChocolate]
}
var type: BeverageType {
switch self {
case .cola, .milk, .wine:
return .coldBeverage
case .coffee, .tea, .hotChocolate:
return .hotBeverage
}
}
}
extension BeverageType {
var associatedBeverages: [Beverage] {
return Beverage.beverages.filter { $0.type == self }
}
}

Related

why cant i return opaque types in my swift code? i am already returning a type conforming to that protocol [duplicate]

This question already has answers here:
What is the "some" keyword in Swift(UI)?
(14 answers)
Closed 1 year ago.
image
As showing in the image, i'm already using types such as MilkChocolate which conforms to the "Chocolate" protocal, and im trying to declare a function which returns a "some chocolate", which means return a type of chocolate depends on the input, but it gives me an error says
Function declares an opaque return type, but the return statements in its body do not have matching underlying types
this confused me by a lot and i think MiklChocolate is an underlying type for the Chocolate protocol
whats wrong?🤔
and my code should match this tutorial: https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html
PS: if you cant view the image, here's the code
protocol Chocolate {
associatedtype Content
var mass:Double {get}
}
struct Honey {}
struct Milk {}
struct Wine {}
class HoneyChocolate: Chocolate {
typealias Content = Honey
var mass = 1.0
}
class MilkChocolate: Chocolate {
typealias Content = Milk
var mass = 1.2
var mysteriousEffect = true
}
class WineChocolate: Chocolate {
typealias Content = Wine
var mass:Double = 999
}
func giveMeChocolate(of type:String) -> some Chocolate {
switch type {
case "honey":
return HoneyChocolate()
case "milk":
return MilkChocolate()
default:
return WineChocolate()
}
}
The problem occurs because Swift can't return different types of generic types. HoneyChocolate and WineChocolate are different types and that causes an issue.
A different way of achieving your goal is to return a class type of Chocolate.
First let's declare our enum flavors:
enum Flavor {
case Honey, Milk, Wine
}
then we will declare the superclass Chocolate:
class Chocolate {
var flavor: Flavor
var mass:Double
init(_ flavor: Flavor ,_ mass: Double) {
self.flavor = flavor
self.mass = mass
}
}
Now we can inherit this class:
class HoneyChocolate: Chocolate {
init() {
super.init(Flavor.Honey, 1.0)
}
}
class MilkChocolate: Chocolate {
init() {
super.init( Flavor.Milk, 1.2)
var mysteriousEffect = true
}
}
class WineChocolate: Chocolate {
init() {
super.init( Flavor.Wine, 999)
var mysteriousEffect = true
}
}
finally we can return our chocolates:
func giveMeChocolate(of type:Flavor) -> Chocolate {
switch type {
case Flavor.Honey:
return HoneyChocolate()
case Flavor.Milk:
return MilkChocolate()
default:
return WineChocolate()
}
}
Why some doesn't work
some allows you to return a generic type like and ONLY one type.
for example:
let's make a CandyChocolate class:
class CandyChocolate: Chocolate {
typealias Content = Candy
var mass = 1.0
var sweetness
init(sweetness: int) {
self.sweetness = sweetness
}
}
Now to return a some Chocolate we are allowed to return exactly one type of chocolate:
func giveMeChocolate(of type:String) -> some Chocolate {
switch type {
case "honey":
return CandyChocolate(sweetness: 5)
case "milk":
return CandyChocolate(sweetness: 3)
default:
return CandyChocolate(sweetness: 8)
}
}

Kotlin enum classes in Swift

I would like to use this Kotiln code in Swift, but I don't know how to get the best and clean solution:
enum class ProType(val gCode: String, val cCode: String) {
FUND("FN", "PP"),
STOCK("VA", "")
}
Technically #esemusa answer is right. But if you have more than ~5 values in enum, you end up with difficult to maintain giant switch statements for every property.
So for cases like that I prefer to do this:
struct ProTypeItem {
var gCode: String
var cCode: String
}
struct ProType {
static let fund = ProTypeItem(gCode: "FN", cCode: "PP")
static let stock = ProTypeItem(gCode: "VA", cCode: "")
}
And you use it simply as ProType.stock, ProType.fund.gCode etc
You can also make ProTypeItem Comparable, Equatable etc.
should be like this:
enum ProType {
case fund
case stock
var gCode: String {
switch self {
case .fund:
return "FN"
case .stock:
return "VA"
}
}
var cCode: String {
switch self {
case .fund:
return "PP"
case .stock:
return ""
}
}
}

Swift Collection conformance default

In my app I've some objects that conform to Collection. I do this because then I get the for-loop syntax and all the filter/map/etc methods for free. But I noticed it is always to same. I've got an private array and I just forward the calls. So I thought I would wrap Collection protocol in another protocol like so:
protocol CollectionTrait: Collection {
associatedtype CollectionType: Collection
var _items: CollectionType { get }
}
extension CollectionTrait {
var startIndex: CollectionType.Index {
return _items.startIndex
}
var endIndex: CollectionType.Index {
return _items.endIndex
}
func index(after i: CollectionType.Index) -> CollectionType.Index {
return _items.index(after: i)
}
subscript(index: CollectionType.Index) -> CollectionType.Element {
get {
return _items[index]
}
}
}
And this can be used as follows:
class Words: CollectionTrait {
let _items = [
"foo", "bar", "baz"
]
}
let words = Words()
for word in words {
print(word)
}
I feel like this is great, only problem I have now is that _items needs to be public, but I kinda want it to be private since I preferable don't wanna expose it. So for now I prefixed it with an underscore, to show it shouldn't be used. Does anybody know a way to force this behaviour? Or just in general a better way to avoid code duplication without inheritance (is not always possible in my case)
If you're fine with splitting your code up into multiple files, you can define CollectionTrait as a private protocol and conform to it with fileprivate. If, in one file, you have:
private protocol CollectionTrait: Collection {
associatedtype CollectionType: Collection
var _items: CollectionType { get }
}
extension CollectionTrait {
var startIndex: CollectionType.Index {
return _items.startIndex
}
var endIndex: CollectionType.Index {
return _items.endIndex
}
func index(after i: CollectionType.Index) -> CollectionType.Index {
return _items.index(after: i)
}
subscript(index: CollectionType.Index) -> CollectionType.Element {
get {
return _items[index]
}
}
}
class Words: CollectionTrait {
fileprivate let _items = [
"foo", "bar", "baz"
]
}
In another file, if you try to use Words you can:
let words = Words()
for word in words {
print(word)
}
But trying to access words._items directly would be an error, since it's fileprivate.

Multiple index types in Swift

In Swift (a language I'm still fairly new to), I'm trying to define a class that allows indexing using either an Int or Range<Int>. For example:
var m = Matrix(rows: 10, cols: 10)
var v = m[1, 0..<10]
The two ways I can think of allowing this issue is to either adding an extension to the Range class:
extension Range {
init(_ intValue:Element) {
self.init(start: intValue, end: intValue.successor())
}
}
or to create an enum that allows for either type:
enum IndexType {
case value(Int)
case range(Range<Int>)
init(_ v:Int) {
self = .value(v)
}
init(_ r:Range<Int>) {
self = .range(r)
}
}
However, neither solution works as intended, as I still need to specify the type manually. For example, given the function:
func slice(indices:IndexType...) -> [Double] {
// ...
}
I can't then just do:
slice(1, 3...4, 5)
but instead have to do:
slice(IndexType(1), IndexType(3...4), 5)
Is there a way to accomplish this in Swift? I'm used to c++, which would do type inference automatically, but the same doesn't appear to work with Swift.
One similar question I found was:
Swift Arrays of Multiple Types
However, I really would like to avoid the use of Any as I know the two types it should be.
protocol MatrixIndex {
var Matrix_range: Range<Int> { get }
}
extension Int : MatrixIndex {
var Matrix_range: Range<Int> {
get {
return Range<Int>(start: self, end: self+1)
}
}
}
extension Range : MatrixIndex {
var Matrix_range: Range<Int> {
get {
return Range<Int>(start: self.startIndex as! Int, end: self.endIndex as! Int)
}
}
}
class Matrix {
subscript(row: MatrixIndex, column: MatrixIndex) -> () {
get {
print("getting \(row.Matrix_range) \(column.Matrix_range)")
}
set(newValue) {
print("setting \(row.Matrix_range) \(column.Matrix_range)")
}
}
}

Can I group two functions with Generics into one function in Swift?

I have two bellow functions with Generics.
func objectFunc<T:SomeProtocol>(obj:T)
func arrayFunc<T:SomeProtocol>(obj:[T])
Can I group these functions into one function?
I found the link Checking if an object is a given type in Swift, but this is a little different.
Added.
For example, I want to do like bellow.
func objectAndArrayFunc<T>(arg:T, someEnum:SomeEnum){
switch someEnum {
case A:
// something
case B:
// something
}
if let items = arg as? [T] {
for item in items {
// something
}
} else if let item = arg as? T {
// something
}
// I want to do something [T] and T common processing
}
enum SomeEnum {
case A
case B
}
Also, SomeEnum count might increase.
Generally speaking, depends on what // something is. There are many ways ...
Private common processor
protocol Property {
var name: String{ get }
}
enum SomeEnum {
case A, B
}
func process<T:Property>(object:T, someEnum:SomeEnum) {
process(object, nil, someEnum)
}
func process<T:Property>(objects:[T], someEnum:SomeEnum) {
process(nil, objects, someEnum)
}
private func process<T:Property>(object: T?, objects:[T]?, someEnum:SomeEnum) {
switch someEnum {
case .A:
// something
break
case .B:
// something
break
}
// holds all items for common processing
var itemsToProcess: [T] = []
if let items = objects {
// process items
itemsToProcess = items
for item in items {
println("\(item.name)")
}
} else if let item = object {
// process single item
itemsToProcess = [item]
println("\(item.name)")
}
// iterate over single/all items and process them
for item in itemsToProcess {
println("\(item.name)")
}
}
Wrap it to Enum
protocol Property {
var name: String{ get }
}
enum SomeEnum {
case A, B
}
enum Objects<T> {
case Single(T)
case Multiple([T])
}
private func process<T:Property>(objects: Objects<T>, someEnum:SomeEnum) {
switch someEnum {
case .A:
// something
break
case .B:
// something
break
}
// holds all items for common processing
var itemsToProcess: [T] = []
switch objects {
case .Multiple(let items):
// process items
itemsToProcess = items
for item in items {
println("\(item.name)")
}
case .Single(let item):
// process single item
itemsToProcess = [item]
println("\(item.name)")
}
// iterate over single/all items and process them
for item in itemsToProcess {
println("\(item.name)")
}
}
struct Prop: Property {
var name: String {
return "hi"
}
}
let prop = Prop()
process(.Single(prop), .A)
process(.Multiple([prop]), .B)
Unfortunately, the 2nd example segfaults Swift 1.2 compiler.
Anyway, it really depends on what your goal is. Why you do not want pass even single item as [T], ...
To answer your question - no, you can't pass T or [T] in one argument, different types. Unless you wrap it to Enum or whatever, unless you do want to use AnyObject and make as dances, ...