JD

CAB201 Programming Principles - Comprehensive Study Notes

Object-Oriented Programming (OOP) – Overview

  • Object-oriented programming is a software development paradigm in which data is packaged with the operations that execute on it.
  • In traditional programming, procedures and data were separate; in OOP they are combined into an object with fields (data) and methods (operations).
  • The combined package is called an object; the data are fields and the operations are methods.
  • OOP has been an industry-standard paradigm for decades due to its ability to produce solutions that scale more effectively than traditional approaches.

The Four Principles of OOP

  • Abstraction – hide intricate and volatile details inside an object and expose a simplified external interface.
  • Encapsulation – internal workings of an object are protected; use the object only through its external interface.
  • Inheritance – create new objects that extend existing objects, reusing and augmenting existing behavior while preserving the same usage.
  • Polymorphism – objects can behave in unique, individual ways when the same operations are performed on them.

Defining a Class

  • A class is a fundamental concept in OOP for creating custom object types.
  • C# is a class-based language; all code you write and all fields you create are part of a class (or struct).
  • Classes are used for a variety of purposes and support multiple programming paradigms.
  • A class provides a template for object creation and specifies details that apply to every member of the class, while also identifying attributes that may vary among instances.
  • Think of a class as a cookie cutter and objects as cookies.
  • A class groups related data and/or methods and encapsulates data with the operations that act on it.
  • A class represents a custom type (though not all classes are custom types).

Grouping Related Data

  • Scenario: storing information about students.
  • Instead of separate arrays for names, IDs, and GPAs (which risks being out of sync and complicates operations like sorting), use a class to group related data.
  • Example attributes for a Student:
    • Name as a string
    • ID as an int
    • GPA as a float

A Concrete Class Example: Student

  • Class fields (as an example):
class Student {
    public int ID;
    public string Name;
    public float GPA;
}
  • Creating an array of students:
Student[] students = new Student[10];
  • This example demonstrates storing related data together in a single type.

Instantiating a Class

  • Objects are instances of classes.
  • Instantiate objects with the new keyword:
Classname variablename = new Classname();
  • Example:
Student student = new Student();
  • In the above example:
  • Class: Student
  • Object: student
  • student is an instance of Student

Fields and Classes

  • Fields: variables declared in classes that hold data relevant to that class (primitives, other objects, etc.).
  • Access a field via the dot operator: variablename.fieldname.
  • Example: student.ID = 12345678;
  • Fields are sometimes called instance variables because they belong to a specific instance of a class.
  • Unlike languages like JavaScript and Python, in C# an object's fields typically must be declared in the class definition (you cannot store arbitrary fields).

Methods

  • Methods in C# are akin to functions/procedures in other languages.
  • They may take parameters, execute a sequence of instructions, and optionally return a value.
  • Method example:
double HarmonicMean(double a, double b) {
    double mean = 2.0 * a * b / (a + b);
    return mean;
}
  • Method components: Return type, Method name, Parameters, Method signature, Body.

Void Methods

  • A void method has a return type of void and does not return a value.
  • It is not required to have a return statement; execution returns when the method ends.
  • A void method can still use a return statement to exit early, without returning a value:
public void PrintGreeting() {
    Console.WriteLine("Hello World");
}

Invoking Methods on Objects

  • Methods are invoked on objects that are instances of the class they belong to (except for static methods).
  • Methods have access to the fields of the object on which they are invoked.
  • Example:
class Coordinate {
    int x, y;
    public void PrintLocation() {
        Console.WriteLine($"The coordinate is {x},{y}");
    }
}
coordinate.PrintLocation();

Parameter Passing: in, ref, out

  • Parameters can be prefixed with in, ref, or out to control how values are passed.
  • in – input-only; passes by reference but read-only inside method.
  • out – used to return values from a method; the method must assign a value to the parameter.
  • ref – passes by reference; the method can read and modify the original value.
  • Notes:
    • The ref and out keywords must be used on both the declaration and the call sites.
    • in parameters are read-only inside the method.

Parsing Strings to Numbers: int.Parse vs int.TryParse

  • int.Parse() converts a string to an int but throws an exception if parsing fails.
  • Unhandled exceptions terminate the program; this is problematic when input can be unpredictable (e.g., user input).
  • int.TryParse() uses an out parameter to return the parsed value and returns a boolean indicating success or failure.
  • Example:
int.TryParse("123", out int value);

Procedural Abstraction

  • A fundamental abstraction concept in computer science.
  • Identify common tasks and split them into procedures (functions/methods).
  • Benefits:
    • Reuse the procedure in multiple places.
    • Reduces code size and bugs.
    • Centralises changes when requirements change.
  • Well-designed procedures are self-documenting.

Constructors

  • Constructors are special methods used to initialize an object when it is created.
  • Constructors have no return type.
  • If no constructor is provided, a parameterless constructor is generated automatically.
  • If you provide a constructor, an object cannot be created without calling it.
  • Example with a parameterized constructor:
public Student(int id, string name, float gpa) {
    ID = id;
    Name = name;
    GPA = gpa;
    return;
}
  • Usage:
// With a constructor: you must supply parameters
Student student = new Student(12345678, "Alice", 7.0f);

Creating Well-Designed Procedures

  • Choose a good name: concise, descriptive, and self-documenting.
  • Prefer an Is prefix for predicates that return a bool and do not mutate state (e.g. IsBlank(), IsEmpty(), IsActive()).
  • Ensure the method does one thing; if naming is hard, the method may be doing too much.
  • If the name is ambiguous, consider refactoring.

When Abstraction Isn’t Perfect

  • Some details about a method’s internal workings cannot be captured fully in its name.
  • These details should be documented thoroughly.
  • Questions to ask regarding abstraction:
    • What side effects does the method have?
    • What will it do with the parameters?
    • Does it rely on external state, and how?
    • What can I do with the return value?

NULL VALUES and Nullable Types

  • null means the reference points to no object; applicable to object references.
  • It is an error to call a method or access a field through a null reference.
  • C# introduces nullable types to handle the potential for null values safely.
  • Syntax: append ? to a value type to make it nullable, e.g. int?, string? (reference types can also be nullable via ?).
  • Compiler warnings help prevent null reference issues.
  • Examples:
    • int[]? array;
    • Student? myStudent;

Null Operators

  • Null coalescing operator: ??
  • Null coalescing assignment: ??=
  • Null conditional access: ?. and ?[]
  • Semantics:
    • L ?? R returns L if L is not null; otherwise returns R.
    • L ??= R assigns R to L if L is null; otherwise does nothing.
    • a?.b accesses member b only if a is not null; otherwise returns null.
    • a?[i] accesses indexer only if a is not null.

Examples Using Null Operators

  • Basic coalescing:
string response = Console.ReadLine() ?? "";
Console.WriteLine("You entered a {0}-length string", response.Length);
  • With nullable response:
string? response = Console.ReadLine();
response ??= "";
Console.WriteLine("You entered a {0}-length string", response.Length);
  • Using null-conditional and length:
string? response = Console.ReadLine();
Console.WriteLine("You entered a {0}-length string", response?.Length);
  • Accessing a character safely:
string? response = Console.ReadLine();
Console.WriteLine("The first character is {0}", response?[0]);

Nullable Parameters

  • Methods can take nullable or non-nullable parameters.
  • Nullable parameters effectively make the parameter optional; supplying null can carry a meaning.
  • The contract: a nullable parameter may be null; a non-nullable parameter is assumed not to be null.
  • Compiler warnings may occur if non-nullable parameters could be null.

Overloading vs Overriding

  • Method overloading allows multiple methods with the same name but different parameter lists within a class.
  • Example, all methods named Method but with different argument types/counts:
public void Method(int a, int b)
public void Method(int a, float b)
public void Method(int a, int b, int c)
  • The correct overload is chosen at compile time based on static types of the arguments.
  • Important to distinguish from overriding (runtime polymorphism) which is not covered in this section.

Uses of Method Overloading

  • Best used to provide different versions of a method that accept different argument shapes.
  • Example: a drawing method with different overloads:
public void DrawRectangle(Coord topLeft, Coord topRight)
public void DrawRectangle(int x1, int y1, int x2, int y2)
  • Overloads can return different types or have different access levels (though not recommended to rely on this).

Drawbacks and Tips for Method Overloading

  • Overloading can become hard to maintain if overused.
  • Prefer implementing overloads in terms of each other where possible (e.g., convert to a common form and delegate).
  • If some arguments have default values, consider optional arguments instead of excessive overloading.

Optional Arguments (Default Values)

  • Optional arguments allow omitting values in calls; defaults are supplied by the method signature.
  • Example:
public decimal CalculatePrice(decimal gst = 0.10m)
  • When not supplied, the optional argument takes its default value.
  • Named arguments can be useful when there are multiple optional arguments:
decimal price = CalculatePrice(gst: 0.00m);

Visibility (Access Modifiers)

  • Classes, methods, and fields can have visibility modifiers to control access.
  • Main modifiers:
    • private – internal to the class; private methods/fields can only be accessed by other members of the class.
    • public – accessible from anywhere.
    • internal – accessible within the same assembly; in many contexts equivalent to public for practical purposes in tutorials.
  • Note: Visual Studio often shows internal by default in generated code.
  • For more details see official docs: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structures/access-modifiers

The this Keyword

  • this is used to refer to members of the current object.
  • Useful to disambiguate between local variables and fields when they have the same name (e.g., in constructors):
public class Example {
    private float GPA;
    public Example(float GPA) {
        this.GPA = GPA;
    }
}
  • Without this, the local parameter could obscure the instance field.

XML Comments

  • XML comments provide markup to describe classes, methods, or fields.
  • Syntax uses three slashes: /// followed by XML tags, e.g. <summary>, <param>, <returns>.
  • They show up in IDE tooltips and help documents, improving API usability without digging into code:
/// <summary>
/// Returns the current location of this actor
/// </summary>
/// <param name="x">The actor's X coordinate</param>
/// <param name="y">The actor's Y coordinate</param>
public void GetLocation(out int x, out int y) { … }

Pre- and Post-Conditions

  • A formal way to document method contracts.
  • Pre-conditions describe what must be true before calling the method (caller’s responsibility):
/// <summary>
/// Sets the actor's location
/// Pre: x and y are both positive values
/// </summary>
public void SetLocation(int x, int y) { … }
  • Post-conditions describe what must be true after the method executes (method guarantees):
/// Post: the actor's location is set to (x,y)

Properties

  • Properties are a C# feature that behave like fields but are implemented via getters and setters.
  • They act as a replacement for traditional getter/setter methods and can enforce invariants.
  • Example of a class with properties and backing fields:
class Customer {
    private string name;
    private string addr;
    private int id;

    public string Name {
        get { return name; }
        set { name = value; }
    }

    public string Address {
        get { return addr; }
        set { addr = value; }
    }

    public int Id {
        get { return id; }
        set { id = value; }
    }
}

Getters

  • A property can have a getter that returns a value.
  • Example:
public int Count {
    get {
        return customers.Count;
    }
}
  • A getter alone is read-only.

Setters

  • A property may have a setter that validates and stores values:
public string Name {
    set {
        if (value == "" || value.Length > MAX_NAME_LENGTH) {
            throw new ArgumentException("Invalid value for name");
        }
        name = value;
    }
    get {
        return name;
    }
}

Auto-Implemented Properties

  • A shorthand that creates a private backing field automatically:
public string Address { get; set; }
  • The compiler generates an anonymous backing field behind the scenes.
  • You can still expose full property logic if needed by providing explicit getters/setters.

Auto-Implemented Properties vs Fields

  • Auto-implemented properties are functionally identical to fields for storage but offer flexibility for future changes.
  • Fields are harder to replace with properties without breaking the ABI (application binary interface).
  • Auto-implemented properties allow changing to explicit properties later without breaking external code (though semantic changes may still affect callers).

Tips for Using Properties

  • Use XML comments to describe properties (at the property level, not each getter/setter individually).
  • Route all access to the backing field through the property to preserve restrictions.
  • Ensure properties maintain the same semantics as fields (e.g., no unintended side effects in getters, setters that actually modify the value).

Static

  • The keyword static has three meanings in C# depending on what it is applied to:
    • Static methods/properties
    • Static fields
    • Static classes

Static Methods and Properties

  • Regular (non-static) methods require an instance of the class to be called.
    • Example: Employee.Pay() is called on a specific employee to generate an invoice.
  • Static methods do not operate on a specific instance; they are called on the class itself.
    • Example: Employee.PayAll(List<Employee> employees)
  • Static methods are appropriate when the method does not need instance data.

Static Fields

  • Static fields belong to the class, not to any instance.
  • They can be accessed without an instance (e.g., ClassName.Field).
  • They are dangerous and often discouraged for public use.
  • Private static fields can be used in certain legitimate scenarios.
  • One exception: const fields are implicitly static and allowed even if public.

Static Classes

  • Static classes cannot be instantiated.
  • They can contain only static methods and fields.
  • Static classes are often used as utility containers for commonly used methods.
  • They can have poor cohesion if a class collects unrelated methods merely for convenience.

Static - Conclusion (Best Practices)

  • Use static methods/properties where appropriate.
  • Avoid static fields unless there is a clear, legitimate need for a private static field.
  • Never use public static fields.
  • Use static classes where appropriate, but avoid grouping unrelated methods purely for convenience.

Acknowledgments and Closing

  • The slides include an acknowledgment of traditional landowners (First Nations) and a general thanks.
  • Acknowledgement of Traditional Owners: QUT acknowledges the Turrbal and Yugara as First Nations owners of the lands where QUT stands (cultural and teaching context).

Key Formulas and Notation (Summary)

  • Harmonic mean example from methods:
  • Harmonic mean of two numbers $a$ and $b$ is defined as
    \text{mean} = \frac{2ab}{a+b}

Quick Reference: Terminology

  • Class: a template for creating objects; defines fields and methods.
  • Object/Instance: a concrete realization of a class.
  • Field/Instance variable: data stored in an object.
  • Method: a function that operates on an object and may read/modify its fields.
  • Constructor: a special method used to initialize a new object; no return type.
  • Getter/Setter: accessors for a property.
  • Property: a member that provides controlled access to an internal field.
  • Nullable type (suffix ?): allows a value type to be null.
  • Null-coalescing operator: ??.
  • Null-conditional access: ?. and ?[].
  • In/Ref/Out: parameter passing modifiers with distinct semantics.
  • Optional arguments: default parameter values; named arguments.
  • Overloading: multiple methods with the same name but different parameter lists.
  • Static vs instance members: class-level vs per-object.

End of Notes

  • These notes reflect the contents of the CAB201 – Programming Principles transcript (object-oriented programming, C# concepts, and related practices) as presented in the slides.