TIC2002 (2018)
  • Flat (current format)
  •     Nested
  • Schedule
  • Textbook
  • Admin Info
  • Report Bugs
  • Slack
  • Forum
  • Instructors
  • Announcements
  • File Submissions
  • Tutorial Schedule
  • Team IDs
  • Java Coding Standard
  • samplerepo-things
  • Addressbook-level1
  • Addressbook-level2
  • Addressbook-level3
  • Addressbook-level4
  • Projects List
  • Week 2 [Aug 20]

    Todo

    Admin info to read:

    Admin Appendix B (Policies) → Policy on tech help

    Policy on tech help

    Do not expect your tutor to code or debug for you. We strongly discourage tutors from giving technical help directly to their own teams because we want to train you in troubleshooting tech problems yourselves. Allowing direct tech help from tutors transfers the troubleshooting responsibility to tutors.

    It is ok to ask for help from classmates even for assignments, even from other teams, as long as you don't copy from others and submit as your own. It doesn't matter who is helping you as long as you are learning from it.

    We encourage you to give tech help to each other, but do it in a way that the other person learns from it.

    Related: [Admin: Appendix D: Getting Help]

    Admin Tools


    Learning Management System: This module website is the main source of information for the module. In addition, we use IVLE for some things (e.g., announcements, file submissions, grade book, ...) and LumiNUS for lecture webcasts (reason: IVLE no longer supports webcasts).

    Collaboration platform: You are required to use GitHub as the hosting and collaboration platform of your project (i.e., to hold the Code repository, Issue Tracker, etc.). See Appendix E for more info on how to setup and use GitHub for your project.

    Communication: Keeping a record of communications among your team can help you, and us, in many ways. We encourage you to do at least some of the project communication in written medium (e.g., GitHub Issue Tracker) to practice how to communicate technical things in written form.

    • Instead of the IVLE forum, we encourage you to post your questions/suggestions in this github/nus-tic2002-2018/forum.
    • Alternatively, you can post in our slack channel https://nus-tic2002-2018.slack.com. We encourage you all to join the slack channel (you'll need to use an email address ending in @nus.edu.sg, @comp.nus.edu.sg, @u.nus.edu.sg or @u.nus.edu to join this channel).
    • Note that slack is useful for quick chats while issue tracker is useful for longer-running conversations.
    • You are encouraged to use channels with a wider audience (common channel in slack, GitHub issue tracker) for module-related communication as much as possible, rather than private channels such as private slack/FB messages or direct emails. Rationale: more classmates can benefit from the discussions.

    IDE: You are recommended to use Intellij IDEA for module-related programming work. You may use the community edition (free) or the ultimate edition (free for students). While the use of Intellij is not compulsory, note that module materials are optimized for Intellij. Use other IDEs at your own risk.

    Revision control: You are required to use Git. Other revision control software are not allowed.
    The recommended GUI client for Git is SourceTree (which comes bundled with Git), but you may use any other, or none.

    Collating code: To extract out code written by each person, we use a custom-built tool called Collate.

    Collate is a tool for collating code written by different developers.

    Steps to use Collate:

    1. Download Collate-TUI.jar from the Collate Tool project
    2. Annotate your code to indicate who wrote which part of the code (instructions given below)
    3. Run the Collate tool to collate code written by each person into separate files (instructions given below)

    Annotating code to indicate authorship

    • Mark your code with a //@@author {yourGithubUsername}. Note the double @.
      The //@@author tag should appear only at the beginning of the code you wrote. The code up to the next //@@author tag or the end of the file (whichever comes first) will be considered as was written by that author. Here is a sample code file:

      //@@author johndoe
      method 1 ...
      method 2 ...
      //@@author sarahkhoo
      method 3 ...
      //@@author johndoe
      method 4 ...
      
    • If you don't know who wrote the code segment below yours, you may put an empty //@@author (i.e. no GitHub username) to indicate the end of the code segment you wrote. The author of code below yours can add the GitHub username to the empty tag later. Here is a sample code with an empty author tag:

      method 0 ...
      //@@author johndoe
      method 1 ...
      method 2 ...
      //@@author
      method 3 ...
      method 4 ...
      
    • The author tag syntax varies based on file type e.g. for java, css, fxml. Use the corresponding comment syntax for non-Java files.
      Here is an example code from an xml/fxml file.

      <!-- @@author sereneWong -->
      <textbox>
        <label>...</label>
        <input>...</input>
      </textbox>
      ...
      
    • Do not put the //@@author inside java header comments as only the content below that tag will be collated.
      👎

      /**
        * Returns true if ...
        * @@author johndoe
        */
      

      👍

      //@@author johndoe
      /**
        * Returns true if ...
        */
      

    What to and what not to annotate

    • Annotate both functional and test code but not documentation files.

    • Annotate only significant size code blocks that can be reviewed on its own  e.g., a class, a sequence of methods, a method.
      Claiming credit for code blocks smaller than a method is discouraged but allowed. If you do, do it sparingly and only claim meaningful blocks of code such as a block of statements, a loop, or an if-else statement%%.

      • If an enhancement required you to do tiny changes in many places, there is no need to collate all those tiny changes; you can describe those changes in the Project Portfolio page instead.
      • If a code block was touched by more than one person, either let the person who wrote most of it (e.g. more than 80%) take credit for the entire block, or leave it as 'unclaimed' (i.e., no author tags).
      • Related to the above point, if you claim a code block as your own, more than 80% of the code in that block should have been written by yourself. For example, no more than 20% of it can be code you reused from somewhere.
      • 💡 GitHub has a blame feature and a history feature that can help you determine who wrote a piece of code.
    • Do not try to boost the length of your collated files using dubious means such as duplicating the same code in multiple places. In particular, do not copy-paste test cases to create redundant tests. Even repetitive code blocks within test methods should be extracted out as utility methods to reduce code duplication.
      Individual members are responsible for making sure their own collated files contain the correct content.
      If you notice a team member claiming credit for code that he/she did not write or use other questionable tactics, you can email us (after the final submission) to let us know.

    • If you wrote a significant amount of code that was not used in the final product,

      • Create a folder called {project root}/unused
      • Move unused files (or copies of files containing unused code) to that folder
      • use //@@author {yourGithubUsername}-unused to mark unused code in those files (note the suffix unused) e.g.
      //@@author johndoe-unused
      method 1 ...
      method 2 ...
      

      Please put a comment in the code to explain why it was not used.

    • If you reused code from elsewhere, mark such code as //@@author {yourGithubUsername}-reused (note the suffix reused) e.g.

      //@@author johndoe-reused
      method 1 ...
      method 2 ...
      
    • For code generated by the IDE/framework, it should not be annotated as your own.

    • Code you modified in minor ways e.g. adding a parameter. These can be left out of collated code but can be mentioned in the Project Portfolio page if you want to claim credit for them.

    Collating the annotated code

    You need to put the collated code in the following folders

    Code Type Folder
    functional code collated/functional
    test code collated/test
    unused code collated/unused

    Refer to Collate Tool's user guide to find how to run the tool over the annotated code.

    Given below are DOS sample commands you can put in a batch file and run it to collate the code.

    java -jar Collate-TUI.jar collate from src/main to collated/functional include java, fxml, css
    
    java -jar Collate-TUI.jar collate from src/test to collated/test include java
    
    java -jar Collate-TUI.jar collate from unused to collated/unused include java, fxml, css
    

    The output should be something like the structure given below.

    collated/
        functional/
            johndoe.md
            sarahkhoo.md
            ravikumar.md
            ravikumarreused.md
        test/
            johndoe.md
            sarahkhoo.md
            ravikumar.md
        unused/
            johndoe.md
    
    • After running the collate tool, you are recommended to look through the generated .md files to ensure all your code has been extracted correctly.

    • Push the *.md files created to a folder called /collated in your repo.

    Admin Project: Overview

    The high-level learning outcome of the project (and to a large degree, the entire module):

    Can contribute production quality SE work to a small/medium software project

    Accordingly, the module project is structured to resemble an intermediate stage of a non-trivial real-life software project. In this project you will,

    1. conceptualize and implement enhancements to a given product, and,
    2. have it ready to be continued by future developers.

    Admin Project: The product

    In this semester, we are going to enhance an AddressBook application.

    This product is meant for users who can type fast, and prefer typing over mouse/voice commands. Therefore, Command Line Interface (CLI) is the primary mode of input.

    Relevant: [Admin Project Contstraints → More info about the 'CLI app' requirement ]

     
    • Constraint-CLI: Command Line Interface is the primary mode of input. The GUI should be used primarily to give visual feedback to the user rather than to collect input. Some minimal use of mouse is OK (e.g. to click the minimize button), but the primary input should be command-driven.
      • Mouse actions should have keyboard alternatives.
      • Typing is preferred over key combinations. Design the app in a way that you can do stuff faster by typing compared to mouse actions or key combinations.
      • One-shot commands are preferred over multi-step commands. If you provide a multi-step command to help new users, you should also provide a one-shot equivalent for regular users.  Reason: We want the user to be able to accomplish tasks faster using CLI than a GUI; having to enter commands part-by-part will slow down the user.
      • ❗️ While we don't prohibit GUI-only features, such features will be ignored during grading.

    Admin Project: Scope
    In general, each team is expected to take one of these two directions:
    • [Direction 1] Optimize AddressBook for a more specific target user group:

      An AddressBook,

      • for users in a specific profession  e.g. doctors, salesmen, teachers, etc.
      • based on the nature/scale of contacts  e.g. huge number of contacts (for HR admins, user group admins), mostly incomplete contacts, highly volatile contact details, contacts become inactive after a specific period (e.g. contract employees)
      • based on what users do with the contacts  e.g. organize group events, share info, do business, do analytics

    • [Direction 2] Morph AddressBook into a different product: Given that AddressBook is a generic app that manages a type of elements (i.e. contacts), you can use it as a starting point to create an app that manages something else.
      ❗️ This is a high-risk high-reward option because morphing requires extra work but a morphed product may earn more marks than an optimized product of similar complexity.

      An app to manage,

      • Bookmarks of websites
      • Tasks/Schedule
      • Location info
      • Thing to memorize i.e. flash cards, trivia
      • Forum posts, news feeds, Social media feeds
      • Online projects or issue trackers that the user is interested in
      • Emails, possibly from different accounts
      • Multiple types of related things  e.g. Contacts and Tasks (if Tasks are allocated to Contacts)

    For either direction, you need to define a target user profile and a value proposition:

    • Target user profile: Define a very specific target user profile.
      💡 We require you to narrow down the target user profile  as opposed to trying to make it as general as possible. Here is an example direction of narrowing down target user: anybody → teachers → university teachers → tech savvy university teachers → TIC2002 instructors.

      ❗️ Be careful not to contradict given project constraints when defining the user profile  e.g. the target user should still prefer typing over mouse actions.

      It is expected that your product will be optimized for the chosen target users i.e., add features that are especially/only applicable for target users (to make the app especially attractive to them). w.r.t. the example above, there can be features that are applicable to TIC2002 instructors only, such as the ability to navigate to a student's project on GitHub 💡 Your project will be graded based on how well the features match the target user profile and how well the features fit-together.

      • It is an opportunity to exercise your product design skills because optimizing the product to a very specific target user requires good product design skills.
      • It minimizes the overlap between features of different teams which can cause plagiarism issues. Furthermore, higher the number of other teams having the same features, less impressive your work becomes especially if others have done a better job of implementing that feature.

    • Value proposition: Define a clear value proposition (what problem does the product solve? how does it make the the user's life easier?) that matches the target user profile.

    Individually, each student is expected to,

    1. Contribute one enhancement to the product
      Each enhancement should be stand-alone but,

      • it should be end-user visible and end-user testable.
      • should fit with the rest of the software (and the target user profile),
      • and should have the consent of the team members.
      1. Add a new feature
      2. Enhance an existing features in a major way e.g. make the command syntax more user friendly and closer to natural language
      3. A major redesign of the GUI e.g. make it work like a chat application (note: chat is a form of CLI)
      4. Integrate with online services e.g. Google contacts, Facebook, GitHub, etc.

      Here are some examples of different major enhancements and the grade the student is likely to earn for the relevant parts of the project grade.

      In the initial stages of the project you are recommended to add minor enhancements in order to get familiar with the project. These minor enhancements are unlikely to earn marks. You are advised not to spend a lot of effort on minor enhancements.

      Here is a non-exhaustive list of minor enhancements:

      1. Support different themes for the Look & Feel  dark, light, etc.
      2. Support more fields  e.g. Birthday
      3. Load a different page instead of the default Google search page  e.g. Google Maps page or Twitter page
      4. Sort items
      5. Multiple panels  e.g. an additional panel to show recently accessed items
      6. Marking some items as favorites
      7. Ability to search by labels
      8. Ability to specify colors for labels

    2. Recommended: contribute to all aspects of the project: e.g. write backend code, frontend code, test code, user documentation, and developer documentation. If you limit yourself to certain aspects only, you will lose marks allocated for the aspects you did not do.
      In particular, you are required to divide work based on features rather than components:

      • By the end of this project each team member is expected to have implemented an enhancement end-to-end, doing required changes in almost all components.  Reason: to encourage you to learn all components of the software, instead of limiting yourself to just one/few components.
      • Nevertheless, you are still expected to divide the components of the product among team members so that each team member is in charge of one or more components. While others will be modifying those components as necessary for the features they are implementing, your role as the in charge of a component is to guide others modifying that component (reason: you are supposed to be the most knowledgeable about that component) and protect that component from degrading  e.g., you can review others' changes to your component and suggest possible changes.
    3. Do a share of team-tasks: These are the tasks that someone in the team has to do. Marks allocated to team-tasks will be divided among team members based on how much each member contributed to those tasks.

      Here is a non-exhaustive list of team-tasks:

      1. Necessary general code enhancements e.g.,
        1. Work related to renaming the product
        2. Work related to changing the product icon
        3. Morphing the product into a different product
      2. Setting up the GitHub, Travis, AppVeyor, etc.
      3. Maintaining the issue tracker
      4. Release management
      5. Updating user/developer docs that are not specific to a feature  e.g. documenting the target user profile
      6. Incorporating more useful tools/libraries/frameworks into the product or the project workflow (e.g. automate more aspects of the project workflow using a GitHub plugin)

    4. Share roles and responsibilities of the project.

      Roles indicate aspects you are in charge of and responsible for. E.g., if you are in charge of documentation, you are the person who should allocate which parts of the documentation is to be done by who, ensure the document is in right format, ensure consistency etc.

      This is a non-exhaustive list; you may define additional roles.

      • Team lead: Responsible for overall project coordination.
      • Documentation (short for ‘in charge of documentation’): Responsible for the quality of various project documents.
      • Testing: Ensures the testing of the project is done properly and on time.
      • Code quality: Looks after code quality, ensures adherence to coding standards, etc.
      • Deliverables and deadlines: Ensure project deliverables are done on time and in the right format.
      • Integration: In charge of versioning of the code, maintaining the code repository, integrating various parts of the software to create a whole.
      • Scheduling and tracking: In charge of defining, assigning, and tracking project tasks.
      • [Tool ABC] expert: e.g. Intellij expert, Git expert, etc. Helps other team member with matters related to the specific tool.
      • In charge of[Component XYZ]: e.g. In charge of Model, UI, Storage, etc. If you are in charge of a component, you are expected to know that component well, and review changes done to that component in v1.3-v1.4.

      Please make sure each of the important roles are assigned to one person in the team. It is OK to have a 'backup' for each role, but for each aspect there should be one person who is unequivocally the person responsible for it.

    5. Write ~300-500 LoC of code, on average.

    As a team, you are expected to work together to,

    1. Preserve product integrity: i.e.
      1. Enhancements added fit together to form a cohesive product.
      2. Documentation follows a consistent style and presents a cohesive picture to the reader.
      3. Final project demo presents a cohesive picture to the audience.
    2. Maintain product quality: i.e. prevent breaking other parts of the product as it evolves. Note that bugs local to a specific feature will be counted against the author of that feature. However, if a new enhancement breaks the entire product, the whole team will have to share the penalty.
    3. Manage the project smoothly: i.e. ensure workflow, code maintenance, integration, releases, etc. are done smoothly.

    Admin Project: Constraints

    Your project should comply with the following constraints. Reason: to increase comparability among projects and to maximize applicability of module learning outcomes in the project.

    • Constraint-Morph: The final product should be a result of morphing the given code base. i.e. enhance and/or evolve the given code to arrive at the new software. However, you are allowed to replace all existing code with new code, as long as it is done incrementally. e.g. one feature/component at a time
      Reason: To ensure your code has a decent quality level from the start.

    • Constraint-Incremental: The product needs to be developed incrementally over the project duration. While it is fine to do less in some weeks and more in other weeks, a reasonably consistent delivery rate is expected. For example, it is not acceptable to do the entire project over the recess week and do almost nothing for the remainder of the semester. Reasons: 1. To simulate a real project where you have to work on a code base over a long period, possibly with breaks in the middle. 2. To learn how to deliver big features in small increments.

    • Constraint-CLI: Command Line Interface is the primary mode of input. The GUI should be used primarily to give visual feedback to the user rather than to collect input. Some minimal use of mouse is OK (e.g. to click the minimize button), but the primary input should be command-driven.
      • Mouse actions should have keyboard alternatives.
      • Typing is preferred over key combinations. Design the app in a way that you can do stuff faster by typing compared to mouse actions or key combinations.
      • One-shot commands are preferred over multi-step commands. If you provide a multi-step command to help new users, you should also provide a one-shot equivalent for regular users.  Reason: We want the user to be able to accomplish tasks faster using CLI than a GUI; having to enter commands part-by-part will slow down the user.
      • ❗️ While we don't prohibit GUI-only features, such features will be ignored during grading.
    • Constraint-Human-Editable-File: The data should be stored locally and should be in a human editable text file.
      Reason: To allow advanced users to manipulate the data by editing the data file.

    • Constraint-OO: The software should follow the Object-oriented paradigm.
      Reason: For you to practice using OOP in a non-trivial project.

    • Constraint-No-DBMS: Do not use a DBMS to store data.
      Reason: Using a DBMS to store data will reduce the room to apply OOP techniques to manage data. It is true that most real world systems use a DBMS, but given the small size of this project, we need to optimize it for TIC2002 module learning outcomes; covering DBMS-related LOs will have to be left to database modules or level 3 project modules.

    • Constraint-Platform-Independent: The software should work on the Windows, Linux, and OS-X platforms. Even if you are unable to manually test the app on all three platforms, consciously avoid using OS-dependent libraries and OS-specific features.
      Reason: Peer testers should be able to use any of these platforms.

    • Constraint-No-Installer: The software should work without requiring an installer. Having an optional installer is OK as long as the portable (non-installed) version has all the critical functionality.
      Reason: We do not want to install all your projects on our testing machines when we test them for grading.

    • Constraint-External-Software: The use of third-party frameworks/libraries is allowed but only if they,

      • are free, open-source, and have permissive license terms (E.g., trial version of libraries that require purchase after N days are not allowed).
      • do not require any installation by the user of your software.
      • do not violate other constraints.

      and is subjected to prior approval by the teaching team.
      Reason: We will not allow third-party software that can interfere with the learning objectives of the module.

      Please post in the forum your request to use a third-party libraries before you start using the library. Once a specific library has been approved for one team, other teams may use it without requesting permission again.
      Reason: The whole class should know which external software are used by others so that they can do the same if they wish to.

    Admin Project: Timeline

    To expedite your project implementation, you will be given some sample code (AddressBook-Level1 to AddressBook-Level4, shown as AB1 to AB4 in the diagram above). You can use AB1 to AB3 to ramp up your tech skills in preparation for the project. AB4 is to be used as the basis for your project.

    AB4 is the version you will use as the starting point for your final project. Some of the work you do in AB1 to AB3 can be ported over to AB4 and can be used to claim credit in the final project.

    Given below is the high-level timeline of the project.

    Week Stage Activities
    3 inception Decide on a overall project direction (user profile, problem addressed, optimize or morph?).
    4 mid-v1.0 Decide on requirements (user stories, use cases, non-functional requirements).
    5 v1.0 Conceptualize product and document it as a user guide(draft), draft a rough project plan.
    6 mid-v1.1 Set up project repo, start moving UG and DG to the repo, attempt to do local-impact changes to the code base.
    7 v1.1 Update UG and DG in the repo, update project plan in repo, attempt to do global-impact changes to the code base.
    8 mid-v1.2 Adjust project schedule/rigor as needed, complete repo set up, start proper milestone management.
    9 v1.2 Move code towards v2.0 in small steps, start documenting design/implementation details in DG.
    10 mid-v1.3 Continue to enhance features.
    11 v1.3 Release as a jar file, release updated user guide, peer-test released products, verify code authorship.
    12 mid-v1.4 Tweak as per peer-testing results, draft Project Portfolio Page, practice product demo.
    13 v1.4 Final tweaks to docs/product, release product, demo product, test/evaluate peer products.

    More details of each stage is provided elsewhere is this website.

    Admin A: Module Principles

    These are some of the main principles underlying the module structure.

    The product is you, NOT what you build.

    The software product you build is a side effect only. You are the product of this module. This means,

    • We may not take the most efficient route to building the software product. We take the route that allows you to learn the most.
    • Building a software product that is unique, creative, and shiny is not our priority (although we try to do a bit of that too). Learning to take pride in, and discovering the joy of, high quality software engineering work is our priority.

    Following from that, we evaluate you on not just how much you've done, but also, how well you've done those things. Here are some of the aspects in which we focus on:

    We appreciate ...

    But we value more ...

    Ability to deal with low-level details

    Ability to abstract over details, generalize, see the big picture

    A drive to learn latest and greatest technologies

    Ability to make the best of given tools

    Ability to find problems that interest you and solve them

    Ability to solve the given problem to the best of your ability

    Ability to burn the midnight oil to meet a deadline

    Ability to schedule work so that the need for 'last minute heroics' is minimal

    Preference to do things you like or things you are good at

    Ability to buckle down and deliver on important things that you don't necessarily like or aren't good at

    Ability to deliver desired end results

    Ability to deliver in a way that shows how well you delivered (i.e. visibility of your work)

    We learn together, NOT compete against each other.

    You are not in a competition. Our grading is not forced on a bell curve.

    Learn from each other. That is why we open-source your submissions.

    Teach each other, even those in other teams. Those who do it well can become tutors next time.

    Continuously engage, NOT last minute heroics.

    We want to train you to do software engineering in a steady and repeatable manner that does not require 'last minute heroics'.

    In this module, last minute heroics will not earn you a good project grade, and last minute mugging will not earn you a good exam grade.

    Where you reach at the end matters, NOT what you knew at the beginning.

    When you start the module, some others in the class may appear to know a lot more than you. Don't let that worry you. The final grade depends on what you know at the end, not what you knew to begin with. All marks allocated to intermediate deliverables are within the reach of everyone in the class irrespective of their prior knowledge.

    Admin Appendix C (FAQs) → Why you force me to visit a separate website instead of using IVLE?

    Why you force me to visit a separate website instead of using IVLE?

    We have a separate website because some of the module information does not fit into the structure imposed by IVLE.

    On a related note, keep in mind that 'hunting and gathering' of relevant information is one of the skills you need to survive 'in the wild'. Do not always expect all relevant materials to appear 'magically' in some kind of 'work bin'.

    Admin Appendix C (FAQs) → Why slides are not detailed?

    Why slides are not detailed?

    Slides are not meant to be documents to print and study for exams. Their purpose is to support the lecture delivery and keep you engaged during the lecture. That's why our slides are less detailed and more visual.

    Admin Appendix C (FAQs) → Why so much self-study?

    Why so much self-study?

    Self-study is a critical survival skill in SE industry. Lectures will show you the way, but absorbing content is to be done at your own pace, by yourself. In this module, we still tell you what content to study and also pass most of the content to you. After you graduate, you have to decide what to study and find your own content too.

    Outcomes

    OOP

    W2.1 Can explain OOP W2.1a Can describe OOP at a higher level

    Paradigms → Object Oriented Programming → Introduction →

    What

    Object-Oriented Programming (OOP) is a programming paradigm. A programming paradigm guides programmers to analyze programming problems, and structure programming solutions, in a specific way.

    Programming languages have traditionally divided the world into two parts—data and operations on data. Data is static and immutable, except as the operations may change it. The procedures and functions that operate on data have no lasting state of their own; they’re useful only in their ability to affect data.

    This division is, of course, grounded in the way computers work, so it’s not one that you can easily ignore or push aside. Like the equally pervasive distinctions between matter and energy and between nouns and verbs, it forms the background against which we work. At some point, all programmers—even object-oriented programmers—must lay out the data structures that their programs will use and define the functions that will act on the data.

    With a procedural programming language like C, that’s about all there is to it. The language may offer various kinds of support for organizing data and functions, but it won’t divide the world any differently. Functions and data structures are the basic elements of design.

    Object-oriented programming doesn’t so much dispute this view of the world as restructure it at a higher level. It groups operations and data into modular units called objects and lets you combine objects into structured networks to form a complete program. In an object-oriented programming language, objects and object interactions are the basic elements of design.

    -- Object-Oriented Programming with Objective-C, Apple

    Some other examples of programming paradigms are:

    Paradigm Programming Languages
    Procedural Programming paradigm C
    Functional Programming paradigm F#, Haskel, Scala
    Logic Programming paradigm Prolog

    Some programming languages support multiple paradigms.

    Java is primarily an OOP language but it supports limited forms of functional programming and it can be used to (although not recommended) write procedural code.  e.g. se-edu/addressbook-level1

    JavaScript and Python support functional, procedural, and OOP programming.

    A) Choose the correct statements

    • a. OO is a programming paradigm
    • b. OO guides us in how to structure the solution
    • c. OO is mainly an abstraction mechanism
    • d. OO is a programming language
    • e. OO is modeled after how the objects in real world work

    B) Choose the correct statements

    • a. Java and C++ are OO languages
    • b. C language follows the Functional Programming paradigm
    • c. Java can be used to write procedural code
    • d. Prolog follows the Logic Programming paradigm

    A) (a)(b)(c)(e)

    Explanation: While many languages support the OO paradigm, OO is not a language itself.

    B) Choose the correct statement

    (a)(b)(c)(d)

    Explanation: C follows the procedural paradigm. Yes, we can write procedural code using OO languages e.g., AddressBook-level1.

    OO is a higher level mechanism than the procedural paradigm.

    True.

    Explanation: Procedural languages work at simple data structures (e.g., integers, arrays) and functions level. Because an object is an abstraction over data+related functions, OO works at a higher level.

    W2.1b Can describe how OOP relates to the real world

    Paradigms → Object Oriented Programming → Objects →

    What

    Every object has both state (data) and behavior (operations on data). In that, they’re not much different from ordinary physical objects. It’s easy to see how a mechanical device, such as a pocket watch or a piano, embodies both state and behavior. But almost anything that’s designed to do a job does, too. Even simple things with no moving parts such as an ordinary bottle combine state (how full the bottle is, whether or not it’s open, how warm its contents are) with behavior (the ability to dispense its contents at various flow rates, to be opened or closed, to withstand high or low temperatures).

    It’s this resemblance to real things that gives objects much of their power and appeal. They can not only model components of real systems, but equally as well fulfill assigned roles as components in software systems.

    -- Object-Oriented Programming with Objective-C, Apple

    Object Oriented Programming (OOP) views the world as a network of interacting objects.

    A real world scenario viewed as a network of interacting objects:

    You are asked to find out the average age of a group of people Adam, Beth, Charlie, and Daisy. You take a piece of paper and pen, go to each person, ask for their age, and note it down. After collecting the age of all four, you enter it into a calculator to find the total. And then, use the same calculator to divide the total by four, to get the average age. This can be viewed as the objects You, Pen, Paper, Calculator, Adam, Beth, Charlie, and Daisy interacting to accomplish the end result of calculating the average age of the four persons. These objects can be considered as connected in a certain network of certain structure.

    OOP solutions try to create a similar object network inside the computer’s memory – a sort of a virtual simulation of the corresponding real world scenario – so that a similar result can be achieved programmatically.

    OOP does not demand that the virtual world object network follow the real world exactly.

    Our previous example can be tweaked a bit as follows:

    • Use an object called Main to represent your role in the scenario.
    • As there is no physical writing involved, we can replace the Pen and Paper with an object called AgeList that is able to keep a list of ages.

    Every object has both state (data) and behavior (operations on data).

    Object Real World? Virtual World? Example of State (i.e. Data) Examples of Behavior (i.e. Operations)
    Adam Name, Date of Birth Calculate age based on birthday
    Pen - Ink color, Amount of ink remaining Write
    AgeList - Recorded ages Give the number of entries, Accept an entry to record
    Calculator Numbers already entered Calculate the sum, divide
    You/Main Average age, Sum of ages Use other objects to calculate

    Every object has an interface and an implementation.

    Every real world object has:

    • an interface that other objects can interact with
    • an implementation that supports the interface but may not be accessible to the other object

    The interface and implementation of some real-world objects in our example:

    • Calculator: the buttons and the display are part of the interface; circuits are part of the implementation.
    • Adam: In the context of our 'calculate average age' example, the interface of Adam consists of requests that adam will respond to, e.g. "Give age to the nearest year, as at Jan 1st of this year" "State your name"; the implementation includes the mental calculation Adam uses to calculate the age which is not visible to other objects.

    Similarly, every object in the virtual world has an interface and an implementation.

    The interface and implementation of some virtual-world objects in our example:

    • Adam: the interface might have a method getAge(Date asAt); the implementation of that method is not visible to other objects.

    Objects interact by sending messages.

    Both real world and virtual world object interactions can be viewed as objects sending message to each other. The message can result in the sender object receiving a response and/or the receiving object’s state being changed. Furthermore, the result can vary based on which object received the message, even if the message is identical (see rows 1 and 2 in the example below).

    Examples:

    World Sender Receiver Message Response State Change
    Real You Adam "What is your name?" "Adam" -
    Real as above Beth as above "Beth" -
    Real You Pen Put nib on paper and apply pressure Makes a mark on your paper Ink level goes down
    Virtual Main Calculator (current total is 50) add(int i): int i = 23 73 total = total + 23

    Consider the following real-world scenario.

    Tom read a Software Engineering textbook (he has been assigned to read the book) and highlighted some of the text in it.  

    Explain the following statements about OOP using the above scenario as an example.

    1. Object Oriented Programming (OOP) views the world as a network of interacting objects.
    2. Every object has both state (data) and behavior (operations on data).
    3. Every object has an interface and an implementation.
    4. Objects interact by sending messages.
    5. OOP does not demand that the virtual world object network follow the real world exactly.

    [1] Object Oriented Programming (OOP) views the world as a network of interacting objects.

    Interacting objects in the scenario: Tom, SE Textbook (Book for short), Text, (possibly) Highlighter

    💡 objects usually match nouns in the description

    [2]Every object has both state (data) and behavior (operations on data).

    Object Examples of state Examples of behavior
    Tom memory of the text read read
    Book title show text
    Text font size get highlighted

    [3] Every object has an interface and an implementation.

    • Interface of an object consists of how other objects interact with it i.e., what other objects can do to that object
    • Implementation consist of internals of the object that facilitate the interactions but not visible to other objects.
    Object Examples of interface Examples of implementation
    Tom receive reading assignment understand/memorize the text read, remember the reading assignment
    Book show text, turn page how pages are bound to the spine
    Text read how characters/words are connected together or fixed to the book

    [4] Objects interact by sending messages.

    Examples:

    • Tom sends message turn page to the Book
    • Tom sends message show text to the Book. When the Book shows the Text, Tom sends the message read to the Text which returns the text content to Tom.
    • Tom sends message highlight to the Highlighter while specifying which Text to highlight. Then the Highlighter sends the message highlight to the specified Text.

    [5] OOP does not demand that the virtual world object network follow the real world exactly.

    Examples:

    • A virtual world simulation of the above scenario can omit the Highlighter object. Instead, we can teach Text to highlight themselves when requested.

    Evidence:

    Consider the following real-world scenario.

    Tom read a Software Engineering textbook (he has been assigned to read the book) and highlighted some of the text in it.  

    Explain the following statements about OOP using the above scenario as an example.

    1. Object Oriented Programming (OOP) views the world as a network of interacting objects.
    2. Every object has both state (data) and behavior (operations on data).
    3. Every object has an interface and an implementation.
    4. Objects interact by sending messages.
    5. OOP does not demand that the virtual world object network follow the real world exactly.

    [1] Object Oriented Programming (OOP) views the world as a network of interacting objects.

    Interacting objects in the scenario: Tom, SE Textbook (Book for short), Text, (possibly) Highlighter

    💡 objects usually match nouns in the description

    [2]Every object has both state (data) and behavior (operations on data).

    Object Examples of state Examples of behavior
    Tom memory of the text read read
    Book title show text
    Text font size get highlighted

    [3] Every object has an interface and an implementation.

    • Interface of an object consists of how other objects interact with it i.e., what other objects can do to that object
    • Implementation consist of internals of the object that facilitate the interactions but not visible to other objects.
    Object Examples of interface Examples of implementation
    Tom receive reading assignment understand/memorize the text read, remember the reading assignment
    Book show text, turn page how pages are bound to the spine
    Text read how characters/words are connected together or fixed to the book

    [4] Objects interact by sending messages.

    Examples:

    • Tom sends message turn page to the Book
    • Tom sends message show text to the Book. When the Book shows the Text, Tom sends the message read to the Text which returns the text content to Tom.
    • Tom sends message highlight to the Highlighter while specifying which Text to highlight. Then the Highlighter sends the message highlight to the specified Text.

    [5] OOP does not demand that the virtual world object network follow the real world exactly.

    Examples:

    • A virtual world simulation of the above scenario can omit the Highlighter object. Instead, we can teach Text to highlight themselves when requested.
    W2.1c Can explain the relationship between classes and objects

    Paradigms → Object Oriented Programming → Classes →

    Basic

    Writing an OOP program is essentially writing instructions that the computer uses to,

    1. create the virtual world of object network, and
    2. provide it the inputs to produce the outcome we want.

    A class contains instructions for creating a specific kind of objects. It turns out sometimes multiple objects have the same behavior because they are of the same kind. Instructions for creating a one kind (or ‘class’) of objects can be done once and that same instructions can be used to instantiate objects of that kind. We call such instructions a Class.

    Classes and objects in an example scenario

    Consider the example of writing an OOP program to calculate the average age of Adam, Beth, Charlie, and Daisy.

    Instructions for creating objects Adam, Beth, Charlie, and Daisy will be very similar because they are all of the same kind : they all represent ‘persons’ with the same interface, the same kind of data (i.e. name, DoB, etc.), and the same kind of behavior (i.e. getAge(Date), getName(), etc.). Therefore, we can have a class called Person containing instructions on how to create Person objects and use that class to instantiate objects Adam, Beth, Charlie, and Daisy.

    Similarly, we need classes AgeList, Calculator, and Main classes to instantiate one each of AgeList, Calculator, and Main objects.

    Class Objects
    Person objects representing Adam, Beth, Charlie, Daisy
    AgeList an object to represent the age list
    Calculator an object to do the calculations
    Main an object to represent you who manages the whole operation

    Consider the following scenario. If you were to simulate this in an OOP program, what are the classes and the objects you would use?

      A customer (name: John) gave a cheque to the Cashier (name: Peter) to pay for the LoTR and GoT books he bought.
    Class Objects
    Customer john
    Book LoTR, GoT
    Cheque checqueJohnGave
    Cashier peter

    Assume you are writing a CLI program called CityConnect for storing and querying distances between cities. The behavior is as follows:

    Welcome to CityConnect!
    
    Enter command: addroute Clementi BuonaVista 12
    Route from Clementi to BuonaVista with distance 12km added
    
    Enter command: getdistance Clementi BuonaVista
    Distance from Clementi to BuonaVista is 12
    
    Enter command: getdistance Clementi JurongWest
    No route exists from Clementi to JurongWest!
    
    Enter command: addroute Clementi JurongWest 24
    Route from Clementi to JurongWest with distance 24km added
    
    Enter command: getdistance Clementi JurongWest
    Distance from Clementi to JurongWest is 24
    
    Enter command: exit
    
    

    What classes would you have in your code if you write your program based on the OOP paradigm?

    One class you can have is Route


    Evidence:

    Consider the following scenario. If you were to simulate this in an OOP program, what are the classes and the objects you would use?

      A customer (name: John) gave a cheque to the Cashier (name: Peter) to pay for the LoTR and GoT books he bought.
    Class Objects
    Customer john
    Book LoTR, GoT
    Cheque checqueJohnGave
    Cashier peter
    W2.1d Can explain the abstraction aspect of OOP

    Paradigms → Object Oriented Programming → Objects →

    Objects as Abstractions

    The concept of Objects in OOP is an abstraction mechanism because it allows us to abstract away the lower level details and work with bigger granularity entities i.e. ignore details of data formats and the method implementation details and work at the level of objects.

     

    Abstraction is a technique for dealing with complexity. It works by establishing a level of complexity we are interested in, and suppressing the more complex details below that level.

    We can deal with a Person object that represents the person Adam and query the object for Adam's age instead of dealing with details such as Adam’s date of birth (DoB), in what format the DoB is stored, the algorithm used to calculate the age from the DoB, etc.

    W2.1e Can explain the encapsulation aspect of OOP

    Paradigms → Object Oriented Programming → Objects →

    Encapsulation Of Objects

    Encapsulation protects an implementation from unintended actions and from inadvertent access.
    -- Object-Oriented Programming with Objective-C, Apple

    An object is an encapsulation of some data and related behavior in two aspects:

    1. The packaging aspect: An object packages data and related behavior together into one self-contained unit.

    2. The information hiding aspect: The data in an object is hidden from the outside world and are only accessible using the object's interface.

    Choose the correct statements

    • a. An object is an encapsulation because it packages data and behavior into one bundle.
    • b. An object is an encapsulation because it lets us think in terms of higher level concepts such as Students rather than student-related functions and data separately.

    Don't confuse encapsulation with abstraction.

    Choose the correct statement

    (a)

    Explanation: The second statement should be: An object is an abstraction encapsulation because it lets ...

    W2.1f Can explain class-level members

    Paradigms → Object Oriented Programming → Classes →

    Class-Level Members

    While all objects of a class has the same attributes, each object has its own copy of the attribute value.

    All Person objects have the Name attribute but the value of that attribute varies between Person objects.

    However, some attributes are not suitable to be maintained by individual objects. Instead, they should be maintained centrally, shared by all objects of the class. They are like ‘global variables’ but attached to a specific class. Such variables whose value is shared by all instances of a class are called class-level attributes.

    The attribute totalPersons should be maintained centrally and shared by all Person objects rather than copied at each Person object.

    Similarly, when a normal method is being called, a message is being sent to the receiving object and the result may depend on the receiving object.

    Sending the getName() message to Adam object results in the response "Adam" while sending the same message to the Beth object gets the response "Beth".

    However, there can be methods related to a specific class but not suitable for sending message to a specific object of that class. Such methods that are called using the class instead of a specific instance are called class-level methods.

    The method getTotalPersons() is not suitable to send to a specific Person object because a specific object of the Person class should not know about the total number of Person objects.

    Class-level attributes and methods are collectively called class-level members (also called static members sometimes because some programming languages use the keyword static to identify class-level members). They are to be accessed using the class name rather than an instance of the class.

    Which of these are suitable as class-level variables?

    • a. system: multi-player Pac Man game, Class: Player, variable: totalScore
    • b. system: eLearning system, class: Course, variable: totalStudents
    • c. system: ToDo manager, class: Task, variable: totalPendingTasks
    • d. system: any, class: ArrayList, variable: total (i.e., total items in a given ArrayList object)

    (c)

    Explanation: totalPendingTasks should not be managed by individual Task objects and therefore suitable to be maintained as a class-level variable. The other variables should be managed at instance level as their value varies from instance to instance. e.g., totalStudents for one Course object will differ from totalStudents of another.

    Implementation

    W2.2 Can use Java objects W2.2a Can use in-built Java objects

    C++ to Java → Objects →

    Using Java Objects

    Java is an "object-oriented" language, which means that it uses objects to represent data and provide methods related to them. Object types are called classes e.g., you can use String objects in Java and those objects belong to the String class.

    importing

    Java comes with many inbuilt classes which are organized into packages. Here are some examples:

    package Some example classes in the package
    java.lang String, Math, System

    Before using a class in your code, you need to import the class. import statements appear at the top of the code.

    This example imports the java.awt.Point (i.e., the Point class in the java.awt package) class -- which can be used to represent the coordinates of a location in a Cartesian plane -- and use it in the main method.

     

    In mathematical notation, points are often written in parentheses with a comma separating the coordinates. For example, (0,0) indicates the origin, and (x,y) indicates the point x units to the right and y units up from the origin.  

    import java.awt.Point;
    
    public class Main{
        public static void main(String[] args) {
            Point spot = new Point(3, 4);
            int x = spot.x;
            System.out.println(x);
       }
    }
    

    💡 You might wonder why we can use the System class without importing it. System belongs to the java.lang package, which is imported automatically.

    new operator

    To create a new object, you have to use the new operator

    This line shows how to create a new Point object using the new operator:

    Point spot = new Point(3, 4);
    

    Update the code below to create a new Rectangle object as described in the code comments, to produce the given output.

    • The Rectangle class is found in the java.awt package.
    • The parameters you need to supply when creating new Rectangle objects are (int x, int y, int width, int height).
    public class Main {
        public static void main(String[] args) {
            Rectangle r;
    
            // TODO create a Rectangle object that has the properties x=0, y=0, width=5, height=10
            // assign it to r
    
            System.out.println(r);
        }
    }
    

    java.awt.Rectangle[x=0,y=0,width=5,height=10]
    
    • Import the java.awt.Rectangle class
    • This is how you create the required object new Rectangle(0, 0, 5, 10)

    Evidence:

    To be able to do exercises such as these:

    Update the code below to create a new Rectangle object as described in the code comments, to produce the given output.

    • The Rectangle class is found in the java.awt package.
    • The parameters you need to supply when creating new Rectangle objects are (int x, int y, int width, int height).
    public class Main {
        public static void main(String[] args) {
            Rectangle r;
    
            // TODO create a Rectangle object that has the properties x=0, y=0, width=5, height=10
            // assign it to r
    
            System.out.println(r);
        }
    }
    

    java.awt.Rectangle[x=0,y=0,width=5,height=10]
    
    • Import the java.awt.Rectangle class
    • This is how you create the required object new Rectangle(0, 0, 5, 10)
    W2.2b Can use instance members of objects

    C++ to Java → Objects →

    Instance Members

    Variables that belong to an object are called attributes (or fields).

    To access an attribute of an object, Java uses dot notation.

    The code below uses spot.x which means "go to the object spot refers to, and get the value of the attribute x."

    Point spot = new Point(3, 4);
    int sum = spot.x * spot.x + spot.y * spot.y;
    System.out.println(spot.x + ", " + spot.y + ", " + sum);
    

    3, 4, 25
    

    You can mutate an object by assigning a different values to its attributes.

    This example changes the x value of the Point object to 5.

    Point spot = new Point(3, 4);
    spot.x = 5;
    System.out.println(spot.x + ", " + spot.y);
    

    5, 4
    

    Java uses the dot notation to invoke methods on an object too.

    This example invokes the translate method on a Point object so that it moves to a different location.

    Point spot = new Point(3, 4);
    System.out.println(spot.x + ", " + spot.y);
    spot.translate(5,5);
    System.out.println(spot.x + ", " + spot.y);
    

    3, 4
    8, 9
    

    Update the code below as described in code comments, to produce the given output.

    import java.awt.Rectangle;
    
    public class Main {
        public static void main(String[] args) {
            Rectangle r = new Rectangle(0, 0, 4, 6);
            System.out.println(r);
    
            int area;
            //TODO: add a line below to calculate the area using width and height properties of r
            // and assign it to the variable area
    
            System.out.println("Area: " + area);
    
            //TODO: add a line here to set the size of r to 8x10 (width x height)
            //Recommended: use the setSize(int height, int width) method of the Rectangle object
    
            System.out.println(r);
        }
    
    }
    

    java.awt.Rectangle[x=0,y=0,width=4,height=6]
    Area: 24
    java.awt.Rectangle[x=0,y=0,width=8,height=10]
    
    • Area can be calculated as r.width * r.height
    • Setting the size can be done as r.setSize(8, 10)

    Evidence:

    To be able to do exercises such as these:

    Update the code below as described in code comments, to produce the given output.

    import java.awt.Rectangle;
    
    public class Main {
        public static void main(String[] args) {
            Rectangle r = new Rectangle(0, 0, 4, 6);
            System.out.println(r);
    
            int area;
            //TODO: add a line below to calculate the area using width and height properties of r
            // and assign it to the variable area
    
            System.out.println("Area: " + area);
    
            //TODO: add a line here to set the size of r to 8x10 (width x height)
            //Recommended: use the setSize(int height, int width) method of the Rectangle object
    
            System.out.println(r);
        }
    
    }
    

    java.awt.Rectangle[x=0,y=0,width=4,height=6]
    Area: 24
    java.awt.Rectangle[x=0,y=0,width=8,height=10]
    
    • Area can be calculated as r.width * r.height
    • Setting the size can be done as r.setSize(8, 10)
    W2.2c Can pass objects between methods

    C++ to Java → Objects →

    Passing Objects Around

    You can pass objects as parameters to a method in the usual way.

    The printPoint method below takes a Point object as an argument and displays its attributes in (x,y) format.

    public static void printPoint(Point p) {
        System.out.println("(" + p.x + ", " + p.y + ")");
    }
    
    public static void main(String[] args) {
        Point spot = new Point(3, 4);
        printPoint(spot);
    }
    

    3, 4
    

    You can return an object from a method too.

    The java.awt package also provides a class called Rectangle. Rectangle objects are similar to points, but they have four attributes: x, y, width, and height. The findCenter method below takes a Rectangle as an argument and returns a Point that corresponds to the center of the rectangle:

    public static Point findCenter(Rectangle box) {
        int x = box.x + box.width / 2;
        int y = box.y + box.height / 2;
        return new Point(x, y);
    }
    

    The return type of this method is Point. The last line creates a new Point object and returns a reference to it.

    null and NullPointerException

    null is a special value that means "no object". You can assign null to a variable to indicate that the variable is 'empty' at the moment. However, if you try to use a null value, either by accessing an attribute or invoking a method, Java throws a NullPointerException.

    In this example, the variable spot is assigned a null value. As a result, trying to access spot.x attribute or invoke spot.translate method results in a NullPointerException.

    Point spot = null;
    int x = spot.x;          // NullPointerException
    spot.translate(50, 50);  // NullPointerException
    

    On the other hand, it is legal return null from a method or to pass a null reference as an argument to a method.

    Returning null from a method.

    public static Point createCopy(Point p) {
        if (p == null) {
            return null; // return null if p is null
        }
    
        // create a new object with same x,y values
        return new Point(p.x, p.y);
    }
    

    Passing null as the argument.

    Point result = createCopy(null);
    System.out.println(result);
    

    null
    

    It is possible to have multiple variables that refer to the same object.

    Notice how p1 and p2 are aliases for the same object. When the object is changed using the variable p1, the changes are visible via p2 as well (and vice versa), because they both point to the same Point object.

    Point p1 = new Point(0,0);
    Point p2 = p1;
    System.out.println("p1: " + p1.x + ", " + p1.y);
    System.out.println("p2: " + p2.x + ", " + p2.y);
    p1.x = 1;
    p2.y = 2;
    System.out.println("p1: " + p1.x + ", " + p1.y);
    System.out.println("p2: " + p2.x + ", " + p2.y);
    

    p1: 0, 0
    p2: 0, 0
    p1: 1, 2
    p2: 1, 2
    

    Java does not have explicit pointers (and other related things such as pointer de-referencing, pointer arithmetic). When an object is passed into a method as an argument, the method gains access to the original object. If the method changes the object it received, the changes are retained in the object even after the method is completed.

    Note how p3 retains changes done to it by the method swapCoordinates even after the method call.

    public static void swapCoordinates(Point p){
        int temp = p.x;
        p.x = p.y;
        p.y = temp;
    }
    
    public static void main(String[] args) {
        Point p3 = new Point(2,3);
        System.out.println("p3: " + p3.x + ", " + p3.y);
        swapCoordinates(p3);
        System.out.println("p3: " + p3.x + ", " + p3.y);
    }
    
    p3: 2, 3
    p3: 3, 2
    

    Add a method move(Point p, Rectangle r) to the code below, to produce the given output. The behavior of the method is as follows:

    • Returns a new Point object that has attributes x and y that match those of r
    • Does not modify p
    • Updates r so that its attributes x and y match those of p
    • Returns null and does nothing if either p or r is null
    import java.awt.Point;
    import java.awt.Rectangle;
    
    public class Main {
    
        //TODO add your method here
    
        public static void main(String[] args) {
            Point p1 = new Point(0, 0);
            Rectangle r1 = new Rectangle(2, 3, 5, 6);
            System.out.println("arguments: " + p1 + ", " + r1);
    
            Point p2 = move(p1, r1);
            System.out.println("argument point after method call: " + p1);
            System.out.println("argument rectangle after method call: " + r1);
            System.out.println("returned point: " + p2);
    
            System.out.println(move(null, null));
        }
    }
    

    arguments: java.awt.Point[x=0,y=0], java.awt.Rectangle[x=2,y=3,width=5,height=6]
    argument point after method call: java.awt.Point[x=0,y=0]
    argument rectangle after method call: java.awt.Rectangle[x=0,y=0,width=5,height=6]
    returned point: java.awt.Point[x=2,y=3]
    null
    

    Partial solution:

    public static Point move(Point p, Rectangle r){
        if (p == null || r == null){
            // ...
        }
        Point newPoint = new Point(r.x, r.y);
        r.x = p.x;
        // ...
        return newPoint;
    }
    

    Evidence:

    To be able to do exercises such as these:

    Add a method move(Point p, Rectangle r) to the code below, to produce the given output. The behavior of the method is as follows:

    • Returns a new Point object that has attributes x and y that match those of r
    • Does not modify p
    • Updates r so that its attributes x and y match those of p
    • Returns null and does nothing if either p or r is null
    import java.awt.Point;
    import java.awt.Rectangle;
    
    public class Main {
    
        //TODO add your method here
    
        public static void main(String[] args) {
            Point p1 = new Point(0, 0);
            Rectangle r1 = new Rectangle(2, 3, 5, 6);
            System.out.println("arguments: " + p1 + ", " + r1);
    
            Point p2 = move(p1, r1);
            System.out.println("argument point after method call: " + p1);
            System.out.println("argument rectangle after method call: " + r1);
            System.out.println("returned point: " + p2);
    
            System.out.println(move(null, null));
        }
    }
    

    arguments: java.awt.Point[x=0,y=0], java.awt.Rectangle[x=2,y=3,width=5,height=6]
    argument point after method call: java.awt.Point[x=0,y=0]
    argument rectangle after method call: java.awt.Rectangle[x=0,y=0,width=5,height=6]
    returned point: java.awt.Point[x=2,y=3]
    null
    

    Partial solution:

    public static Point move(Point p, Rectangle r){
        if (p == null || r == null){
            // ...
        }
        Point newPoint = new Point(r.x, r.y);
        r.x = p.x;
        // ...
        return newPoint;
    }
    
    W2.2d Can explain Java garbage collection

    C++ to Java → Objects →

    Garbage Collection

    What happens when no variables refer to an object?

    Point spot = new Point(3, 4);
    spot = null;
    

    The first line creates a new Point object and makes spot refer to it. The second line changes spot so that instead of referring to the object, it refers to nothing. If there are no references to an object, there is no way to access its attributes or invoke a method on it. From the programmer’s view, it ceases to exist. However it’s still present in the computer’s memory, taking up space.

    In Java, you don’t have to delete objects you create when they are no longer needed. As your program runs, the system automatically looks for stranded objects and reclaims them; then the space can be reused for new objects. This process is called garbage collection. You don’t have to do anything to make garbage collection happen, and in general don’t have to be aware of it. But in high-performance applications, you may notice a slight delay every now and then when Java reclaims space from discarded objects.

    W2.3 Can write Java classes W2.3a Can define Java classes

    C++ to Java → Classes →

    Defining Classes

    As you know,

    • Defining a class creates a new object type with the same name.
    • Every object belongs to some object type; that is, it is an instance of some class.
    • A class definition is like a template for objects: it specifies what attributes the objects have and what methods can operate on them.
    • The new operator instantiates objects, that is, it creates new instances of a class.
    • The methods that operate on an object type are defined in the class for that object.

    Here's a class called Time, intended to represent a moment in time. It has three attributes and no methods.

    public class Time {
        private int hour;
        private int minute;
        private int second;
    }
    

    You can give a class any name you like. The Java convention is to use PascalCase format for class names.

    The code should be in a file whose name matches the class e.g., the Time class should be in a file named Time.java.

    When a class is public (e.g., the Time class in the above example) it can be used in other classes. But the instance variables that are private (e.g., the hour, minute and second attributes of the Time class) can only be accessed from inside the Time class.

    Constructos

    The syntax for constructors is similar to that of other methods, except:

    • The name of the constructor is the same as the name of the class.
    • The keyword static is omitted.
    • Do not return anything. A constructor returns the created object by default.

    When you invoke new, Java creates the object and calls your constructor to initialize the instance variables. When the constructor is done, new returns a reference to the new object.

    Here is an example constructor for the Time class:

    public Time() {
        hour = 0;
        minute = 0;
        second = 0;
    }
    

    This constructor does not take any arguments. Each line initializes an instance variable to zero (which in this example means midnight). Now you can create Time objects.

    Time time = new Time();

    Like other methods, constructors can be overloaded, which means you can provide multiple constructors with different parameters.

    You can add another constructor to the Time class to allow creating Time objects that are initialized to a specific time:

    public Time(int h, int m, int s) {
        hour = h;
        minute = m;
        second = s;
    }
    

    Here's how you can invoke the new constructor:

    Time justBeforeMidnight = new Time(11, 59, 59);
    
    this keyword

    The this keyword is a reference variable in Java that refers to the current object. You can use this the same way you use the name of any other object. For example, you can read and write the instance variables of this, and you can pass this as an argument to other methods. But you do not declare this, and you can’t make an assignment to it.

    In the following version of the constructor, the names and types of the parameters are the same as the instance variables (parameters don’t have to use the same names, but that’s a common style). As a result, the parameters shadow (or hide) the instance variables, so the keyword this is necessary to tell them apart.

    public Time(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }
    

    this can be used to refer to a constructor of a class within the same class too.

    In this example the constructor Time() uses the this keyword to call its own overloaded constructor Time(int, int, int)

    public Time() {
        this(0, 0, 0); // call the overloaded constructor
    }
    
    public Time(int hour, int minute, int second) {
        // ...
    }
    
    
    Instance methods

    You can add methods to a class which can then be used from the objects of that class. These instance methods do not have the static keyword in the method signature. Instance methods can access attributes of the class.

    Here's how you can add a method to the Time class to get the number of seconds passed till midnight.

    public int secondsSinceMidnight() {
        return hour*60*60 + minute*60 + second;
    }
    

    Here's how you can use that method.

    Time t = new Time(0, 2, 5);
    System.out.println(t.secondsSinceMidnight() + " seconds since midnight!");
    

    Define a Circle class so that the code given below produces the given output. The nature of the class is a follows:

    • Attributes(all private):
      • int x, int y: represents the location of the circle
      • double radius: the radius of the circle
    • Constructors:
      • Circle(): initializes x, y, radius to 0
      • Circle(int x, int y, double radius): initializes the attributes to the given values
    • Methods:
      • getArea(): int
        Returns the area of the circle as an int value (not double). Calculated as 2xPIx(radius)2
        💡 You can convert to double to an int using (int) e.g., x = (int)2.25 gives x the value 2.
        💡 You can use Math.PI to get the value of Pi
        💡 You can use Math.pow() to raise a number to a specific power e.g., Math.pow(3, 2) calculates 32
    public class Main {
        public static void main(String[] args) {
            Circle c = new Circle();
    
            System.out.println(c.getArea());
            c = new Circle(1, 2, 5);
            System.out.println(c.getArea());
    
        }
    }
    

    0
    78
    
    • Put the Circle class in a file called Circle.java

    Partial solution:

    public class Circle {
        private int x;
        // ...
    
        public Circle(){
            this(0, 0, 0);
        }
    
        public Circle(int x, int y, double radius){
            this.x = x;
            // ...
        }
    
        public int getArea(){
            double area = Math.PI * Math.pow(radius, 2);
            return (int)area;
        }
    
    }
    

    Evidence:

    To be able to do exercises such as these:

    Define a Circle class so that the code given below produces the given output. The nature of the class is a follows:

    • Attributes(all private):
      • int x, int y: represents the location of the circle
      • double radius: the radius of the circle
    • Constructors:
      • Circle(): initializes x, y, radius to 0
      • Circle(int x, int y, double radius): initializes the attributes to the given values
    • Methods:
      • getArea(): int
        Returns the area of the circle as an int value (not double). Calculated as 2xPIx(radius)2
        💡 You can convert to double to an int using (int) e.g., x = (int)2.25 gives x the value 2.
        💡 You can use Math.PI to get the value of Pi
        💡 You can use Math.pow() to raise a number to a specific power e.g., Math.pow(3, 2) calculates 32
    public class Main {
        public static void main(String[] args) {
            Circle c = new Circle();
    
            System.out.println(c.getArea());
            c = new Circle(1, 2, 5);
            System.out.println(c.getArea());
    
        }
    }
    

    0
    78
    
    • Put the Circle class in a file called Circle.java

    Partial solution:

    public class Circle {
        private int x;
        // ...
    
        public Circle(){
            this(0, 0, 0);
        }
    
        public Circle(int x, int y, double radius){
            this.x = x;
            // ...
        }
    
        public int getArea(){
            double area = Math.PI * Math.pow(radius, 2);
            return (int)area;
        }
    
    }
    
    W2.3b Can define getters and setters

    C++ to Java → Classes →

    Getters and setters

    As the instance variables of Time are private, you can access them from within the Time class only. To compensate, you can provide methods to access attributes:

    public int getHour() {
        return hour;
    }
    
    public int getMinute() {
        return minute;
    }
    
    public int getSecond() {
        return second;
    }
    

    Methods like these are formally called “accessors”, but more commonly referred to as getters. By convention, the method that gets a variable named something is called getSomething.

    Similarly, you can provide setter methods to modify attributes of a Time object:

    public void setHour(int hour) {
        this.hour = hour;
    }
    
    public void setMinute(int minute) {
        this.minute = minute;
    }
    
    public void setSecond(int second) {
        this.second = second;
    }
    

    Consider the Circle class below:

    public class Circle {
        private int x;
        private int y;
        private double radius;
    
        public Circle(){
            this(0, 0, 0);
        }
    
        public Circle(int x, int y, double radius){
            this.x = x;
            this.y = y;
            this.radius = radius;
        }
    
        public int getArea(){
            double area = Math.PI * Math.pow(radius, 2);
            return (int)area;
        }
    
    }
    

    Update it as follows so that code given below produces the given output.

    • Add getter/setter methods for all three attributes
    • Update the setters and constructors such that if the radius supplied is negative, the code automatically set the radius to 0 instead.
    public class Main {
        public static void main(String[] args) {
            Circle c = new Circle(1,2, 5);
    
            c.setX(4);
            c.setY(5);
            c.setRadius(6);
            System.out.println("x      : " + c.getX());
            System.out.println("y      : " + c.getY());
            System.out.println("radius : " + c.getRadius());
            System.out.println("area   : " + c.getArea());
    
            c.setRadius(-5);
            System.out.println("radius : " + c.getRadius());
            c = new Circle(1, 1, -4);
            System.out.println("radius : " + c.getRadius());
    
        }
    }
    

    x      : 4
    y      : 5
    radius : 6.0
    area   : 113
    radius : 0.0
    radius : 0.0
    

    Partial solution:

    public Circle(int x, int y, double radius){
        setX(x);
        setY(y);
        setRadius(radius);
    }
    
    public void setRadius(double radius) {
        this.radius = Math.max(radius, 0);
    }
    

    Evidence:

    To be able to do exercises such as these:

    Consider the Circle class below:

    public class Circle {
        private int x;
        private int y;
        private double radius;
    
        public Circle(){
            this(0, 0, 0);
        }
    
        public Circle(int x, int y, double radius){
            this.x = x;
            this.y = y;
            this.radius = radius;
        }
    
        public int getArea(){
            double area = Math.PI * Math.pow(radius, 2);
            return (int)area;
        }
    
    }
    

    Update it as follows so that code given below produces the given output.

    • Add getter/setter methods for all three attributes
    • Update the setters and constructors such that if the radius supplied is negative, the code automatically set the radius to 0 instead.
    public class Main {
        public static void main(String[] args) {
            Circle c = new Circle(1,2, 5);
    
            c.setX(4);
            c.setY(5);
            c.setRadius(6);
            System.out.println("x      : " + c.getX());
            System.out.println("y      : " + c.getY());
            System.out.println("radius : " + c.getRadius());
            System.out.println("area   : " + c.getArea());
    
            c.setRadius(-5);
            System.out.println("radius : " + c.getRadius());
            c = new Circle(1, 1, -4);
            System.out.println("radius : " + c.getRadius());
    
        }
    }
    

    x      : 4
    y      : 5
    radius : 6.0
    area   : 113
    radius : 0.0
    radius : 0.0
    

    Partial solution:

    public Circle(int x, int y, double radius){
        setX(x);
        setY(y);
        setRadius(radius);
    }
    
    public void setRadius(double radius) {
        this.radius = Math.max(radius, 0);
    }
    
    W2.3c Can use class-level members

    C++ to Java → Classes →

    Class-Level Members

    The content below is an extract from -- Java Tutorial, with slight adaptations.

    When a number of objects are created from the same class blueprint, they each have their own distinct copies of instance variables. In the case of a Bicycle class, the instance variables are gear, and speed. Each Bicycle object has its own values for these variables, stored in different memory locations.

    Sometimes, you want to have variables that are common to all objects. This is accomplished with the static modifier. Fields that have the static modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.

    Suppose you want to create a number of Bicycle objects and assign each a serial number, beginning with 1 for the first object. This ID number is unique to each object and is therefore an instance variable. At the same time, you need a field to keep track of how many Bicycle objects have been created so that you know what ID to assign to the next one. Such a field is not related to any individual object, but to the class as a whole. For this you need a class variable, numberOfBicycles, as follows:

    public class Bicycle {
    
        private int gear;
        private int speed;
    
        // an instance variable for the object ID
        private int id;
    
        // a class variable for the number of Bicycle objects instantiated
        private static int numberOfBicycles = 0;
            ...
    }
    

    Class variables are referenced by the class name itself, as in Bicycle.numberOfBicycles This makes it clear that they are class variables.

    The Java programming language supports static methods as well as static variables. Static methods, which have the static modifier in their declarations, should be invoked with the class name, without the need for creating an instance of the class, as in ClassName.methodName(args)

    The static modifier, in combination with the final modifier, is also used to define constants. The final modifier indicates that the value of this field cannot change.For example, the following variable declaration defines a constant named PI, whose value is an approximation of pi (the ratio of the circumference of a circle to its diameter): static final double PI = 3.141592653589793;

    Here is an example with class-level variables and class-level methods:

    public class Bicycle {
    
        private int gear;
        private int speed;
    
        private int id;
    
        private static int numberOfBicycles = 0;
    
    
        public Bicycle(int startSpeed, int startGear) {
            gear = startGear;
            speed = startSpeed;
    
            numberOfBicycles++;
            id = numberOfBicycles;
        }
    
        public int getID() {
            return id;
        }
    
        public static int getNumberOfBicycles() {
            return numberOfBicycles;
        }
    
        public int getGear(){
            return gear;
        }
    
        public void setGear(int newValue) {
            gear = newValue;
        }
    
        public int getSpeed() {
            return speed;
        }
    
        // ...
    
    }
    

    💡 Explanation of System.out.println(...):

    • out is a class-level public attribute of the System class.
    • println is a instance level method of the out object.

    Consider the Circle class below:

    public class Circle {
        private int x;
        private int y;
        private double radius;
    
        public Circle(){
            this(0, 0, 0);
        }
    
        public Circle(int x, int y, double radius){
            setX(x);
            setY(y);
            setRadius(radius);
        }
    
        public int getX() {
            return x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public double getRadius() {
            return radius;
        }
    
        public void setRadius(double radius) {
            this.radius = Math.max(radius, 0);
        }
    
        public int getArea(){
            double area = Math.PI * Math.pow(radius, 2);
            return (int)area;
        }
    }
    

    Update it as follows so that code given below produces the given output.

    • Add a class-level getMaxRadius method that returns the maximum radius that has been used in all Circle objects created thus far.
    public class Main {
        public static void main(String[] args) {
            Circle c = new Circle();
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
            c = new Circle(0, 0, 10);
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
            c = new Circle(0, 0, -15);
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
            c.setRadius(12);
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
        }
    }
    

    max radius used so far : 0.0
    max radius used so far : 10.0
    max radius used so far : 10.0
    max radius used so far : 12.0
    

    You can use a static variable maxRadius to track the maximum value used for the radius attribute so far.

    Partial solution:

    public void setRadius(double radius) {
        this.radius = Math.max(radius, 0);
        if (maxRadius < this.radius){
            // ...
        }
    }
    

    Evidence:

    To be able to do exercises such as these:

    Consider the Circle class below:

    public class Circle {
        private int x;
        private int y;
        private double radius;
    
        public Circle(){
            this(0, 0, 0);
        }
    
        public Circle(int x, int y, double radius){
            setX(x);
            setY(y);
            setRadius(radius);
        }
    
        public int getX() {
            return x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public double getRadius() {
            return radius;
        }
    
        public void setRadius(double radius) {
            this.radius = Math.max(radius, 0);
        }
    
        public int getArea(){
            double area = Math.PI * Math.pow(radius, 2);
            return (int)area;
        }
    }
    

    Update it as follows so that code given below produces the given output.

    • Add a class-level getMaxRadius method that returns the maximum radius that has been used in all Circle objects created thus far.
    public class Main {
        public static void main(String[] args) {
            Circle c = new Circle();
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
            c = new Circle(0, 0, 10);
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
            c = new Circle(0, 0, -15);
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
            c.setRadius(12);
            System.out.println("max radius used so far : " + Circle.getMaxRadius());
        }
    }
    

    max radius used so far : 0.0
    max radius used so far : 10.0
    max radius used so far : 10.0
    max radius used so far : 12.0
    

    You can use a static variable maxRadius to track the maximum value used for the radius attribute so far.

    Partial solution:

    public void setRadius(double radius) {
        this.radius = Math.max(radius, 0);
        if (maxRadius < this.radius){
            // ...
        }
    }
    
    W2.4 Can use basic features of an IDE W2.4a Can explain IDEs

    Implementation → IDEs →

    What

    Professional software engineers often write code using Integrated Development Environments (IDEs). IDEs support all development-related work within the same tool.

    An IDE generally consists of:

    • A source code editor that includes features such as syntax coloring, auto-completion, easy code navigation, error highlighting, and code-snippet generation.
    • A compiler and/or an interpreter (together with other build automation support) that facilitates the compilation/linking/running/deployment of a program.
    • A debugger that allows the developer to execute the program one step at a time to observe the run-time behavior in order to locate bugs.
    • Other tools that aid various aspects of coding e.g. support for automated testing, drag-and-drop construction of UI components, version management support, simulation of the target runtime platform, and modeling support.

    Examples of popular IDEs:

    • Java: Eclipse, Intellij IDEA, NetBeans
    • C#, C++: Visual Studio
    • Swift: XCode
    • Python: PyCharm

    Some Web-based IDEs have appeared in recent times too e.g., Amazon's Cloud9 IDE.

    Some experienced developers, in particular those with a UNIX background, prefer lightweight yet powerful text editors with scripting capabilities (e.g. Emacs) over heavier IDEs.

    • a. Compiling
    • b. Syntax error highlighting
    • c. Debugging
    • d. Code navigation e.g., to navigate from a method call to the method implementation
    • e. Simulation e.g., run a mobile app in a simulator
    • f. Code analysis e.g. to find unreachable code
    • g. Reverse engineering design/documentation e.g. generate diagrams from code
    • h. Visual programming e.g. Write programs using ‘drag and drop’ actions instead of typing code
    • i. Syntax assistance e.g., show hints as you type
    • j. Code generation e.g., to generate the code required by simply specifying which component/structure you want to implement
    • k. Extension i.e., ability add more functionality to the IDE using plugins

    All.

    Explanation: While all of these features may not be present in some IDEs, most do have these features in some form or other.


    Evidence:

    Install Intellij IDEA on your computer. Either the Community Edition (free) or the Ultimate Edition (free for students) is fine.

    W2.4b Can setup a project in an IDE

    Tools → Intellij IDEA →

    Project Setup

    Running Intellij IDEA for the First Time
     


     

    A little bit more detailed explanation (from CodeLaunch) with some additional info at the end.


    Importing a Project to Intellij IDEA

    Evidence:

    Create a new project in Intellij and write some code in it. Run the code.

    W2.4c Can navigate code effectively using IDE features

    Tools → Intellij IDEA →

    Code Navigation

    Some useful navigation shortcuts:

    1. Quickly locate a file by name.
    2. Go to the definition of a method from where it is used.
    3. Go back to the previous location.
    4. View the documentation of a method from where the method is being used, without navigating to the method itself.
    5. Find where a method/field is being used.

    Evidence:

    Add more code to your project in the IDE so that you have multiple files and multiple methods. Navigate through the code using IDE features e.g., jump from method call to the method definition.

    Tutorial 2

    For LOs from the 'C++ to Java' chapter, you can do the coding exercises in Repl.it. The link to the exercises will be given to you in Lecture 1.


    For W1.1a Can explain pros and cons of software engineering
    Details of the LO

    Software Engineering → Introduction →

    Pros and Cons

     

    Software Engineering: Software Engineering is the application of a systematic, disciplined, quantifiable approach to the development, operation, and maintenance of software" -- IEEE Standard Glossary of Software Engineering Terminology

    The following description of the Joys of the Programming Craft was taken from Chapter 1 of the famous book The Mythical Man-Month, by Frederick P. Brooks.

    Why is programming fun? What delights may its practitioner expect as his reward?

    First is the sheer joy of making things. As the child delights in his mud pie, so the adult enjoys building things, especially things of his own design. I think this delight must be an image of God's delight in making things, a delight shown in the distinctness and newness of each leaf and each snowflake.

    Second is the pleasure of making things that are useful to other people. Deep within, we want others to use our work and to find it helpful. In this respect the programming system is not essentially different from the child's first clay pencil holder "for Daddy's office."

    Third is the fascination of fashioning complex puzzle-like objects of interlocking moving parts and watching them work in subtle cycles, playing out the consequences of principles built in from the beginning. The programmed computer has all the fascination of the pinball machine or the jukebox mechanism, carried to the ultimate.

    Fourth is the joy of always learning, which springs from the nonrepeating nature of the task. In one way or another the problem is ever new, and its solver learns something: sometimes practical, sometimes theoretical, and sometimes both.

    Finally, there is the delight of working in such a tractable medium. The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by the exertion of the imagination. Few media of creation are so flexible, so easy to polish and rework, so readily capable of realizing grand conceptual structures....

    Yet the program construct, unlike the poet's words, is real in the sense that it moves and works, producing visible outputs separate from the construct itself. It prints results, draws pictures, produces sounds, moves arms. The magic of myth and legend has come true in our time. One types the correct incantation on a keyboard, and a display screen comes to life, showing things that never were nor could be.

    Programming then is fun because it gratifies creative longings built deep within us and delights sensibilities we have in common with all men.

    Not all is delight, however, and knowing the inherent woes makes it easier to bear them when they appear.

    First, one must perform perfectly. The computer resembles the magic of legend in this respect, too. If one character, one pause, of the incantation is not strictly in proper form, the magic doesn't work. Human beings are not accustomed to being perfect, and few areas of human activity demand it. Adjusting to the requirement for perfection is, I think, the most difficult part of learning to program.

    Next, other people set one's objectives, provide one's resources, and furnish one's information. One rarely controls the circumstances of his work, or even its goal. In management terms, one's authority is not sufficient for his responsibility. It seems that in all fields, however, the jobs where things get done never have formal authority commensurate with responsibility. In practice, actual (as opposed to formal) authority is acquired from the very momentum of accomplishment.

    The dependence upon others has a particular case that is especially painful for the system programmer. He depends upon other people's programs. These are often maldesigned, poorly implemented, incompletely delivered (no source code or test cases), and poorly documented. So he must spend hours studying and fixing things that in an ideal world would be complete, available, and usable.

    The next woe is that designing grand concepts is fun; finding nitty little bugs is just work. With any creative activity come dreary hours of tedious, painstaking labor, and programming is no exception.

    Next, one finds that debugging has a linear convergence, or worse, where one somehow expects a quadratic sort of approach to the end. So testing drags on and on, the last difficult bugs taking more time to find than the first.

    The last woe, and sometimes the last straw, is that the product over which one has labored so long appears to be obsolete upon (or before) completion. Already colleagues and competitors are in hot pursuit of new and better ideas. Already the displacement of one's thought-child is not only conceived, but scheduled.

    This always seems worse than it really is. The new and better product is generally not available when one completes his own; it is only talked about. It, too, will require months of development. The real tiger is never a match for the paper one, unless actual use is wanted. Then the virtues of reality have a satisfaction all their own.

    Of course the technological base on which one builds is always advancing. As soon as one freezes a design, it becomes obsolete in terms of its concepts. But implementation of real products demands phasing and quantizing. The obsolescence of an implementation must be measured against other existing implementations, not against unrealized concepts. The challenge and the mission are to find real solutions to real problems on actual schedules with available resources.

    This then is programming, both a tar pit in which many efforts have floundered and a creative activity with joys and woes all its own. For many, the joys far outweigh the woes....

    [Text and book cover source: Wikipedia]

    [Fred Brooks photo source]

    The Mythical Man-Month: Essays on Software Engineering is a book on software engineering and project management by Fred Brooks, whose central theme is that "adding manpower to a late software project makes it later". This idea is known as Brooks's law, and is presented along with the second-system effect and advocacy of prototyping.

    Compare Software Engineering with Civil Engineering in terms of how work products in CE (i.e. buildings) differ from those of SE (i.e. software).

    Buildings Software
    Visible, tangible Invisible, intangible
    Wears out over time Does not wear out
    Change is limited by physical restrictions (e.g. difficult to remove a floor from a high rise building) Change is not limited by such restrictions. Just change the code and recompile.
    Creating an exact copy of a building is impossible. Creating a near copy is almost as costly as creating the original. Any number of exact copies can be made with near zero cost.
    Difficult to move. Easily delivered from one place to another.
    Many low-skilled workers following tried-and-tested procedures. No low-skilled workers involved. Workers have more freedom to follow their own procedures.
    Easier to assure quality (just follow accepted procedure). Not easy to assure quality.
    Majority of the work force has to be on location. Can be built by people who are not even in the same country.
    Raw materials are costly, costly equipment required. Almost free raw materials and relatively cheap equipment.
    Once construction is started, it is hard to do drastic changes to the design. Building process is very flexible. Drastic design changes can be done, although costly
    A lot of manual and menial labor involved. Most work involves highly-skilled labor.
    Generally robust. E.g. removing a single brick is unlikely to destroy a building. More fragile than buildings. A single misplaced semicolon can render the whole system useless.

    Comment on this statement: Building software is cheaper and easier than building bridges (all we need is a PC!).

    Depends on the size of the software. Manpower required for software is very costly. On the other hand, we can create a very valuable software (e.g. an iPhone application that can make million dollars in a month) with a just a PC and a few days of work!

    Justify this statement: Coding is still a ‘design’ activity, not a ‘manufacturing’ activity. You may use a comparison (or an analogy) of Software engineering versus Civil Engineering to argue this point.

    Arguments to support this statement:

    • If coding is a manufacturing activity, we should be able to do it using robotic machines (just like in the car industry) or low-skilled laborers (like in the construction industry).
    • If coding is a manufacturing activity, we wouldn’t be changing it so much after we code software. But if the code is in fact a ‘design’, yes, we would fiddle with it until we get it right.
    • Manufacturing is the process of building a finished product based on the design. Code is the design. Manufacturing is what is done by the compiler (fully automated).

    However, the type of ‘design’ that occurs during coding is at a much lower level than the ‘design’ that occurs before coding.

    List some (at least three each) pros and cons of Software Engineering compared to other traditional Engineering careers.

    • a. Need for perfection when developing software
    • b. Requiring some amount of tedious, painstaking labor
    • c. Ease of copying and transporting software makes it difficult to keep track of versions
    • d. High dependence on others
    • e. Seemingly never ending effort required for testing and debugging software
    • f. Fast moving industry making our work obsolete quickly

    (c)



    Evidence:

    To be able answer questions such as these:

    List some (at least three each) pros and cons of Software Engineering compared to other traditional Engineering careers.

    For W1.3d Can run a simple Java program
    Details of the LO

    C++ to Java → Getting Started →

    Running a Program

    To run the HelloWorld program, in a command console, run the following command from the folder containing HelloWorld.class file.

    >_ java HelloWorld

    Notes:

    • java in the command above refers to the Java interpreter installed in your computer.
    • Similar to javac, your console should be able to find the java executable.

    When you run a Java program, you can encounter a run-time error. These errors are also called "exceptions" because they usually indicate that something exceptional (and bad) has happened. When a run-time error occurs, the interpreter displays an error message that explains what happened and where.

    For example, modify the HelloWorld code to include the following line, compile it again, and run it.

    System.out.println(5/0);
    

    You should get a message like this:

    Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Hello.main(Hello.java:5)
    

    Integrated Development Environments (IDEs) can automate the intermediate step of compiling. They usually have a Run button which compiles the code first and then runs it.

    Example IDEs:

    • Intellij IDEA
    • Eclipse
    • NetBeans
    • Install Java in your Computer, if you haven't done so already.
    • Write, compile and run a small Java program (e.g., a HelloWorld program) in your Computer. You can use any code editor to write the program but use the command prompt to compile and run the program.
    • Modify the code and run the program again.


    Evidence:

    To be able to do exercises such as this:

    • Install Java in your Computer, if you haven't done so already.
    • Write, compile and run a small Java program (e.g., a HelloWorld program) in your Computer. You can use any code editor to write the program but use the command prompt to compile and run the program.
    • Modify the code and run the program again.
    For W1.4d Can use arrays
    Details of the LO

    C++ to Java → Data Types →

    Arrays

    Arrays are indicated using square brackets ([]). To create the array itself, you have to use the new operator. Here are some example array declarations:

    int[] counts;
    counts = new int[4]; // create an int array of size 4
    
    int size = 5;
    double[] values;
    values = new double[size]; //use a variable for the size
    
    double[] prices = new double[size]; // declare and create at the same time
    
    Alternatively, you can use the shortcut syntax to create and initialize an array:
    int[] values = {1, 2, 3, 4, 5, 6};
    
    int[] anArray = {
        100, 200, 300,
        400, 500, 600,
        700, 800, 900, 1000
    };
    

    -- Java Tutorial

    The [] operator selects elements from an array. Array elements indices start from 0.

    int[] counts = new int[4];
    
    System.out.println("The first element is " + counts[0]);
    
    counts[0] = 7; // set the element at index 0 to be 7
    counts[1] = counts[0] * 2;
    counts[2]++; // increment value at index 2
    

    A Java array is aware of its size. A Java array prevents a programmer from indexing the array out of bounds. If the index is negative or not present in the array, the result is an error named ArrayIndexOutOfBoundsException.

    int[] scores = new int[4];
    System.out.println(scores.length) // prints 4
    scores[5] = 0; // causes an exception
    

    4
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
    	at Main.main(Main.java:6)
    

    It is also possible to create arrays of more than one dimension:

    String[][] names = {
        {"Mr. ", "Mrs. ", "Ms. "},
        {"Smith", "Jones"}
    };
    
    System.out.println(names[0][0] + names[1][0]); // Mr. Smith
    System.out.println(names[0][2] + names[1][1]); // Ms. Jones
    

    -- Java Tutorial

    Passing arguments to a program

    The args parameter of the main method is an array of Strings containing command line arguments supplied (if any) when running the program.

    public class Foo{
        public static void main(String[] args) {
            System.out.println(args[0]);
        }
    }
    

    You can run this program (after compiling it first) from the command line by typing:

    >_ java Foo abc

    abc

    Write a Java program that takes two command line arguments and prints true or false to indicate if the two arguments have the same value. Follow the sample output given below.

    class WordComparator {
      public static void main(String[] args) {
          // add your code here
      }
    }
    

    >_ java WordComparator adam eve

    Words given: adam, eve
    They are the same: false
    

    >_ java WordComparator eve eve

    Words given: eve, eve
    They are the same: true
    

    💡 Use the following technique to compare two Strings(i.e., don't use ==). Reason: to be covered in a later topic.

    String x = "foo";
    boolean isSame = x.equals("bar") // false
    isSame = x.equals("foo") // true
    
    • The two command line arguments can be accessed inside the main method using args[0] and args[1].
    • When using multiple operators in the same expression, you might need to use parentheses to specify operator precedence. e.g., "foo" + x == y vs "foo" + (x == y)
    class WordComparator {
      public static void main(String[] args) {
          String first = args[0];
          String second = args[1];
          System.out.println("Words given: " + first + ", " + second);
          // ...
      }
    }
    
    


    Evidence:

    To be able to do exercises such as this:

    Write a Java program that takes two command line arguments and prints true or false to indicate if the two arguments have the same value. Follow the sample output given below.

    class WordComparator {
      public static void main(String[] args) {
          // add your code here
      }
    }
    

    >_ java WordComparator adam eve

    Words given: adam, eve
    They are the same: false
    

    >_ java WordComparator eve eve

    Words given: eve, eve
    They are the same: true
    

    💡 Use the following technique to compare two Strings(i.e., don't use ==). Reason: to be covered in a later topic.

    String x = "foo";
    boolean isSame = x.equals("bar") // false
    isSame = x.equals("foo") // true
    
    • The two command line arguments can be accessed inside the main method using args[0] and args[1].
    • When using multiple operators in the same expression, you might need to use parentheses to specify operator precedence. e.g., "foo" + x == y vs "foo" + (x == y)
    class WordComparator {
      public static void main(String[] args) {
          String first = args[0];
          String second = args[1];
          System.out.println("Words given: " + first + ", " + second);
          // ...
      }
    }
    
    
    For W1.5a Can use branching
    Details of the LO

    C++ to Java → Control Flow →

    Branching

    if-else statements

    Java supports the usual forms of if statements:

    if (x > 0) {
        System.out.println("x is positive");
    }
    
    if (x % 2 == 0) {
        System.out.println("x is even");
    } else {
        System.out.println("x is odd");
    }
    
    if (x > 0) {
        System.out.println("x is positive");
    } else if (x < 0) {
        System.out.println("x is negative");
    } else {
        System.out.println("x is zero");
    }
    
    if (x == 0) {
        System.out.println("x is zero");
    } else {
        if (x > 0) {
            System.out.println("x is positive");
        } else {
            System.out.println("x is negative");
        }
    }
    

    The braces are optional (but recommended) for branches that have only one statement. So we could have written the previous example this way ( Bad):

    if (x % 2 == 0)
        System.out.println("x is even");
    else
        System.out.println("x is odd");
    
    switch statements

    The switch statement can have a number of possible execution paths. A switch works with the byte, short, char, and int primitive data types. It also works with enums, String.

    Here is an example (adapted from -- Java Tutorial):

    public class SwitchDemo {
        public static void main(String[] args) {
    
            int month = 8;
            String monthString;
            switch (month) {
            case 1:  monthString = "January";
                break;
            case 2:  monthString = "February";
                break;
            case 3:  monthString = "March";
                break;
            case 4:  monthString = "April";
                break;
            case 5:  monthString = "May";
                break;
            case 6:  monthString = "June";
                break;
            case 7:  monthString = "July";
                break;
            case 8:  monthString = "August";
                break;
            case 9:  monthString = "September";
                break;
            case 10: monthString = "October";
                break;
            case 11: monthString = "November";
                break;
            case 12: monthString = "December";
                break;
            default: monthString = "Invalid month";
                break;
            }
            System.out.println(monthString);
        }
    }
    

    August

    Write a Java program that takes several command line arguments that describe a person or a family | and prints out a greeting. The parameters can be one of two formats.

    arguments format explanation expected output
    NAME GENDER Indicates a single person. GENDER can be M or F Smith M Dear Mr. Smith
    Lee F Dear Mdm. Lee
    NAME MULTIPLE_GENDERS Indicates a family. Tan M M F Dear Tan family

    Follow the sample output given below.

    >_ java Greeter Smith M Dear Mr. Smith

    >_ java Greeter Lee F Dear Mdm. Lee

    >_ java Greeter Tan M M F Dear Tan family

    You can assume that the input is always in the correct format i.e., no need to handle invalid input cases.

    Partial solution:

    public class Greeter {
        public static void main(String[] args) {
            String first = args[0];
            String second = args[1];
            if (args.length == 2) {
                if (second.equals("M")) {
                    // ...
                }
            } else {
                // ...
            }
        }
    }
    

    Write a Java program that takes a letter grade e.g., A+ as a command line argument and prints the CAP value for that grade.

    💡 Use a switch statement in your code.

    A+ A A- B+ B B- C Else
    5.0 5.0 4.5 4.0 3.5 3.0 2.5 0

    Follow the sample output given below.

    >_ java GradeHelper B CAP for grade B is 3.5

    You can assume that the input is always in the correct format i.e., no need to handle invalid input cases.

    Partial solution:

    public class GradeHelper {
        public static void main(String[] args) {
            String grade = args[0];
            double cutoff = 0;
            switch (grade) {
            case "A+":
                // ...
            }
            System.out.println("CAP for grade " + grade + " is " + cutoff);
        }
    }
    


    Evidence:

    To be able to do exercises such as these:

    Write a Java program that takes several command line arguments that describe a person or a family | and prints out a greeting. The parameters can be one of two formats.

    arguments format explanation expected output
    NAME GENDER Indicates a single person. GENDER can be M or F Smith M Dear Mr. Smith
    Lee F Dear Mdm. Lee
    NAME MULTIPLE_GENDERS Indicates a family. Tan M M F Dear Tan family

    Follow the sample output given below.

    >_ java Greeter Smith M Dear Mr. Smith

    >_ java Greeter Lee F Dear Mdm. Lee

    >_ java Greeter Tan M M F Dear Tan family

    You can assume that the input is always in the correct format i.e., no need to handle invalid input cases.

    Partial solution:

    public class Greeter {
        public static void main(String[] args) {
            String first = args[0];
            String second = args[1];
            if (args.length == 2) {
                if (second.equals("M")) {
                    // ...
                }
            } else {
                // ...
            }
        }
    }
    

    Write a Java program that takes a letter grade e.g., A+ as a command line argument and prints the CAP value for that grade.

    💡 Use a switch statement in your code.

    A+ A A- B+ B B- C Else
    5.0 5.0 4.5 4.0 3.5 3.0 2.5 0

    Follow the sample output given below.

    >_ java GradeHelper B CAP for grade B is 3.5

    You can assume that the input is always in the correct format i.e., no need to handle invalid input cases.

    Partial solution:

    public class GradeHelper {
        public static void main(String[] args) {
            String grade = args[0];
            double cutoff = 0;
            switch (grade) {
            case "A+":
                // ...
            }
            System.out.println("CAP for grade " + grade + " is " + cutoff);
        }
    }
    
    For W1.5b Can use methods
    Details of the LO

    C++ to Java → Control Flow →

    Methods

    Defining methods

    Here’s an example of adding more methods to a class:

    public class PrintTwice {
    
        public static void printTwice(String s) {
            System.out.println(s);
            System.out.println(s);
        }
    
        public static void main(String[] args) {
            String sentence = “Polly likes crackers”
            printTwice(sentence);
    
        }
    }
    
    

    Polly likes crackers
    Polly likes crackers
    

    By convention, method names should be named in the camelCase format.

     

    CamelCase is named after the "humps" of its capital letters, similar to the humps of a Bactrian camel. Camel case (stylized as camelCase) is the practice of writing compound words or phrases such that each word or abbreviation in the middle of the phrase begins with a capital letter, with no intervening spaces or punctuation.

    -- adapted from Wikipedia

    e.g., createEmptyList, listOfIntegers, htmlText, dvdPlayer. This book defines camelCase style as requiring the first letter to be lower case. If the first letter is upper case instead e.g., CreateEmptyList, it is called UpperCamelCase or PascalCase.

    Similar to the main method, the printTwice method is public (i.e., it can be invoked from other classes) static and void.

    Parameters

    A method can specify parameters. The printTwice method above specifies a parameter of String type. The main method passes the argument "Polly likes crackers" to that parameter.

    The value provided as an argument must have the same type as the parameter. Sometimes Java can convert an argument from one type to another automatically. For example, if the method requires a double, you can invoke it with an int argument 5 and Java will automatically convert the argument to the equivalent value of type double 5.0.

    Because variables only exist inside the methods where they are defined, they are often called local variables. Parameters and other variables declared inside a method only exist inside their own methods. Inside main, there is no such thing as s. If you try to use it there, you’ll get a compiler error. Similarly, inside printTwice there is no such thing as sentence. That variable belongs to main.

    return statements

    The return statement allows you to terminate a method before you reach the end of it:

    public static void printLogarithm(double x) {
        if (x <= 0.0) {
            System.out.println("Error: x must be positive.");
            return;
        }
        double result = Math.log(x);
        System.out.println("The log of x is " + result);
    }
    

    It can be used to return a value from a method too:

    public class AreaCalculator{
    
        public static double calculateArea(double radius) {
            double result = 3.14 * radius * radius;
            return result;
        }
    
        public static void main(String[] args) {
            double area = calculateArea(12.5);
            System.out.println(area);
        }
    }
    
    Overloading

    Java methods can be overloaded. If two methods do the same thing, it is natural to give them the same name. Having more than one method with the same name is called overloading, and it is legal in Java as long as each version takes different parameters.

    public static double calculateArea(double radius) {
        //...
    }
    
    public static double calculateArea(double height, double width) {
        //...
    }
    
    Recursion

    Methods can be recursive. Here is an example in which the nLines method calls itself recursively:

    public static void nLines(int n) {
        if (n > 0) {
            System.out.println();
            nLines(n - 1);
        }
    }
    

    Add the following method to the class given below.

    • public static double getGradeCap(String grade): Returns the CAP value of the given grade. The mapping from grades to CAP is given below.
    A+ A A- B+ B B- C Else
    5.0 5.0 4.5 4.0 3.5 3.0 2.5 0
    public class Main {
    
        // ADD YOUR CODE HERE
    
        public static void main(String[] args) {
            System.out.println("A+: " + getGradeCap("A+"));
            System.out.println("B : " + getGradeCap("B"));
        }
    }
    

    A+: 5.0
    B : 3.5
    

    Partial solution:

        public static double getGradeCap(String grade) {
            double cap = 0;
            switch (grade) {
            case "A+":
            case "A":
                cap = 5.0;
                break;
            case "A-":
                cap = 4.5;
                break;
            case "B+":
                cap = 4.0;
                break;
            case "B":
                cap = 3.5;
                break;
            case "B-":
                cap = 3.0;
                break;
            default:
            }
            return cap;
        }
    


    Evidence:

    To be able to do exercises such as these:

    Add the following method to the class given below.

    • public static double getGradeCap(String grade): Returns the CAP value of the given grade. The mapping from grades to CAP is given below.
    A+ A A- B+ B B- C Else
    5.0 5.0 4.5 4.0 3.5 3.0 2.5 0
    public class Main {
    
        // ADD YOUR CODE HERE
    
        public static void main(String[] args) {
            System.out.println("A+: " + getGradeCap("A+"));
            System.out.println("B : " + getGradeCap("B"));
        }
    }
    

    A+: 5.0
    B : 3.5
    

    Partial solution:

        public static double getGradeCap(String grade) {
            double cap = 0;
            switch (grade) {
            case "A+":
            case "A":
                cap = 5.0;
                break;
            case "A-":
                cap = 4.5;
                break;
            case "B+":
                cap = 4.0;
                break;
            case "B":
                cap = 3.5;
                break;
            case "B-":
                cap = 3.0;
                break;
            default:
            }
            return cap;
        }
    
    For W1.5c Can use loops
    Details of the LO

    C++ to Java → Control Flow →

    Loops

    while loops

    Here is an example while loop:

    public static void countdown(int n) {
        while (n > 0) {
            System.out.println(n);
            n = n - 1;
        }
        System.out.println("Blastoff!");
    }
    
    for loops

    for loops have the form:

    for (initializer; condition; update) {
        statement(s);
    }
    

    Here is an example:

    public static void printTable(int rows) {
        for (int i = 1; i <= rows; i = i + 1) {
            printRow(i, rows);
        }
    }
    
    do-while loops

    The while and for statements are pretest loops; that is, they test the condition first and at the beginning of each pass through the loop. Java also provides a posttest loop: the do-while statement. This type of loop is useful when you need to run the body of the loop at least once.

    Here is an example (from -- Java Tutorial):

    class DoWhileDemo {
        public static void main(String[] args){
            int count = 1;
            do {
                System.out.println("Count is: " + count);
                count++;
            } while (count < 11);
        }
    }
    
    break and continue

    A break statement exits the current loop.

    Here is an example (from -- Java Tutorial):

    class Main {
        public static void main(String[] args) {
            int[] numbers = new int[] { 1, 2, 3, 0, 4, 5, 0 };
            for (int i = 0; i < numbers.length; i++) {
                if (numbers[i] == 0) {
                    break;
                }
                System.out.print(numbers[i]);
            }
        }
    }
    

    123
    

    [Try the above code on Repl.it]

    A continue statement skips the remainder of the current iteration and moves to the next iteration of the loop.

    Here is an example (from -- Java Tutorial):

    public static void main(String[] args) {
        int[] numbers = new int[] { 1, 2, 3, 0, 4, 5, 0 };
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == 0) {
                continue;
            }
            System.out.print(numbers[i]);
        }
    }
    

    12345
    

    [Try the above code on Repl.it]

    Enhanced for loops

    Since traversing arrays is so common, Java provides an alternative for-loop syntax that makes the code more compact. For example, consider a for loop that displays the elements of an array on separate lines:

    for (int i = 0; i < values.length; i++) {
        int value = values[i];
        System.out.println(value);
    }
    

    We could rewrite the loop like this:

    for (int value : values) {
        System.out.println(value);
    }
    

    This statement is called an enhanced for loop. You can read it as, “for each value in values”. Notice how the single line for (int value : values) replaces the first two lines of the standard for loop.

    Add the following method to the class given below.

    • public static double[] getMultipleGradeCaps(String[] grades): Returns the CAP values of the given grades. e.g., if the input was the array ["A+", "B"], the method returns [5.0, 3.5]. The mapping from grades to CAP is given below.
    A+ A A- B+ B B- C Else
    5.0 5.0 4.5 4.0 3.5 3.0 2.5 0
    public class Main {
    
        // ADD YOUR CODE HERE
    
        public static double getGradeCap(String grade) {
            double cap = 0;
            switch (grade) {
            case "A+":
            case "A":
                cap = 5.0;
                break;
            case "A-":
                cap = 4.5;
                break;
            case "B+":
                cap = 4.0;
                break;
            case "B":
                cap = 3.5;
                break;
            case "B-":
                cap = 3.0;
                break;
            case "C":
                cap = 2.5;
                break;
            default:
            }
            return cap;
        }
    
        public static void main(String[] args) {
            String[] grades = new String[]{"A+", "A", "A-"};
            double[] caps = getMultipleGradeCaps(grades);
            for (int i = 0; i < grades.length; i++) {
                System.out.println(grades[i] + ":" + caps[i]);
            }
        }
    }
    

    A+:5.0
    A:5.0
    A-:4.5
    

    Partial solution:

        public static double[] getMultipleGradeCaps(String[] grades) {
            double[] caps = new double[grades.length];
            for (int i = 0; i < grades.length; i++) {
               // ...
            }
            return caps;
        }
    


    Evidence:

    To be able to do exercises such as these:

    Add the following method to the class given below.

    • public static double[] getMultipleGradeCaps(String[] grades): Returns the CAP values of the given grades. e.g., if the input was the array ["A+", "B"], the method returns [5.0, 3.5]. The mapping from grades to CAP is given below.
    A+ A A- B+ B B- C Else
    5.0 5.0 4.5 4.0 3.5 3.0 2.5 0
    public class Main {
    
        // ADD YOUR CODE HERE
    
        public static double getGradeCap(String grade) {
            double cap = 0;
            switch (grade) {
            case "A+":
            case "A":
                cap = 5.0;
                break;
            case "A-":
                cap = 4.5;
                break;
            case "B+":
                cap = 4.0;
                break;
            case "B":
                cap = 3.5;
                break;
            case "B-":
                cap = 3.0;
                break;
            case "C":
                cap = 2.5;
                break;
            default:
            }
            return cap;
        }
    
        public static void main(String[] args) {
            String[] grades = new String[]{"A+", "A", "A-"};
            double[] caps = getMultipleGradeCaps(grades);
            for (int i = 0; i < grades.length; i++) {
                System.out.println(grades[i] + ":" + caps[i]);
            }
        }
    }
    

    A+:5.0
    A:5.0
    A-:4.5
    

    Partial solution:

        public static double[] getMultipleGradeCaps(String[] grades) {
            double[] caps = new double[grades.length];
            for (int i = 0; i < grades.length; i++) {
               // ...
            }
            return caps;
        }
    

    Lecture 2

    [slides]