Limits of Protocol Extensions and defaults in swift2 - swift

So I was playing around with protocol extensions and i ran into an "interesting" problem.
I wanted to write a Meters and Kilometers units type for testing some things out. Its VERY easy to do this as a class where there is a base class and both sub classes override the base, while just overriding a simple value
//Conversion factor between types
enum DISTANCE_UNIT_TYPE : Double {
case METER = 1.0;
case KILOMETER = 0.001;
}
protocol DistanceUnit {
var unitType : DISTANCE_UNIT_TYPE {get}
var value : Double { get set }
var baseValue : Double { get set }
}
struct Kilometers : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.KILOMETER
var value : Double
var baseValue : Double
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
struct Meters : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.METER
var value : Double
var baseValue : Double
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
So as you can see i have lots of duplicate code (specifically the initializers)
I tried to make a protocol extension to set the default initializer
extension DistanceUnit {
init(_ v : Double) {
value = v
baseValue = v * unitType.rawValue
}
}
but I get an error of variable 'self' passed by reference before being initalized
Is there any way to get this to work or do i just have to type lots of duplicate code? Maybe using unsafe or something?

I assume that fqdn is right and we won't be able to use custom inits inside protocols extension as we would like to, but only time will tell.
But there is still some workaround:
struct Meters : DistanceUnit {
var unitType = DISTANCE_UNIT_TYPE.METER
var value : Double
var baseValue : Double
init() { // this one is needed as designated initializer for your protocol extension
value = 0
baseValue = 0
}
}
protocol DistanceUnit {
var unitType : DISTANCE_UNIT_TYPE {get}
var value : Double { get set }
var baseValue : Double { get set }
init() // this is new and you will NEED to implement this in your structure or class
}
extension DistanceUnit {
init(_ v : Double) {
self.init()
value = v
baseValue = v * unitType.rawValue
}
// you can now implement a lot more different default inits and they should work fine here :)
// here is a quick example
init(_ s : String) {
self.init(Double(s.characters.count))
}
}
Hope that will help you. I learned this trick a few days ago when i was building a custom generic singleton generator with protocol extensions (see here).

Related

Swift, Protocols and Generics in Genetic Algorithm

I am trying to switch from Java to Swift and improve my programming skills in this language.
However, I have some difficulties understanding how generics works in Swift after a study of:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html
I have started to write a genetic algorithm by writing some protocols.
protocol Point : Equatable {
var identifier: String { get }
var x: Double { get }
var y: Double { get }
func distance<P : Point>(to point: P) -> Double
}
protocol Individual {
associatedtype P : Point
var fitness: Double { get }
var chromosomes: [P] { get }
}
and now I want to make a struct which conforms to the Individual protocol.
The only try that compiles is
struct Route : Individual {
typealias P = City;
var fitness: Double { 0.0 }
var chromosomes: [City]
}
However, I want to make Route as much as generic, therefore I don't want to tell that it uses City as implementation of Point. I want that Route knows that it works on array of objects which conforms to Point protocol.
I'd appreciate your help.
Thank you in advance.
First of all, I'd suggest adding a Self requirement on the distance(to:) method. Self just tells the compiler that the paremeter is the same type as the conforming type.
protocol Point : Equatable {
var identifier: String { get }
var x: Double { get }
var y: Double { get }
func distance(to point: Self) -> Double
}
So, in your City struct point must also be of type City.
struct City: Point {
var identifier: String
var x: Double
var y: Double
func distance(to point: City) -> Double {
return .zero
}
}
You can make your Route struct more flexible by adding a generic parameter that also satisfies the associated type requirement imposed by the Individual protocol.
struct Route<P: Point>: Individual {
var fitness: Double { 0.0 }
var chromosomes: [P]
}
To instantiate a Route:
var cityRoute = Route<City>(chromosomes: [])
You can create an array of class that implements a specific protocol, so for example in this case you will have:
struct Route: Individual {
typealias P = City;
var fitness: Double { 0.0 }
var chromosomes: [Point]
}
and you can call all the protocol methods.

How to initialize a generic inside another generic using the same type in Swift?

I am trying to use a generic struct inside another generic struct.
public protocol FloatConvertible {
init(_ other:Float)
init(_ other:Double)
init(_ x:FloatConvertible)
func _asOther<T:FloatConvertible>() -> T
}
extension FloatConvertible {
public init(_ x:FloatConvertible) {self = x._asOther()}
}
extension Float : FloatConvertible {
public func _asOther<T:FloatConvertible>() -> T {return T(self)}
}
extension Double : FloatConvertible {
public func _asOther<T:FloatConvertible>() -> T {return T(self)}
}
struct B<U> {
var multVar: U
init(multVar: U) {
self.multVar = multVar
}
}
struct A<T> {
var array = [B<T>]()
init(_ a: [T]) {
for f in a {
array.append(B<T>(multVar: f))
}
}
func printResult(){
var result: Float = 1.0
for x in array {
result = result * Float(x.multVar)
}
}
}
var array = [3.0,2.0]
var structA = A<FloatConvertible>(array)
structA.printResult()
generics.swift:37:29: error: initializer 'init(_:)' requires that 'T' conform to 'BinaryInteger'
result = result * Float(x.multVar)
^
Swift.Float:3:23: note: where 'Source' = 'T'
#inlinable public init<Source>(_ value: Source) where Source : BinaryInteger
I am getting this error.
But when I used a single variable instead of an array, type casted it to a Float and printed it, it worked.
Is this the correct way to initialise a generic struct inside another generic struct using the same type? If not, what can I do?
The actual code I'm using is below:
// struct defining a data series
public struct Series<T,U> {
public var barGraphSeriesOptions = BarGraphSeriesOptions()
public var scatterPlotSeriesOptions = ScatterPlotSeriesOptions()
public var pairs = [Pair<T,U>]()
public var scaledPairs = [Pair<T,U>]()
public var maxY: Float = 0
public var minY: Float = 0
public var label = "Plot"
public var color : Color = .blue
public var startColor: Color? = nil
public var endColor: Color? = nil
public init() {}
public init(pairs : [Pair<T,U>], label l: String, startColor : Color = .lightBlue, endColor : Color = Color.lightBlue, hatchPattern: BarGraphSeriesOptions.Hatching = .none, scatterPattern: ScatterPlotSeriesOptions.ScatterPattern = .circle){
self.pairs = pairs
label = l
self.startColor = startColor
self.endColor = endColor
barGraphSeriesOptions.hatchPattern = hatchPattern
scatterPlotSeriesOptions.scatterPattern = scatterPattern
}
public init(pairs : [Pair<T,U>], label l: String, color c: Color = Color.lightBlue, hatchPattern: BarGraphSeriesOptions.Hatching = .none, scatterPattern: ScatterPlotSeriesOptions.ScatterPattern = .circle){
self.pairs = pairs
label = l
color = c
barGraphSeriesOptions.hatchPattern = hatchPattern
scatterPlotSeriesOptions.scatterPattern = scatterPattern
}
}
The error comes from the fact that, in the implementation of A<T>, your generic parameter as no constraint, which means it could be anything (from a Float, to a custom struct/class).
This imply that you can't convert it into a Float. For example, if I create an instance of A with a custom struct, the float conversion is impossible.
struct A<T> {
var array = [B<T>]()
init(_ a: [T]) {
for f in a {
array.append(B<T>(multVar: f))
}
}
}
struct User {}
A([User(), User()]) // this is a valid initialization
But at this point, you cant just cast a User into a Float
Float(User()) // error
You can solve this either by:
adding a constraint to the generic parameter (in the A struct)
restraining the printResult() method implementation when T conforms to FloatConvertible
Constraint A<T>
struct A<T: FloatConvertible> {
var array = [B<T>]()
init(_ a: [T]) {
for f in a {
array.append(B<T>(multVar: f))
}
}
func printResult() {
var result: Float = 1.0
for x in array {
result = result * Float(x.multVar)
}
}
}
var array = [3.0, 2.0]
var structA = A(array)
structA.printResult()
Constraint printResult()
struct A<T: FloatConvertible> {
var array = [B<T>]()
init(_ a: [T]) {
for f in a {
array.append(B<T>(multVar: f))
}
}
}
extension A where T: FloatConvertible {
func printResult() {
var result: Float = 1.0
for x in array {
result = result * Float(x.multVar)
}
}
}
var array = [3.0, 2.0]
var structA = A(array)
structA.printResult()

Swift protocol property set not executed

I try to use the set method for calling a function after the value is changed.
I did not see why the set method is not called.
The code could be directly executed in playground
//: Playground - noun: a place where people can play
import UIKit
protocol RandomItem {
var range : (Int,Int) {get set}
var result : Int {get set}
init()
mutating func createRandom()
}
extension RandomItem {
var range : (Int,Int) {
get {
return range
}
set {
range = newValue
self.createRandom()
}
}
}
struct Item: RandomItem {
var range = (0,1)
var result: Int = 0
init() {
self.createRandom()
}
mutating func createRandom() {
let low = UInt32(range.0)
let high = UInt32(range.1)
result = Int(arc4random_uniform(high - low + 1) + low)
}
}
Your struct Item declares its own range property, which overrides the default you created in the protocol extension. The range property in Item has no getters or setters defined to do what your extension version does.
Another issue:
Your protocol extension defines the range property as a computed property (no storage) whose getter and setter both call itself. This will loop infinitely.
Maybe you are looking for something more like:
protocol RandomItem {
var storedRange: (Int, Int) { get }
var range : (Int,Int) {get set}
var result : Int {get set}
init()
mutating func createRandom()
}
extension RandomItem {
var range : (Int,Int) {
get {
return storedRange
}
set {
storedRange = newValue
self.createRandom()
}
}
}
struct Item: RandomItem {
var result: Int = 0
var storedRange = (0, 1)
init() {
self.createRandom()
}
mutating func createRandom() {
let low = UInt32(range.0)
let high = UInt32(range.1)
result = Int(arc4random_uniform(high - low + 1) + low)
}
}
This requires a conforming type to define a stored property storedRange, which the default implementation of the computed property range will interact with.

Swift Custom Variable Type

For working with complex numbers, this is how I've been doing it:
import Foundation
class Complex {
var real: Float
var imaginary: Float
init(re: Float, im: Float) {
self.imaginary = im
self.real = re
}
func abs() -> Float {
return sqrtf(powf(self.real, 2) + powf(self.imaginary, 2))
}
func string() -> String {
if (ceilf(self.real) == self.real) && (ceilf(self.imaginary) == self.imaginary){
return "\(Int(self.real))+\(Int(self.imaginary))i"
}
return "\(self.real)+\(self.imaginary)i"
}
func arg() -> Float {
return atan2f(self.imaginary, self.real)
}
}
var someComplex = Complex(re: 2, im: 3)
var someComplexString = someComplex.string() //"2+3i"
var someComplexAbsolute = someComplex.abs() // 3.60...
var someComplexArgument = someComplex.arg() //0.98...
Now I was wondering, if there was any way to define a custom type of variable that would let me write it as someComplex: Complex = 3i for example. Is it possible to create a new type "from the ground up"?
I'm slightly uncertain if this is what you're looking for, but based on your comment to the other answer
"Thanks, but what I meant was something like a custom type that would accept all floats and i for example",
you could create a wrapper that holds a single generic value, where the generic type of this value is type constrained to some protocol, to which you in turn extend the types you wish to be wrappable but the type. E.g., below allowing types Int, Float and String to be wrapped by the wrapper
protocol MyGenericTypes { }
extension Int: MyGenericTypes { }
extension Float: MyGenericTypes { }
extension String: MyGenericTypes { }
struct SomeWrapper<T: MyGenericTypes> {
var value: T
init(_ value: T) {
self.value = value
}
}
let myInt = 42
let myFloat: Float = 4.2
let myString = "forty-two"
let wrappedInt = SomeWrapper(myInt) // T inferred as "Int"
let wrappedFloat = SomeWrapper(myFloat) // T inferred as "Float"
let wrappedString = SomeWrapper(myString) // T ingerred as "String"
print(wrappedInt.dynamicType) // SomeWrapper<Int>
print(wrappedFloat.dynamicType) // SomeWrapper<Float>
print(wrappedString.dynamicType) // SomeWrapper<String>
You can naturally write generic functions allowing arguments for SomeWrapper<T> instances, type constraining T in the same fashion as in the struct definition above
func foo<T: MyGenericTypes>(bar: SomeWrapper<T>) -> () {
print(bar.value)
}
foo(wrappedInt) // 4.2
foo(wrappedFloat) // 42
foo(wrappedString) // forty-two

Access variable of an enum nested in struct in a protocol extension in Swift

I am implementing a converter that easily converts double type parameters of a run into proper unit according to the provided unit style, metric or imperial. Distance is entered in meters which gets converted to km or miles according to the given unit style.
enum for two states of unit style
//enum to track the states of unit style
enum UnitStyle{
case Metric, Imperial
}
protocol implemented by every parameter of the run. This requires model to implement a type called Unit because every parameter has its own type of unit. e.g. For distance it can be out of km or mi whereas for speed it can be out of km/hr or mi/hr
//every parameter of run has to implement this protocol
protocol RunParameter{
typealias Unit: RawRepresentable
var value: Double{get set}
var unit: Unit{get}
var unitStyle: UnitStyle{get set}
}
This extension does all the magic. It multiplies the value of given run parameter to its suitable unit to obtain the correct value. Everything is fine till here. Now I need to get the unit description as well here in this method so that I can return it to display on the screen. For this I created a description variable inside the enum Unit but the problem is I can not access this description variable in protocol extension. In a nutshell only rawValue variable is available on self.unit no description variable inside protocol extension.
extension RunParameter where Unit.RawValue == Double{
mutating func getValueForUnitStyle(unitStyle: UnitStyle) -> Double{
self.unitStyle = unitStyle
return value * self.unit.rawValue
//here I want to return both calculated value and unit string
//but unable to access unit description on self.unit
}
}
struct Distance: RunParameter {
enum Unit: Double {
case km = 0.001
case m = 1.0
case mi = 0.000621371
var description: String{
switch self{
case .km: return "km"
case .m: return "m"
case .mi: return "mi"
}
}
}
var value: Double
var unitStyle = UnitStyle.Metric
var unit: Unit {
get{
switch unitStyle{
case .Metric: return Unit.km
case .Imperial: return Unit.mi
}
}
}
init(value: Double){
self.value = value
}
}
struct Run {
var unitStyle = UnitStyle.Imperial
var distance = Distance(value: 10.0)
}
description variable is available here. I can access description on x.distance.unit
var x = Run()
let z = x.distance.getValueForUnitStyle(.Imperial)
x.distance.unit.description //output "mi"
enum UnitStyle{
case Metric, Imperial
}
protocol RunParameter{
typealias Unit: RawRepresentable, CustomStringConvertible
var value: Double{get set}
var unit: Unit{get}
var unitStyle: UnitStyle{get set}
}
extension RunParameter where Unit.RawValue == Double{
mutating func getValueForUnitStyle(unitStyle: UnitStyle) -> (Double,String){
self.unitStyle = unitStyle
return (value * self.unit.rawValue, self.unit.description)
//here I want to return both calculated value and unit string
//but unable to access unit description on self.unit
}
}
struct Distance: RunParameter {
enum Unit: Double, CustomStringConvertible {
case km = 0.001
case m = 1.0
case mi = 0.000621371
var description: String{
switch self{
case .km: return "km"
case .m: return "m"
case .mi: return "mi"
}
}
}
var value: Double
var unitStyle = UnitStyle.Metric
var unit: Unit {
get{
switch unitStyle{
case .Metric: return Unit.km
case .Imperial: return Unit.mi
}
}
}
init(value: Double){
self.value = value
}
}
struct Run {
var unitStyle = UnitStyle.Imperial
var distance = Distance(value: 10.0)
}
var x = Run()
let z = x.distance.getValueForUnitStyle(.Imperial)
x.distance.unit.description //output "mi"
print(z.0,z.1) // 0.00621371 mi