W1605 Only One

From Coder Merlin
Revision as of 06:58, 20 June 2019 by Chukwuemeka-tinashe (talk | contribs) (Merlin moved page Project-1605 to W1605 Only One: Improved navigation)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder
Delhi Metro Line 1

Prerequisites[edit]

Research[edit]

Background[edit]

We learned in the previous lab that it's often useful to instantiate multiple objects of the same class. For example, we're able to use one Paddle class to create two paddle instances, one for the left paddle and one for the right. But how can we share state across multiple objects? We'll explore the concept of sharing state in this lab.

Experiment[edit]

Getting Started[edit]

Continue with the previous project.

Enter into the Sources directory of the project.

cd ~/projects/IgisShell-MovingAlong/Sources/IgisShell/

Let's Play[edit]

Start button green arrow

Run your project.
Working with a colleague, navigate to the same URL on two different computers and observe your project. Use your keyboard to move the left paddle up; ask your colleague to use their keyboard to move the left paddle down. Use your mouse to move the ball in your browser, ask your colleague to use their mouse to move the ball in their browser.

Emblem-question-green.svg Question: What is the behavior that you observe? What is the relationship between what's happening in the first browser and what's happening in the second? How can you explain this behavior?

First Steps[edit]

Let's start by reviewing the file "main.swift" which contains our Painter class:

emacs main.swift

Review the line let ball : Ball.

Emblem-question-green.svg Question: What is the purpose of this line? On what line is the ball actually created? If two different browsers connect to your application, how many balls are instantiated?

Investigate[edit]

Let's test our hypothesis. Edit the file "Ball.swift":

emacs Ball.swift

Add a line to print a debugging statement whenever a ball is instantiated:

    init(size:Int) {
        print("Creating new Ball")
        ellipse = Ellipse(center:Point(x:0, y:0), radiusX:size, radiusY:size, fillMode:.fillAndStroke)
        velocityX = 0
        velocityY = 0
    }
Start button green arrow

Run your project.
Be sure to set up your windows so that you can simultaneously observe console output and a browser. Working with a colleague, navigate to the same URL on two different computers and observe the console output. Refresh one of the browsers and then refresh the other.

Emblem-question-green.svg Question: What causes a new ball to be instantiated?

Static Property[edit]

Edit the file "main.swift":

emacs main.swift

Change the line let ball : Ball to:

static let ball = Ball(size:30)

Now, attempt to compile. You'll see a series of errors similar to:

error: static member 'ball' cannot be used on instance of type 'Painter'

This is because Swift insists that we be very clear with regard to intent: do we want to use an instance variable or a static variable? In the case of an instance variable we simply reference the variable (property) using either its unqualified name (e.g. ball) or qualified by identifying the instance (e.g. self.ball)). In the case of a static variable, we're required to overtly clarify our intentions by qualifying the identifier with the class name, in this case Painter.ball because ball is a static variable belonging to the Painter class.

Again, edit main.swift:

emacs main.swift

Remove the line in the initializer that creates a new ball instance, because we've already done this when we declare the variable.

    required init() {
        // ball = Ball(size:30) <-- REMOVE THIS LINE
        ball.changeVelocity(velocityX:10, velocityY:5)

        paddleLeft = Paddle(topLeft:Point(x:0, y:0), size:Size(width:10, height:100))
        paddleRight = Paddle(topLeft:Point(x:0, y:0), size:Size(width:10, height:100))
    }

Change every reference to ball to Painter.ball throughout the entire Painter class.

    func calculate(canvasSize:Size) {
        if !coordinatesSet {
            let canvasCenter = Point(x:canvasSize.width/2, y:canvasSize.height/2)
            Painter.ball.move(to:canvasCenter)

            paddleLeft.move(to:Point(x:10, y:canvasCenter.y))
            paddleRight.move(to:Point(x:canvasSize.width-paddleRight.rectangle.rect.size.width-10, y:canvasCenter.y))

            coordinatesSet = true
        }
        Painter.ball.calculate(canvasSize:canvasSize)
    }
Start button green arrow

Run your project.
Be sure to set up your windows so that you can simultaneously observe console output and a browser. Working with a colleague, navigate to the same URL on two different computers and observe the console output. Refresh one of the browsers and then refresh the other.

Emblem-question-green.svg Question: When was the ball first created? How many subsequent balls were created after the first?

Now, use your keyboard to move the left paddle up; ask your colleague to use their keyboard to move the left paddle down. Use your mouse to move the ball in your browser, ask your colleague to use their mouse to move the ball in their browser.

Emblem-question-green.svg Question: What is the behavior that you observe? What is the relationship between what's happening in the first browser and what's happening in the second? How can you explain this behavior? What has changed?


Exercises[edit]

  1. Add a print statement to the initializer for Paddle. If you re-run the application and launch two browsers as before, how many paddle creation messages do you expect to see? Re-run the application and test your hypothesis.
  2. Make the required changes so that the paddles can be controlled by two different computers yet move in unison.

Key Concepts[edit]

  • A Static property (referred to as a type property in Swift)
    • Have a lifetime of the entire execution of the program
    • Most often have a more limited scope constrained by the enclosing type
    • In the case of classes, enable data to be shared easily amongst all instances
  • In the case of a static variable, we're required to overtly clarify our intentions by qualifying the identifier with the class name