Initializing a variable with a function in a class - swift

I have a class sort of like the one below. It is simplified, but it illustrates my problem. I want to initialize the "number" variable with the function "square".
class SomeClass {
let number: Int
func square (num: Int) -> Int {
return num * num
}
init(num: Int) {
number = square(num)
}
}
But when i make an instance of the class. For example
let instance = SomeClass(num: 2)
it throws the error: use of 'self' in method call 'square' before all stored properties are initialized.
How can i initialize the number by using the function?

In this particular case you can use class method:
class SomeClass {
let number: Int
class func square (num: Int) -> Int {
return num * num
}
init(num: Int) {
number = SomeClass.square(num)
}
}

the only way, how to do what you want to do, is declare the number as var and initialize it with some value
class SomeClass {
var number: Int = 0
func square (num: Int) -> Int {
return num * num
}
init(num: Int) {
number = square(num)
}
}
let instance = SomeClass(num: 2)
instance.number // 4

Related

Copy constructor and "Cannot call value of non-function type" error

I have a base class A and three subclasses:
class A {}
class X : A {}
class Y : A {}
class Z : A {}
In my code, I have an instance m which I would like to create a copy of, of the same type.
I can successfully use the following code:
let n = type(of: m).init(m)
... and in class A:
required init(m : A) {
self.param1 = m.param1
I try to simplify things by creating a copy constructor in class A:
func copy() {
return type(of: self).init(self)
}
but this declaration generates the error: Cannot call value of non-function type 'AType'
Two questions: What am I doing wrong? and Is there a simpler way to create a copy constructor involving subclasses?
Try the Prototype desing pattern:
public protocol Copying: class {
init(_ prototype: Self)
}
extension Copying {
public func copy() -> Self {
return type(of: self).init(self)
}
}
public class A: Copying {
public var value1: Int
public var value2: Int
public init(value1: Int, value2: Int) {
self.value1 = value1
self.value2 = value2
}
public required convenience init(_ a: A) {
self.init(value1: a.value1, value2: a.value2)
}
}
and you can use it like:
let a = A(value1: 700, value2: 37)
let aCopy = a.copy()

Generic way to do math on protocol extensions

Goal
I want to extend basic types like Int, Double, Float... with more flexible properties and make it presentable in a chart on my app. For example, I made a chart draw that is suitable only for displaying Intbut cannot really display Float. I want to make sure when I pass arguments to this view it will display correctly.
Solution
So I made a protocol (for this example made it like this):
protocol SimplyChartable {
static func max(_ dataSet: [SimplyChartable]) -> SimplyChartable
}
And then make an extension for some types:
extension Int: SimplyChartable { }
extension Double: SimplyChartable { }
extension Float: SimplyChartable { }
and so on ...
Problem
This will be all numeric types, and whenever I pass it as numeric types to a func I need to extend all extension like this:
public static func max(_ dataSet: [SimplyChartable]) -> SimplyChartable {
return (dataSet as? [Int])?.max() ?? 0
}
But for Double func will be identical.
So for min I will end up with similar function, the same for divide, adding , some other math... There is a way to write it once and reuse for every type that extends this protocol?
I found out that:
let dataType = type(of: maxValue) /* where `maxValue` is SimplyChartable*/
Will return original type as rawValue. But output of a method type(of is a Metatype and I cannot return it from function and then add two values of this type. So for example this code will not work:
let val1 = SimplyChartable(4)
let val2 = SimplyChartable(2)
let sum = val1 + val2
And how to make it work not ending up with 3 functions like this:
let val1 = SimplyChartable(4)
let val2 = SimplyChartable(2)
let sum = (val1 as! Int) + (val2 as! Int)
Since they all numeric types why don't you use Comparable?
extension SimplyChartable {
static func max<T: Comparable>(dataSet: [T]) -> T? {
return dataSet.max()
}
static func min<T: Comparable>(dataSet: [T]) -> T? {
return dataSet.min()
}
}
extension Int: SimplyChartable { }
extension Double: SimplyChartable { }
Double.max([1.2, 1.1, 1.3]) // 1.3
Int.min([12, 11, 13]) // 11
Just my two cents worth...
This isn't exactly what you've asked for, since it doesn't let you call a static function directly from a protocol metatype. But since that, AFAIK, isn't possible in Swift currently, perhaps this would be the next best thing?
extension Sequence where Element == SimplyChartable {
func max() -> SimplyChartable {
// put your implementation here
}
}
You can then call this by just:
let arr: [SimplyChartable] = ...
let theMax = arr.max()
For your situation, it's much better to use an Array extension rather than a protocol with an array parameter.
To handle each possible type of array i.e [Int], [Double] or [Float], create a wrapper enum with associated types as follows:
public enum SimplyChartableType {
case int(Int)
case float(Float)
case double(Double)
func getValue() -> NSNumber {
switch self {
case .int(let int):
return NSNumber(value: int)
case .float(let float):
return NSNumber(value: float)
case .double(let double):
return NSNumber(value: double)
}
}
init(int: Int) {
self = SimplyChartableType.int(int)
}
init(float: Float) {
self = SimplyChartableType.float(float)
}
init(double: Double) {
self = SimplyChartableType.double(double)
}
}
You can extend Array as follows:
extension Array where Element == SimplyChartableType {
func max() -> SimplyChartableType {
switch self[0] {
case .int(_):
let arr = self.map({ $0.getValue().intValue })
return SimplyChartableType(int: arr.max()!)
case .double(_):
let arr = self.map({ $0.getValue().doubleValue })
return SimplyChartableType(double: arr.max()!)
case .float(_):
let arr = self.map({ $0.getValue().floatValue })
return SimplyChartableType(float: arr.max()!)
}
}
}
Example usage is:
var array = [SimplyChartableType.double(3),SimplyChartableType.double(2),SimplyChartableType.double(4)]
var max = array.max()
And now it's a lot easier to operate on Int, Double or Float together with:
extension SimplyChartableType: SimplyChartable {
//insert functions here
static func randomFunction() -> SimplyChartableType {
//perform logic here
}
}
The above snippet is good if you need a different functionality which operates on non-Collection types.
This doesn't answer your specific question, unfortunately. Perhaps a work around to use a free function and casting.
import UIKit
protocol SimplyChartable {
func chartableValue() -> Double
}
extension Int: SimplyChartable {
func chartableValue() -> Double {
return Double(self) ?? 0
}
}
extension Double: SimplyChartable {
func chartableValue() -> Double {
return self
}
}
extension Float: SimplyChartable {
func chartableValue() -> Double {
return Double(self) ?? 0
}
}
func maxOfSimplyChartables(_ dataSet: [SimplyChartable]) -> SimplyChartable {
return dataSet.max(by: { (lhs, rhs) -> Bool in
return lhs.chartableValue() < rhs.chartableValue()
}) ?? 0
}
let chartableItem1: SimplyChartable = 1255555.4
let chartableItem2: SimplyChartable = 24422
let chartableItem3: SimplyChartable = 35555
let simplyChartableValues = [chartableItem1, chartableItem2, chartableItem3]
maxOfSimplyChartables(simplyChartableValues)

Can I specify that a class instance can be converted to some type?

Say I have a generic class
class Foo<T> { … }
Can I somehow specify that instances of this class can be converted to T in assignments? Example:
let foo = Foo<Int>()
func useAnInt(a: Int) {}
let getTheInt: Int = foo
useAnInt(foo)
Why not just use the underlying type? (Similar to #MrBeardsley's answer)
class Foo<T> {
var t : T
init(t: T) {
self.t = t
}
}
let foo = Foo(t: 3)
func useAnInt(a: Int) {}
let getTheInt: Int = foo.t
useAnInt(foo.t)
You are not able to do what you are asking. Even though Foo defines a generic type T, instances of Foo are still Foo and cannot be converted to the generic type. The reason you would declare a generic type at the class level is to use it multiple places throughout the class.
class Foo<T> {
var value: T
init(withValue: T) {
self.value = withValue
}
func getSomeValue() -> T {
return self.value
}
}
Generics don't mean the class itself is generic and can be converted.
One way of achieving what you want is to use a dedicated protocol for each of the target types that your class shall be convertible to. Here is very basic example:
protocol BoolAdaptable {
func adaptToBool() -> Bool
}
protocol IntAdaptable {
func adaptToInt() -> Int
}
protocol FloatAdaptable {
func adaptToFloat() -> Float
}
class Foo: BoolAdaptable, IntAdaptable, FloatAdaptable {
var v: NSNumber
init(_ v: NSNumber) {
self.v = v
}
func adaptToBool() -> Bool {
return v.boolValue
}
func adaptToInt() -> Int {
return v.integerValue
}
func adaptToFloat() -> Float {
return v.floatValue
}
}
let foo = Foo(NSNumber(double: 1.23))
let getTheBool = foo.adaptToBool() // true
let getTheInt = foo.adaptToInt() // 1
let getTheFloat = foo.adaptToFloat() // 1.23
This could easily be extended to support more complex conversions.

I cannot access a function in a custom class; no matter what I try it comes up with errors

import Cocoa
public class Ut {
public func foo(m: Int) -> Int {
return m*m
}
}
class ViewController: NSViewController {
let j = 3
let k = Ut.foo(j) // 'ViewController.Type' does not have a member named 'j'
...
Unfortunately, you can’t access other properties when giving properties their initial values:
struct S {
let a = 1
// error: S.Type does not have a member named a
let b = a + 1
}
Instead, you have to initialize these values inside init:
struct S {
let a: Int
let b: Int
init() {
// note, a must be initialized in here
// too if b relies on it
a = 1
b = a + 1
}
}
(also, it looks like you’re using Ut.foo as a class-level function but it’s a member function - but this particular error is about the property init)
You have to make your foo(m: Int) as class function in order to call directly like that. Otherwise, you have to create an instance of Ut then call foo() on to this instance
class func foo(m: Int) -> Int {
return m*m
}
then in other place:
let k = Ut.foo(j)
If you pass j as parameter, this call must be placed inside a function, not at class level. If you want to call at class level, pass a value (like: let k = Ut.foo(5) )

Swift: why 'subscript(var digitIndex: Int) -> Int' is a valid function signature?

This piece of code comes from Swift documentation https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html
extension Int {
subscript(var digitIndex: Int) -> Int {
var decimalBase = 1
while digitIndex > 0 {
decimalBase *= 10
--digitIndex
}
return (self / decimalBase) % 10
}
}
Apparently var is a reserved word, so why it is legal to declare: subscript(var digitIndex: Int) -> Int?
If I change the signature to subscript(#digitIndex: Int) -> Int, I will get this compiler error:
My questions are:
1) why the signature is valid?
2) why my change causes an exception?
Declaring a function argument with var means that it can be modified, is not a constant. In your case, without using var, you had a constant argument but you attempted to decrement it. Thus the error.
Your two cases are:
func foo (x: int) { /* x is a constant, like `let x: int` */ }
func foo (var x: int) { /* x is not a constant */ }