Functions, Structs and Value Semantics in Swift - swift

If a struct has a function which contains an object, does the struct retain value semantics? Example:
struct MyStruct {
var x = 3
func setX() {
let y = NSNumber(value: 2)
x = y.intValue
}
}
The struct doesn't have any members with reference so it should have value semantics. Does the fact that the function setX() has a reference member y cause MyStruct to use reference semantics?

Structs with mutating functions retain the same value semantics as any other structs.
Calling setX would mutate the instance it was called on, but NOT any other instances, as they would be distinct copied instances, and not a shared instance (as with reference types).
You can see for yourself in this example:
struct Counter {
var count: Int
mutating func increment() {
count += 1
}
}
var x = Counter(count: 0)
let y = x // a copy is made
print("x: \(x)") // x: Counter(count: 0)
print("y: \(y)") // y: Counter(count: 0)
x.increment()
print("x: \(x)") // x: Counter(count: 1), method target affected
print("y: \(y)") // y: Counter(count: 0), copy unaffected

Related

Value-binding pattern with Swift structs

As the Programming Swift book describes, tuples can be destructured either in the assignment or by value-binding in a switch
let point = (3, 2)
switch point {
case let (x, y):
print("The point is at (\(x), \(y)).")
}
let (a, b) = point
print("The point is at (\(a), \(b)).")
I can't find any mention of how to do the equivalent for structs. For example:
struct S {
let a, b: Int
}
let s = S(a: 1, b: 2)
// This doesn't work:
// let (sa, sb): s
//
// Outputs: error: expression type 'S' is ambiguous without more context
// let (sa, sb) = s
// ^
This doesn't exist as such in the language.
One option is a helper computed property:
struct S {
let i: Int
let b: Bool
}
extension S {
var destructured: (Int, Bool) {
return (self.i, self.b)
}
}
let s = S(i: 10, b: false)
let (i, b) = s.destructured
Of course, you have to manually keep that in sync. Possibly Sourcery could assist with that.
Structs cannot be destructured in Swift.
Your tuple, point = (3, 2), is of type (Int, Int), which is part of why you are able to destructure it.
The type of your struct, S, is just S. Its variables, a and b, are not included in its type in the same literal way as they are for a tuple. A struct is simply a completely different kind of object, and this behavior does not exist for it.

Getting the initialiser values in Swift 3

Essentially I am creating a new data type called Vector3.
class Vector3 {
var x:Int
var y:Int
var z:Int
init(x:Int,y:Int,z:Int) {
self.x = x
self.y = y
self.z = z
}
}
I used the operator overloading feature in Swift in order to use operators on my custom data types.
infix operator +
func +(left:Vector3,right:Vector3) -> Vector3 {
return (Vector3(x: left.x + right.x, y: left.y + right.y, z: left.z + right.z))
}
var customVector = Vector3(x: 1, y: 2, z: 3)
var secondVector = Vector3(x: 3, y: 2, z: 1)
print(customVector + secondVector) //Take note
Currently the console is printing like this:
Vector3
Without the initialisation values, only with the class name.
However, WHAT I WANT is to print something like this:
Vector3(x:4,y:4,z:4)
Hopefully,someone can help me with this! Thanks!
NOTE:I am fully aware that one can get the values of these properties by:
customVector.x //1
customVector.y //2
Currently the console is printing like this: Vector3 without the initialisation values, only with the class name.
This is because you did not tell Swift how exactly you want your instances printed when you interpret them as strings. Make your class conformant to CustomStringConvertible protocol and implement description to print what you need:
class Vector3 : CustomStringConvertible {
...
public var description: String {
return "Vector3(x:\(x),y:\(y),z:\(z))"
}
}

Providing specialized initializers for a generic struct

I have a simple generic struct defined - its only requirements is that its stored properties be Comparable:
struct Bounds<A: Comparable> {
let lower: A
let upper: A
}
However, I'd like to provide a couple of specialized initializers for the struct, which would use some math operations to set up the properties.
init(value: Double, tolerance: Percentage) {
self.lower = value * ( 1 - tolerance )
self.upper = value * ( 1 + tolerance )
}
init(value: Measurement, tolerance: Percentage) {
self.lower = value.value * ( 1 - tolerance )
self.lower = value.value * ( 1 - tolerance )
}
The result should obviously be two different structs, where A is a Double or a Measurement.
But how do I do this?
I can't provide specialized init methods in the definition as the compiler will complain that Double is not convertible to A. OK...
I can't provide the init methods in individual extensions constrained by specific types (where A == Double) as the compiler complains:
Same-type requirement makes generic parameter 'A' non-generic
Maybe I should be using a protocol to which both Double and Measurement conform in initialization, but that seems odd, since the Bounds struct should just care that they both conform to Comparable.
I feel like I'm either missing something really simple, or trying to do something really misguided with generics. Which is it, SO?
Not exactly what you are asking for, but a possible workaround (Swift 3):
extension Bounds where A: FloatingPoint {
init(value: A, tolerance: A) {
self.lower = value * ( A(1) - tolerance )
self.upper = value * ( A(1) + tolerance )
}
}
let b = Bounds(value: 4.0, tolerance: 0.1)
print(b.dynamicType) // Bounds<Double>
You could restrict your generic more strongly, to access in-protocol blueprinted methods for transforming e.g. a Double value to the type of the generic.
protocol FromDoubleTransformable {
static func doubleToSelf(from: Double) -> Self
}
/* drawback: only types conforming to 'FromDoubleTransformable'
will be able to be used as generic in 'Bounds' below */
extension Int: FromDoubleTransformable {
static func doubleToSelf(from: Double) -> Int {
// simple example without any out-of-bounds checking
return Int(from)
}
}
struct Bounds<A: protocol<Comparable, FromDoubleTransformable>> {
let lower: A
let upper: A
init(value: Double, tolerance: Double) {
self.lower = A.doubleToSelf(value * ( 1 - tolerance ))
self.upper = A.doubleToSelf(value * ( 1 + tolerance ))
}
}
let foo = Bounds<Int>(value: 120, tolerance: 0.1)
print(foo.dynamicType) // Bounds<Int>
print(foo.lower, foo.upper) // 108 132
The main problem is that you are performing operations on types where that operations have not been defined.
E.g.
value * ( 1 - tolerance )
The operation - between Int and Tolerance where is defined?
This is how you can fix it
protocol BoundsType: Comparable {
func *(lhs: Self, rhs: Self) -> Self
var prev: Self { get }
var next: Self { get }
init(double: Double)
init<M:Measurement>(measurement:M)
}
protocol Percentage {
associatedtype BoundsType
var toBoundsType: BoundsType { get }
}
protocol Measurement {
associatedtype BoundsType
var toBoundsType: BoundsType { get }
}
struct Bounds<A: BoundsType, P:Percentage, M:Measurement
where P.BoundsType == A, M.BoundsType == A> {
let lower: A
let upper: A
init(value: Double, tolerance: P) {
self.lower = A(double:value) * (tolerance.toBoundsType.prev)
self.upper = A(double:value) * (tolerance.toBoundsType.next)
}
init(value: M, tolerance: P) {
self.lower = A(measurement:value) * tolerance.toBoundsType.prev
self.upper = A(measurement:value) * tolerance.toBoundsType.next
}
}
The correct answer to this is Martin R.'s "workaround." The issue here is that Comparable does not have any of these math operations defined on it, or even any guarantee that it is a numeric type at all. It could just as easily be a string, or an array, or any other type that implements Comparable.
So, yes, you must write extensions constrained to either a common protocol that implements these operators or to the concrete types in question. For example:
extension Bounds where A: FloatingPoint {
init(value: A, tolerance: Percentage) {
self.lower = value * ( 1 - tolerance )
self.upper = value * ( 1 + tolerance )
}
}
Or, if Measurement does not conform to FloatingPoint:
extension Bounds where A == Measurement {
init(value: A, tolerance: Percentage) {
self.lower = value.value * ( 1 - tolerance )
self.upper = value.value * ( 1 + tolerance )
}
}
Also, since you probably don't want to use any non-numeric types for your bounds then I would define it as something along these lines:
struct Bounds<A: Numeric & Comparable> {
let upper: A
let lower: A
}

In Swift why is it that structures declared as constants are unable to update variable properties?

If you have a Structure with variable properties and you set an instance of that Structure to a constant, you can not update its variable properties whereas if you have a Class with variable properties and set an instance of that Class to a constant, you can update its variable properties:
struct StructPoint {
var x: Int
var y: Int
}
class ClassPoint {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
var s = StructPoint(x: 2, y: 3)
let s2 = StructPoint(x: 2, y: 3)
s.x = 3 // allowed
s2.x = 5 // not allowed
var p = ClassPoint(x: 2, y: 3)
let p2 = ClassPoint(x: 2, y: 3)
p.x = 4 // allowed
p2.x = 4 // allowed
Why is this the case? I suspect it has something to do with Classes being a reference type and Structures being a value type, but I'm not sure.
You are correct, this behavior is the result of Classes being reference types and Structures being value types.
The section on Classes as Reference Types explains it with a simple example:
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
Note that tenEighty and alsoTenEighty are declared as constants,
rather than variables. However, you can still change
tenEighty.frameRate and alsoTenEighty.frameRate because the values of
the tenEighty and alsoTenEighty constants themselves do not actually
change. tenEighty and alsoTenEighty themselves do not “store” the
VideoMode instance—instead, they both refer to a VideoMode instance
behind the scenes. It is the frameRate property of the underlying
VideoMode that is changed, not the values of the constant references
to that VideoMode.
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-ID89
Here are a few other good resources to explain reference versus value types from other languages. Even though they are not specifically about Swift, the same concepts apply:
Joseph Albahari's explanation of value vs. reference types in C#
Jon Skeet's explanation of references and values in .NET

Why do I keep getting "Extra Argument in Call" for my initializer in Swift

I keep getting the error "extra argument in call" for repeatedValue in the init function. Why?
class Point<T> {
/* n dimensional point
multiline comments ...
*/
let point : [T]
init(dimensions: Int, rValue: Float = 0.0){
self.point = [T](count: dimensions, repeatedValue:rValue)
}
}
The definition for init with repeatedValue is
Array<T> init(count: Int, repeatedValue: T)
Your rValue must be of type T
If you need the default value your T has also to be a FloatLiteralConvertible,
this:
Array<T> init(count: Int, repeatedValue: T)
won't do it. This however will work and makes more sense since you don`t want points made out of for example "Cats" i guess...
Solution:
class Point<T:FloatLiteralConvertible> {
/* n dimensional point
multiline comments ...
*/
let point : [T]
init(dimensions: Int, rValue: T = 0.0 ){
self.point = [T](count: dimensions, repeatedValue:rValue)
}
}
var pd = Point<Double>(dimensions: 10, rValue: 1.0)
var pf = Point<Float>(dimensions: 10, rValue: 1.0)
dump(pd.point)
dump(pf.point)