Accept Float, Double or Int in Swift `init` to convert to String - swift

I'm attempting to convert a value to a string in an init. That value can be an Int, Double, or Float.
For example:
struct example {
var string: String
init(number: Int) {
string = String(number)
}
}
I would like to say something like below (I'm using Typescript as an example - this obviously doesn't work, but I want number to be any of those three types - all of which String can convert).
struct example {
var string: String
init(number: Int | Float | Double) {
string = String(number)
}
}
Edit: I realized I have another issue. I need to convert back from a string to the type of Int or Double or Float. Using one of the answers below, I'm trying to figure out how to implement getNumberWith5:
struct example2<N: Numeric & CustomStringConvertible>: CustomStringConvertible {
#Binding var number: N
init(number: Binding<N>) {
self._number = number
}
var description: String {
String(describing: number)
}
mutating func getNumberWith5() {
// How do I update number to the type N?
self.number = howDoIConvertToN(description + "5")
}
}
Or from another answer:
struct example3<N: Numeric> {
#Binding var number: N
var string: String
init(number: Binding<N>) {
self._number = number
self.string = "\(number)"
}
mutating func getNumberWith5() {
// How do I update number to the type N?
self.number = howDoIConvertToN(string + "5")
}
}
Edit2 My Answer:
I attempted to create an equivalent of type unions (as Typescript has) using enums in Swift based on this article. But it was challenging to then assign back to that value. I've decided Swift just doesn't have first class support for type unions like Typescript has. So, I used the accepted answer below and this seems to work.
extension String {
func numeric<N: Numeric & LosslessStringConvertible>() -> N? {
N(self)
}
}
struct example4<N: Numeric & LosslessStringConvertible> {
#State var string: String
#Binding var number: N
init(number: Binding<N>) {
self._number = number
self.string = String(describing: number)
}
mutating func getNumberWith5() {
let newString = string + "5"
number = newString.numeric() ?? 0
}
}

Actually if all you want is a string representation of Int Float Double or any other standard numeric type you only need to know that they conform to CustomStringConvertible and use String(describing:).
Or you can use conformance to Numeric and CustomStringConvertible:
struct example {
var string: String
init<C: CustomStringConvertible & Numeric>(number: C) {
string = String(describing: number)
}
}
and maybe even better example itself could conform to CustomStringConvertible
struct example: CustomStringConvertible {
var description: String
init<C: CustomStringConvertible & Numeric>(number: C) {
description = String(describing: number)
}
}
yet another way :
struct example<N: Numeric & CustomStringConvertible>: CustomStringConvertible {
let number: N
init(number: N) {
self.number = number
}
var description: String {
String(describing: number)
}
}
EDIT
I think what you want is a custom Property Wrapper not #Binding:
#propertyWrapper struct CustomStringConversion<Wrapped: CustomStringConvertible> {
var wrappedValue: Wrapped
init(wrappedValue: Wrapped) {
self.wrappedValue = wrappedValue
}
var projectedValue: String { .init(describing: wrappedValue) }
}
struct Foo {
#CustomStringConversion var number = 5
}
let foo = Foo()
let number: Int = foo.number // 5
let stringRepresentation: String = foo.$number // "5"
But as #LeoDabus pointed out using LosslessStringConvertible may be better :
struct example<N: Numeric & LosslessStringConvertible>: LosslessStringConvertible {
let number: N
init(number: N) {
self.number = number
}
init?(_ description: String) {
guard let number = N(description) else { return nil }
self.number = number
}
var description: String {
.init(number)
}
}
let bar = example(number: Double.greatestFiniteMagnitude) // 1.7976931348623157e+308
let baz: example<Double>? = example("1.7976931348623157e+308") // 1.7976931348623157e+308

Use generic structure with Numeric protocol.
struct Example<T:Numeric> {
var string: String
init(number: T) {
self.string = "\(number)"
}
}

struct Example {
var string: String
init(number: Int) {
string = String(number)
}
init(number: Float) {
string = String(number)
}
init(number: Double) {
string = String(number)
}
}

You can have a look at how swift does this with its String-initializer:
struct Example {
init<Number>(number: Number) where Number: BinaryInteger {
string = String(number)
}
}

Related

How can i disable adding new item to an array in Swift?

I have an array like this inside a struct:
struct TestType {
private(set) var array: [String] = ["0", "1", "2"]
mutating func updateItem0(_ value: String) {
self.array[0] = value
}
mutating func updateItem1(_ value: String) {
self.array[1] = value
}
mutating func updateItem2(_ value: String) {
self.array[2] = value
}
}
I want be able to disable appending method to this array when I use an instance of struct, and keeping the count of it as it is. I cannot use private(set) because it would not allow me to update items of it.
My idea is using private(set) inside struct and making a mutating function for updating items in case, I wanted to know if there is better way for it?
Lots of options but a simple enhancement would be passing the index:
mutating func update(_ value: String, at index: Int) {
array[index] = value
}
And another is to check if the operation is possible:
enum Error: Swift.Error {
case indexOutOfBound
}
mutating func update(_ value: String, at index: Int) throws {
guard array.indices.contains(index) else { throw Error.indexOutOfBound }
array[index] = value
}
Here is a nice way to handle it. Add subscript to your struct which then allows you to access and change the values like you would an array. Adopting CustomStringConvertible and implementing description allows you to print the internal array while keeping it entirely private:
struct TestType: CustomStringConvertible {
private var array: [String] = ["0", "1", "2"]
var description: String { String(describing: array) }
subscript(_ index: Int) -> String {
get {
return array[index]
}
set {
array[index] = newValue
}
}
}
var foo = TestType()
foo[0] = "hello"
foo[2] = "goodbye"
foo[3] = "oops" // Fatal error: Index out of range
print(foo[0]) // hello
print(foo[1]) // 1
print(foo[2]) // goodbye
print(foo) // ["hello", "1", "goodbye"]

How could i convert with an extension of NumberFormatter a String to a Float

I have created an extension of NumberFormatter and binaryInteger, to convert Int to String with a space between thousands like thise: 11111 -> 11 111
Now, in another place, i need to reverse the convertion from a specific string to a Float , like this: 11 111 -> 11111.
Here is the first extensions of NumberFormatter and BinaryInteger:
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = " "
formatter.allowsFloats = true
formatter.numberStyle = .decimal
return formatter
}()
}
extension BinaryInteger {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
So, how could i code an another extension, to make the reverse process?
thank you.
Try this:
extension String {
func backToFloat() -> Float {
// Make a copy of original string
var temp = self
// Remove spaces
temp.removeAll(where: { $0 == " " })
return Float(temp) ?? 0.0
}
}
print("1 234 567.2".backToFloat())
// log: 1234567.2
To enable Float -> String and Double -> String:
extension FloatingPoint {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
print(12345678.12.formattedWithSeparator)
// log: 12 345 678.12
You can use the same withSeparator formatter, and add another extension to BinaryInteger:
extension BinaryInteger {
init?(fromStringWithSeparator string: String) {
if let num = NumberFormatter.withSeparator.number(from: string)
.map({ Self.init(truncatingIfNeeded: $0.int64Value) }) {
self = num
} else {
return nil
}
}
}
Here, I basically parsed the number into an NSNumber, and then converted that to an Int64, then converted that to whatever type of BinaryInteger is required. This won't work for the values of UInt64 that are outside of the range of Int64, as the first conversion will convert them to a negative number. So if you want to handle those numbers as well, you should write another UInt64 extension:
extension UInt64 {
init?(fromStringWithSeparator string: String) {
if let num = NumberFormatter.withSeparator.number(from: string)?.uint64Value {
self = num
} else {
return nil
}
}
}

Storing Generic Objects in a Heterogeneous Array and retrieving object parameter as the correct type

Ahoy everyone,
I have recently been trying to implement a Node based graph system that passes data between nodes using plugs. Similar to many of the 3D applications like houdini and maya.
I have written a similar system before using Python, and wanted to try this with Swift as my first learning excersise. Boy did I jump into the deep end on this one.
I am stuck now with Swifts Arrays, as I would like to store a list of Generic plugs.
Each plug can have its own value type float, int, color, string, Vector Matrix.
I have read up about Type Erasers and opaque types, but still cant seem to get my values our of a list in a way that I can perform some arithmetic on them.
All and any help that might put me in the direction would be greatly appreciated :D
import Foundation
import MetalKit
protocol genericPlug {
associatedtype T
func GetValue() -> T
}
class Plug<T>:genericPlug{
var _value:T?
var value:T {
get{GetValue()}
set(val){
value = val
}
}
func GetValue() -> T{
return _value!
}
init(_ newValue:T){
_value=newValue
}
}
class Node{
var plugs:[genericPlug] = []
init(){
var p1 = Plug<Int>(0)
var p2 = Plug(vector2(1.2, 3.1))
var p3 = Plug([0.0, 3.1, 0.6, 1])
plugs.append(p1)
plugs.append(p2)
plugs.append(p3)
}
func execute(){
// will access the plugs in the array and perform some sort of calculations on them.
plugs[0].value + 1 // should equal 1
plugs[1].value.x + 0.8 // should have x=2.0 y=3.1
plugs[2].value[1] - 0.1 // should equal 3.0
}
}
Thanks everyone
Use a generic something to extract what you need. Your options are methods and subscripts.
protocol PlugValue {
init()
}
extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
struct Plug<Value: PlugValue> {
var value: Value
init(_ value: Value) {
self.value = value
}
}
protocol AnyPlug {
var anyValue: PlugValue { get }
}
extension AnyPlug {
subscript<Value: PlugValue>(type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
}
extension Plug: AnyPlug {
var anyValue: PlugValue { value }
}
let plugs: [AnyPlug] = [
Plug(1),
Plug(2.3 as Float),
Plug(4.5),
Plug([6, 7, 8] as SIMD3)
]
plugs[0][Int.self] // 1
plugs[1][Double.self] // 0
plugs[1][] as Float // 2.3
let double: Double = plugs[2]() // 4.5
plugs[3](SIMD3.self).y // 7
With the array of protocols, do you have to down cast them into their Plug when retrieving them every time?
Essentially. This is true of all heterogenous sequences. Here are your options:
extension Array: PlugValue where Element: PlugValue { }
let plug: AnyPlug = Plug([0.1, 1.1, 2.1])
(plug as? Plug<[Double]>)?.value[1]
(plug.anyValue as? [Double])?[1]
extension Plug {
enum Error: Swift.Error {
case typeMismatch
}
}
extension AnyPlug {
func callAsFunction<Value: PlugValue, Return>(_ closure: (Value) -> Return) throws {
guard let value = anyValue as? Value
else { throw Plug<Value>.Error.typeMismatch }
closure(value)
}
}
try plug { (doubles: [Double]) in doubles[1] } // 1.1
try plug { ($0 as [Double])[1] } // 1.1
try plug { $0 as Int } // <Swift.Int>.Error.typeMismatch
I managed to find a solution that worked for my needs.
I am still looking at finding a better way to handle getting the data and their correct type.
import Foundation
import MetalKit
// Creating the PlugType Enum
enum PlugType{
case Integer(Int?)
case Float_(Float?)
case Double_(Double?)
case Vector3(simd_int3)
// default types
static func IntegerType() -> PlugType{ return PlugType.Integer(nil)}
static func FloatType() -> PlugType{ return PlugType.Float_(nil)}
static func DoubleType() -> PlugType{ return PlugType.Double_(nil)}
}
// Implements a way to retrieve the correct value type
extension PlugType{
var IntegerValue: Int{
switch self{
case .Integer(let value):
return value ?? 0
default:
return 0
}
}
var FloatValue: Float{
switch self
{
case .Float_(let value):
return value ?? 0
default:
return 0
}
}
var DoubleValue: Double{
switch self
{
case .Double_(let value):
return value ?? 0
default:
return 0
}
}
}
// Get the string representation of the PlugType
extension PlugType {
var typeName: String{
switch self {
case .Integer: return "Integer"
case .Float_: return "Float"
case .Double_: return "Double"
case .Vector3: return "Vector3"
}
}
var swiftType: Any.Type {
switch self {
case .Integer: return Int.self
case .Float_: return Float.self
case .Double_: return Double.self
case .Vector3: return simd_int3.self
}
}
}
class Plug{
var _value:PlugType?
var type:String? { get{ return _value?.typeName } }
init(_ newValue:PlugType){
_value = newValue
}
func geee<T>(_ input:T) -> T{
switch type {
case "Integer":
return getVal(_value!.IntegerValue) as! T
case "Double":
return getVal(_value!.DoubleValue) as! T
default:
return 0 as! T
}
}
func getVal(_ val:Int) -> Int {
return val
}
func getVal(_ val:Float) -> Float {
return val
}
func getVal(_ val:Double) -> Double {
return val
}
}
var plugs:[Plug] = []
var p1 = Plug(PlugType.Integer(2))

Swift Dictionary Initialization of custom type gives: '>' is not a postfix unary operator error

I am trying to initialise a empty dictionary with custom type in Swift but I am getting '>' is not a postfix unary operator error
struct Prims {
var msSet = [Vertex<Int> : Double]() // This lines gives error
}
I tried another way; still getting same error
struct Prims {
var msSet: [Vertex<Int> : Double]
init() {
self.msSet = [Vertex<Int> : Double]()
}
}
I have defined Vertex in separate file
import Foundation
public struct Vertex<T: Hashable> {
var data: T
}
extension Vertex: Hashable {
public var hashValue: Int {
return "\(data)".hashValue
}
static public func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return lhs.data == rhs.data
}
}
extension Vertex: CustomStringConvertible {
public var description: String {
return "\(data)"
}
}
I am looking for Why it is happening. I know using var msSet = Dictionary<Vertex<Int>, Double>() will work.
While I can't tell you why the swift compiler emits this error, you can make it compile like this:
struct Prims {
var msSet = Dictionary<Vertex<Int>, Double>()
}
or like this:
struct Prims {
typealias V = Vertex<Int>
var msSet = [V : Double]()
}
There are multiple ways of going about this:
msSet = Dictionary< Vertex<Int>, Double >()
or
mSet = [ (Vertex<Int>), Double ]()
or even more verbose
typealias VertexInt=Vertex<Int>
mSet = [ VertexInt, Double ]
I looked over the swift grammar and couldn't find an answer as to why that particular syntax is not valid. It may very well be a bug.
struct Prims {
var msSet = [Vertex<Int> : Double]() // This lines gives error
}
change to
struct Prims {
var msSet = [(Vertex<Int>) : Double]() // This lines gives error
}
complete code
struct Prims {
var msSet = [(Vertex<Int>) : Double]()
}
public struct Vertex<T: Hashable> {
var data: T
}
extension Vertex: Hashable {
public var hashValue: Int {
return data.hashValue
}
static public func ==(lhs: Vertex, rhs: Vertex) -> Bool {
return lhs.data == rhs.data
}
}
extension Vertex: CustomStringConvertible {
public var description: String {
return "\(data)"
}
}
test Code
var test = Prims()
test.msSet.updateValue(43, forKey: Vertex(data: 12))

Swift: The proper way to initialize model class with a lot of properties

How do you initialize your classes/structs with a lot of properties?
This question could probably be asked without Swift context but Swift brings a flavour to it, so I add Swift tag in headline and tags.
Let's say you have a User class with 20 properties. Most of them should not be nil or empty. Let's assume these properties are not interdependent. Let's assume that 33% of it should be constant (let) by the logic of the class. Let's assume that at least 65% of them do not have meaningful default values. How would you design this class and initialize an instance of it?
So far I have few thoughts but none of it seems to be completely satisfactory to me:
put all of the properties linearly in the class and make huge init method:
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date
var lastPlayDate : Date
// then HUUUUGE init
init(id: String,
username: String,
...
lastPlayDate: Date) {
}
}
try to group properties into sub types and deal with smaller inits separately
class User {
struct ID {
let id : String
let username : String
let email : String
}
struct Activity {
var lastLoginDate : Date
var lastPlayDate : Date
}
let id : ID
...
var lastActivity : Activity
// then not so huge init
init(id: ID,
...
lastActivity: Activity) {
}
}
another solution is to break requirements a bit: either declare some of the properties optional and set values after init or declare dummy default values and set normal values after init, which conceptually seems to be the same
class User {
// there is 20 properties like that
let id : String
let username : String
let email : String
...
var lastLoginDate : Date?
var lastPlayDate : Date?
// then not so huge init
init(id: String,
username: String,
email: String) {
}
}
// In other code
var user = User(id: "1", username: "user", email: "user#example.com"
user.lastLoginDate = Date()
Is there a nice paradigm/pattern how to deal with such situations?
You can try the builder pattern.
Example
class DeathStarBuilder {
var x: Double?
var y: Double?
var z: Double?
typealias BuilderClosure = (DeathStarBuilder) -> ()
init(buildClosure: BuilderClosure) {
buildClosure(self)
}
}
struct DeathStar : CustomStringConvertible {
let x: Double
let y: Double
let z: Double
init?(builder: DeathStarBuilder) {
if let x = builder.x, let y = builder.y, let z = builder.z {
self.x = x
self.y = y
self.z = z
} else {
return nil
}
}
var description:String {
return "Death Star at (x:\(x) y:\(y) z:\(z))"
}
}
let empire = DeathStarBuilder { builder in
builder.x = 0.1
builder.y = 0.2
builder.z = 0.3
}
let deathStar = DeathStar(builder:empire)
Example taken from here: https://github.com/ochococo/Design-Patterns-In-Swift
If you are looking for a bit more Java like solution, you can try something like this.
Alternative Example
final class NutritionFacts {
private let servingSize: Int
private let servings: Int
private let calories: Int
private let fat: Int
private let sodium: Int
private let carbs: Int
init(builder: Builder) {
servingSize = builder.servingSize
servings = builder.servings
calories = builder.calories
fat = builder.fat
sodium = builder.sodium
carbs = builder.carbs
}
class Builder {
let servingSize: Int
let servings: Int
private(set) var calories = 0
private(set) var fat = 0
private(set) var carbs = 0
private(set) var sodium = 0
init(servingSize: Int, servings: Int) {
self.servingSize = servingSize
self.servings = servings
}
func calories(value: Int) -> Builder {
calories = value
return self
}
func fat(value: Int) -> Builder {
fat = value
return self
}
func carbs(value: Int) -> Builder {
carbs = value
return self
}
func sodium(value: Int) -> Builder {
sodium = value
return self
}
func build() -> NutritionFacts {
return NutritionFacts(builder: self)
}
}
}
let facts = NutritionFacts.Builder(servingSize: 10, servings: 1)
.calories(value: 20)
.carbs(value: 2)
.fat(value: 5)
.build()
Example taken from: http://ctarda.com/2017/09/elegant-swift-default-parameters-vs-the-builder-pattern