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))"
}
}
Related
I have class that have two similar looking initializers:
public init(
contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
midToLeftSpacing: CGFloat = 0,
rightToMidSpacing: CGFloat = 0
)
public init(
contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6),
midToLeftSpacing: MyInsetLevel = .level0,
rightToMidSpacing: MyInsetLevel = .level0
)
Now i run into problem, looks like when i trying to call initializer compiler can't figure out which one to chose:
init(
vertical: .level0,
left: .level22,
right: .level0
)
Gives error - Ambiguous use of 'init'
It could be easily fixed with modifying initializer or adding next argument with default value, but it doesn't look right, is there any other way to specify init method called?
Your example doesn't match your code (there is no init(vertical:left:right) defined), so I'm going to try to generalize this problem a bit with a full example that avoids the extra types. I'll just use Double and Int here.
Imagine a struct X that internally stores three Doubles:
struct X {
var x: Double
var y: Double
var z: Double
init(x: Double = 0, y: Double = 0, z: Double = 0) {
self.x = x
self.y = y
self.z = z
}
}
You also want to be able to pass three Ints instead, but all three must either be Doubles or Ints, and you want default values. Every use of default values is just a shorthand for an extra method with fewer parameters. To avoid conflicts, you need to include at least one of the parameters as non-default:
extension X {
init(x: Int, y: Int = 0, z: Int = 0) {
self.init(x: Double(x), y: Double(y), z: Double(z))
}
init(y: Int, z: Int = 0) { self.init(x: 0, y: y, z: z) }
init(z: Int) { self.init(x: 0, y: 0, z: z) }
}
Now, every combination is legal, but there are no ambiguities.
This is nice when there's just one extra way to call the init. But maybe you want there to be many. Then a protocol is useful. For example, this approach allows either Int or Double for every parameter:
protocol XParameter {
var xParameterValue: Double { get }
}
extension Double: XParameter {
var xParameterValue: Double { self }
}
extension Int: XParameter {
var xParameterValue: Double { Double(self) }
}
struct X {
var x: Double
var y: Double
var z: Double
init(x: some XParameter = 0, y: some XParameter = 0, z: some XParameter = 0) {
self.x = x.xParameterValue
self.y = y.xParameterValue
self.z = z.xParameterValue
}
}
I'm doing a lot of positioning and animation stuff in literals, and they're taking up a lot of space and becoming unreadable because of the verbosity.
What I'd like to do is turn this
var xy = CGPoint(x: 100, y: 100)
Into this:
var xy = •(100, 100)
Similarly, I'd like to go from:
CGVector(dx: 200, dy: 200)
to something like this:
`(200, 200)
But I don't know how a macro-like shorthand or something like this would be done, or even if it could be done. Any pointers (puntendered) would be better than where I'm at.
I get that this is probably, for most people, less readable.
Due to the context I always know what these are. I don't need the parameter labels or function name to understand what I'm doing. And this is private animation and motion testing, there's no need for anyone else to ever understand what's going on.
extension CGPoint {
init(_ x: CGFloat, _ y: CGFloat) {
self.init(x: x, y: y)
}
}
extension CGVector {
init(_ dx: CGFloat, _ dy: CGFloat) {
self.init(dx: dx, dy: dy)
}
}
typealias P = CGPoint
typealias V = CGVector
let p = P(10, 10)
let v = V(10, 10)
But no idea about the • and ` part - I replaced them with P and V :)
For this type of thing you would likely use a typealias but I don't think you will be able to create types with names as operators or symbols.
See below, I created a typeAlias of CGP for CGPoint, you could simply just alias it to Point if you like.
Here is some information from the docs
A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations are declared using the typealias keyword and have the following form:
typealias name = existing type
After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type.
EDIT
Two simple method of excluding the parameter names:
func cp(_ x: Int, _ y: Int) -> CGPoint {
return CGPoint(x: x, y: y)
}
let point = cp(0,2)
extension CGPoint {
init(_ x: Int, _ y: Int) {
self.init(x: x, y: y)
}
}
typealias CGP = CGPoint
let point2 = CGP(1,1)
The first method just creates a helper function which returns a CGPoint using it's designed intialiser. The second option is the better way of doing it, you extend CGPoint and add an intializer that marks the params as non-named params (by using the _ instead of the external name)
You can't use special characters as the compiler would not be able to differentiate between function names and operators like '*'.
Using typealias
using a typealias would allow you to shorten the function name but not omit the parameter names like you outlined in your question.
typealias p = CGPoint
//example
let p1 = p(x: 60, y: 60)
Using anonymous parameters
func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
return CGPoint(x: x,y: y)
}
//example
let p1 = p(60, 60) //no parameter names
I too like to get rid of the parameter labels, but I don't advise reducing things to any briefer shorthand. I paste this code into the start of all my app projects:
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
extension CGSize {
init(_ width:CGFloat, _ height:CGFloat) {
self.init(width:width, height:height)
}
}
extension CGPoint {
init(_ x:CGFloat, _ y:CGFloat) {
self.init(x:x, y:y)
}
}
extension CGVector {
init (_ dx:CGFloat, _ dy:CGFloat) {
self.init(dx:dx, dy:dy)
}
}
That allows me to say things like CGPoint(1,4), and that's good enough, in my opinion.
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
I am trying to become confident using functions. I am practicing with the code below.
class Arithmetics {
var operand1: Double
var operand2: Double
init(operand1: Double, operand2: Double) {
self.operand1 = operand1
self.operand2 = operand2
}
func AddInsideClass(operand1: Double, operand2: Double) -> Double {
var sum = operand1 + operand2
return sum
}
}
func AddOutsideClass(operand1: Double, operand2: Double) -> Double {
var sum = operand1 + operand2
return sum
}
println(AddOutsideClass(5.5, 4.5))
println(Arithmetics.AddInsideClass(5.5, 4.5))
In the last 2 lines I tried to call the functions and output them on the console. The first println() is calling the function from outside the class, which works fine.
The second println() however gives me an error message that goes like this:
"stdin:23:35: error: extra argument in call
println(Arithmetics.AddInsideClass(5.5, 4.5))
^ ~~~"
What's the problem here?
Is it because I cannot simply call a class method directly? Or can I call class methods only via a class instance like below?
var operation1: Double = Arithmetics.AddInsideClass(5.5, 4.5)
You have two options:
First – using your syntax – you declare the function as static and you can omit the variables and the init function
class Arithmetics {
static func addInsideClass(operand1: Double, operand2: Double) -> Double {
var sum = operand1 + operand2
return sum
}
}
You can call it on the class (the second parameter name is mandatory)
Arithmetics.addInsideClass(5.5, operand2:4.5)
Second you create an instance of the class which now needs no operands in the add function because they are set in the init function.
class Arithmetics {
var operand1: Double
var operand2: Double
init(operand1: Double, operand2: Double) {
self.operand1 = operand1
self.operand2 = operand2
}
func addInsideClass() -> Double {
var sum = operand1 + operand2
return sum
}
}
And the syntax to call it is
let operation1 = Arithmetics(operand1: 5.5, operand2: 4.5)
operation1.addInsideClass()
A class method is a method that operates on class objects rather than
instances of the class.
AddInsideClass is not a class-method. It can only be called using an object of the class Arithmetics and not with the class name itself.
Create an object of the class Arithmetics in order to call its methods in another class.
let arithmeticsClassObj = Arithmetics()
println(arithmeticsClassObj.AddInsideClass(5.5, 4.5))
Reference: Apple Docs
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