How Is `Size` Being Initialized & Accepted as a Parameter, if it's Not in any Subclass nor in the Superclass property, nor '_' is Used Before it?

Hello. In the

init()
function (line 66), inside
class TriangleAndSquare
, how come there's a need for the parameter label
size
to be initialized, and how is it being accepted as a parameter even though it's not a property in any subclass (including that class itself) or superclass?

Also how is

size
being accepted as an argument (lines 67 & 68) it seems, for type
Square: NameShape
(line 12) in its
init()
function (line 15), when
class Square: NameShape
doesn't even have
size
as one of it's properties too [nor is
size
in the superclass:
NameShape
(line 1)], nor is it being initialized in 'class Square: NameShape`?


Shouldn't there be an underscore

_
before
size
in
class TriangleAndSquare
's
init()
function parameter (line 66), perhaps as
init(_ size: Double, name: String)
so that any argument label, when an object is created, can be accepted as its parameter?


This code is from the 'GuidedTour.playground' file from their 'The Swift Programming Language 4.2' (it's in their Swift 5 version, of the same book, as well). The code is in the section: 'Classes and Objects'.


I've already digested the Apple docs and some good video tutorials on the purpose and nature of: initialization, argument, argument labels, parameters & parameter labels but I guess, I need another view/explanation on these.


class NamedShape {
    var numberOfSides: Int = 0
    var name: String
   
    init(name: String) {
        self.name = name
    }
   
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

class Square: NamedShape {
    var sideLength: Double
   
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }
   
    func area() -> Double {
        return sideLength * sideLength
    }
   
    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0
   
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }
   
    var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }
   
    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}

class TriangleAndSquare {
    var triangle: EquilateralTriangle {
        willSet {
            square.sideLength = newValue.sideLength
        }
    }
    var square: Square {
        willSet {
            triangle.sideLength = newValue.sideLength
        }
    }
    init(size: Double, name: String) {
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}


Thank you in advance.

God bless, Revelation 21:4

how come there's a need for the parameter label

size
to be initialized


Parameters does not need to be initialized. It is initialized when the function (including method or init) is called.


how is it being accepted as a parameter even though it's not a property in any subclass (including that class itself) or superclass?


Parameter is a sort of local variable. It may have nothing to do with properties.

I do not understand why you think parameters should be a property. Please explain.


how is

size
being accepted as an argument (lines 67 & 68)


Again, parameter is just a local variable. You know you can pass any local variable as an argument.


Shouldn't there be an underscore

_
before
size
in
class TriangleAndSquare
's
init()
function parameter (line 66),


No. Putting `_` means that the parameter does not have its parameter label. When you want the parameter label to be the same as parameter name, you should not put `_`. The designer of the class `TriangleAndSquare` wants to call the initializer as `TriangleAndSquare(size: someSize, name: someName)`, so he did not put `_`.


I've already digested the Apple docs and some good video tutorials on the purpose and nature of: initialization, argument, argument labels, parameters & parameter labels but I guess, I need another view/explanation on these.


Seems those are not enough, and you need to study more with throwing away your assumptions and prejudices.

You are missing some basic concepts.


In class TriangleAndSquare,


init is a "convenience init", meaning it let you pass parameters to the instance on creation.


Here you pass 2 parameters, size and name that will be used to initialize the properties of the class, triangle and square.


You could do it without this convenience init, but it would be much more complex:


class TriangleAndSquare2 {
    var triangle: EquilateralTriangle?
   
    var square: Square?
   
}

let tAndS = TriangleAndSquare(size: 10.0, name: "Triangle and square")
print(tAndS.square.name, tAndS.square.area(), tAndS.triangle.name, tAndS.triangle.perimeter)

var tAndS2 = TriangleAndSquare2()
tAndS2.square = Square(sideLength: 0.0, name: "no name yet")
tAndS2.square?.sideLength = 10.0
tAndS2.square?.name = "Square name"
tAndS2.triangle = EquilateralTriangle(sideLength: 0.0, name: "no name yet")
tAndS2.triangle?.sideLength = 10.0
tAndS2.triangle?.name = "Triangle name"
print(tAndS2.square!.name, "area", tAndS2.square!.area(), tAndS2.triangle!.name, "perimeter", tAndS2.triangle!.perimeter)

Hi. Thanks Claude31 and OOPer (Object-Oriented Programmer:-) clever).


(Correct me if my terms/concepts are wrong) On the assumption that properties always needing to be parameters, I probably meant to say

that the properties are always in the convenience initializer's definition being equated/initialized to the argument (memberwise initializer & argument are the same thing btw?) that's been passed on to the parameter:


That's the usual example I see in the docs and in other video tutorials.


For example in class NameShape's var name property (line 3) is being initialized in line 6 with whatever the value of the argument will be (passed on to the parameter, name. By the way, is self.name in line 6 a new storage in memory or it just points to var name which is where the real argument/memberwise passed to the name parameter is stored)?


The same pattern is seen in class Square: NameShape, whereby 1 property (sideLength) presumably local only to Square: NameShape is in the definition of init and 2 properties (numberOfSide and name) from the superclass NameShape are in Square: NameShape's init definition, only numberOfSides was changed to 4 (how come the override keyword wasn't needed for that, if it's changing it from 0 in line 2 btw?).


Same with class EquilateralTriangle: NameShape, whereby var sideLength, which has the same name as Square: NameShape's sideLength but local to it, was somehow still initialized in init, even though, it's already given an initialization of 0.0 in line 33 (why give it a value of 0.0, if you're still going to rely for it's initialization from whatever the argument/memberwise initializer for this class' sideLength, btw?).


In line 20 numberOfSides is literally initialized to 4 (how come, again, it does not have the override keyword, if it's changing the initializer/value from 0 from line 2, to the value of 4? If it's not the override keyword, how come numberOfSides can be initialized without the super.init at least, while name (line 37), needs the super.init to get in touch with line 2's name variable? Are all class and struct properties global?)


With those patterns in place, suddenly comes 'size' out of nowhere in TriangleAndSquare. I guess that's how my concept of things got conditioned (the docs probably should mention about how 'size' came to be as a footnote) but now I know.

That's the usual example I see in the docs and in other video tutorials.


True, it's the most frequently found pattern in simplified examples for starters.



With those patterns in place, suddenly comes 'size' out of nowhere in TriangleAndSquare. I guess that's how my concept of things got conditioned (the docs probably should mention about how 'size' came to be as a footnote) but now I know.


You may be confused with the most frequently found patterns and the requirement.


Focusing on initializers, one of the requirement is that all the instance properties need to be ininitalized till the end of the initializer or before calling `super.init`.


And with fulfilling the requirements, you can choose some better parameter names if it suits for a new concept like `TriangleAndSquare`.

The name `sideLength` may suit for each shape like `EquilateralTriangle` or ` Square`, but does it suit for `TriangleAndSquare`?


I'm not sure if the name `size` best fits for `TriangleAndSquare`, but I guess the author might want to show that programmers using Swift have the liberty to choose best-fit names for the new concept.

For example in class NameShape's var name property (line 3) is being initialized in line 6 with whatever the value of the argument will be (passed on to the parameter, name.


It is initialized if you call this initializer:


let aNamedShape = NamedShape(name: "a given name")
print(aNamedShape.name, aNamedShape.simpleDescription())

you get

a given name A shape with 0 sides.


if you add an init()

    init() {
        self.name = ""          // Need to initialize this one
    }


and call

let aNamedShape2 = NamedShape()
print(aNamedShape.name, aNamedShape.simpleDescription())

you get

A shape with 0 sides.


By the way, is self.name in line 6 a new storage in memory or it just points to var name which is where the real argument/memberwise passed to the name parameter is stored)?


Not a new storage, just set the property value of the instance.



The same pattern is seen in class Square: NameShape, whereby 1 property (sideLength) presumably local only to Square: NameShape is in the definition of init and 2 properties (numberOfSide and name) from the superclass NameShape are in Square: NameShape's init definition, only numberOfSides was changed to 4 (how come the override keyword wasn't needed for that, if it's changing it from 0 in line 2 btw?).


property is not local (take care of using precise concept naming) : it is the property of the subclass, that each instance of Square will have.

numberOfSide and name are effectively inherited from the superClass NamedShape

You don't override numberOfSides, you just set its value for any instance of Square.

An override would be if you changed the definition of the var: if the var was a computed property, then you could override its definition


class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    var name2: String {
        return "A fixed name"
    }

    init(name: String) {
        self.name = name
    }
   
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides." + "name2 is" + name2
    }
}

You cannot change the value of name2 in Square,

class Square: NamedShape {
    var sideLength: Double
   
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
        self.name2 = "new name2"
    }

causes a compiler error:

error: MyPlayground IOS XCode10.playground:654:20: error: cannot assign to property: 'name2' is a get-only property

self.name2 = "new name2"

~~~~~~~~~~ ^


but you can override it with a var of the same type (or a subclass of it):

class Square: NamedShape {
    var sideLength: Double

    override var name2 : String {
        return "overriden name2"
    }
   
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }


let aSquare = Square(sideLength: 12.0, name: "Square name")

print(aSquare.name, aSquare.name2)


will give:

Square name overriden name2



Same with class EquilateralTriangle: NameShape, whereby var sideLength, which has the same name as Square: NameShape's sideLength but local to it,

Not local, but instance property

It is the same name, but that does not matter ; why would you give it a different name, in fact you will always refer to it inside the class (hence no confusion possible) or through an instance property:

aSquare.numberOfSides

or

aTriangle.numberOfSides


was somehow still initialized in init, even though, it's already given an initialization of 0.0 in line 33 (why give it a value of 0.0, if you're still going to rely for it's initialization from whatever the argument/memberwise initializer for this class' sideLength, btw?).

Effectively, no need to set it to 0.0 at definition (unless you had an init() func where you do not initialize it) ; I think it is just to show you a different pattern.

In fact, it is a safe practice to get all var initialized at definition


If you write

class EquilateralTriangle: NamedShape {
    var sideLength: Double // = 1.0
   
    init(justTheName: String) {
        //        self.sideLength = 0.0
        super.init(name: justTheName)
    }


Then you get an error:

property 'self.sideLength' not initialized at super.init call

super.init(name: justTheName)

^

You need either to initialize at declaration (of course, you can choose a non zero default value, like 1.0) or in the init(justTheName:)

    init(justTheName: String) {
        self.sideLength = 1.0
        super.init(name: justTheName)
    }

And last question…


In line 20 numberOfSides is literally initialized to 4 (how come, again, it does not have the override keyword, if it's changing the initializer/value from 0 from line 2, to the value of 4?

Here also, not an override, you just set the value in the instance of the subclass.

So line 20 does not change the value in the superclass. This is a basic principle of inheritance.


Logic is:

class NamedShape

sets a default value of 0 for numberOfSides

When you init a Square with

class Square: NamedShape {
    var sideLength: Double
   
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        print("Square inherited numberOfSides", numberOfSides)

        numberOfSides = 4
    }


after initializing all properties of the subclass (sideLength, as it was not defined with a default value), you initialize all the properties inherited from super class. super.init means you use the initializer defined in super class.

At this point, numberOfSides is 0, for the subclass instance

I have added a print on line 7 for you to see it ; result is

Square inherited numberOfSides 0

Then you set the value for the instance


If it's not the override keyword, how come numberOfSides can be initialized without the super.init at least, while name (line 37), needs the super.init to get in touch with line 2's name variable?

Here again, you don't initialize in super, you use super.init to call the parent class init in order to set the value of the inherited properties.


Are all class and struct properties global?)

They are global inside the class, but not out of the class.

Don't confounds local/global which are scope concept with the concept of inheritance.



You should study very carefully the inheritance mechanisms; look at Apple Inc. « The Swift Programming Language (Swift 4). » iBooks.

« Inheritance

A class can inherit methods, properties, and other characteristics from another class. When one class inherits from another, the inheriting class is known as a subclass, and the class it inherits from is known as its superclass. Inheritance is a fundamental behavior that differentiates classes from other types in Swift. »

and a lot more here

How Is `Size` Being Initialized & Accepted as a Parameter, if it's Not in any Subclass nor in the Superclass property, nor '_' is Used Before it?
 
 
Q