What a Class Actually Is
A class is a blueprint. A class definition is like a recipe for a cookie-cutter machine: it describes exactly what properties every object will have and what actions every object can perform. When you call new OrderedPair(x, y), you activate the blueprint and produce one specific object — one cookie — with its own x, y, label, and distance from the origin.
The OrderedPair class packages four properties and six behaviors into a single, self-maintaining unit. The properties (fields) are private: nothing outside the class can reach ptA.absVal directly. The class controls its own state, exposing only what it chooses through getters and a setter. That control is encapsulation — the first principle OOP was designed to enforce.
The three constructors reveal another OOP essential: multiple construction paths. The same class can produce an origin, a specific point, or a transposed copy — depending on what you pass. Every constructor calls computeAbsVal(), which means the object always maintains its own integrity from the moment it is built.
This concept page shows the driver first — the code that creates objects and calls methods — then the class definition. Read them together: the driver shows what the class does from the outside; the blueprint shows how it does it on the inside.
The class anatomy, before any language
── FIELDS (private) ─────────────────────────────────
x, y ← double (the coordinates)
absVal ← double (√x²+y² — distance from origin)
label ← String (name of this point)
── CONSTRUCTORS ─────────────────────────────────────
OrderedPair() ← default: origin (0,0), label = "O"
OrderedPair(x, y) ← place at coords, label = "P"
OrderedPair(orig) ← copy: label = orig.label + "_transpose"
── GETTERS (read-only access) ────────────────────────
getAbsVal() → number
getLabel() → string
── SETTER (one controlled mutation from outside) ─────
setLabel(lbl)
── UTILITY METHODS ──────────────────────────────────
computeAbsVal() ← √(x²+y²) — called by each constructor
transpose() ← swap x ↔ y in place
Every code panel below is a direct translation of this anatomy. Fields become instance variables; constructors become constructor methods; the class controls what gets in and what gets out.
Calling the Class — Driver Programs
These files create objects and call methods. They never touch a field directly — every read goes through a getter. Compare how each language calls the same three constructor paths.
// Paste OrderedPair.js into DevTools Console
// first, then paste this file.
// Return function — mirrors Java's static double f(x)
function f(x) {
console.log("...f...");
var m = 3.0;
var b = 2.0;
return m * x + b;
}//end f
console.log("=== Ordered Pair Runner ===\n");
var x = 2.0;
var y = f(x); // y = 8.0 — captured
console.log("f(" + x + ") = " + y);
console.log("\n--- Creating the Origin ---");
var origin = new OrderedPair();
console.log("origin = " + origin.toString());
console.log("\n--- Creating a Point ---");
var ptA = new OrderedPair(x, y);
console.log("ptA = " + ptA.toString());
ptA.setLabel("A");
console.log("ptA = " + ptA.toString());
//console.log(ptA._absVal); // works but breaks encapsulation
console.log("AbsVal ptA = " + ptA.getAbsVal());
console.log("\n--- Creating a Transposed Point ---");
var ptA_t = new OrderedPair(ptA); // instanceof → copy path
ptA_t.transpose();
console.log("ptA_transpose = " + ptA_t.toString());
console.log("AbsVal " + ptA_t.getLabel()
+ " = " + ptA_t.getAbsVal());
console.log("\n--- Thanks for using our program! ---");
public class OrderedPairDriver{
public static void main(String[] args){
System.out.println(
"=== Ordered Pair Driver ===\n");
double x = 2.0;
double y = f(x); // y = 8.0 — captured
System.out.println(
"f(" + x + ") = " + y
);
System.out.println(
"\n--- Creating the Origin ---");
OrderedPair origin = new OrderedPair();
System.out.println("origin = " + origin);
System.out.println(
"\n--- Creating a Point ---");
OrderedPair ptA = new OrderedPair(x, y);
System.out.println("ptA = " + ptA);
ptA.setLabel("A");
System.out.println("ptA = " + ptA);
//System.out.println(ptA.absVal); // compile error: private
System.out.println(
"AbsVal ptA = " + ptA.getAbsVal());
System.out.println(
"\n--- Creating a Transposed Point ---");
OrderedPair ptA_t = new OrderedPair(ptA);
ptA_t.transpose();
System.out.println(
"ptA_transpose = " + ptA_t);
System.out.println("AbsVal "
+ ptA_t.getLabel()
+ " = " + ptA_t.getAbsVal());
System.out.println(
"\n--- Thanks for using our program! ---");
}//end main
// Return function: return type declared in signature
public static double f(double x) {
System.out.println("...f...");
double m = 3.0;
double b = 2.0;
return m * x + b;
}//end f
}//end class
# Add OrderedPair.py as a second file in
# OnlineGDB, then run this file.
from OrderedPair import OrderedPair
# Return function — mirrors Java's static double f(x)
def f(x):
print("...f...")
m = 3.0
b = 2.0
return m * x + b
#end f
def main():
print("=== Ordered Pair Main ===\n")
x = 2.0
y = f(x) # y = 8.0 — captured
print(f"f({x}) = {y}")
print("\n--- Creating the Origin ---")
origin = OrderedPair()
print("origin =", origin)
print("\n--- Creating a Point ---")
ptA = OrderedPair(x, y)
print("ptA =", ptA)
ptA.set_label("A")
print("ptA =", ptA)
#print(ptA._abs_val) # accessible but breaks encapsulation
print("AbsVal ptA =", ptA.get_abs_val())
print("\n--- Creating a Transposed Point ---")
ptA_t = OrderedPair.from_ordered_pair(ptA)
ptA_t.transpose()
print("ptA_transpose =", ptA_t)
print("AbsVal", ptA_t.get_label(),
"=", ptA_t.get_abs_val())
print("\n--- Thanks for using our program! ---")
if __name__ == "__main__":
main()
The Class Definitions
Same anatomy. Same logic. Study how each language declares fields, handles multiple constructors, and controls access to private state.
// One constructor; instanceof detects which
// "constructor path" the caller intends.
// Underscore = private by convention only.
class OrderedPair {
constructor(xOrOrig, y) {
if (xOrOrig instanceof OrderedPair) {
// ── copy constructor path ──────────
console.log("...copy constructor...");
this._x = xOrOrig._x;
this._y = xOrOrig._y;
this._absVal = this._computeAbsVal();
this._label = xOrOrig._label
+ "_transpose";
} else if (xOrOrig !== undefined
&& y !== undefined) {
// ── two-parameter path ─────────────
console.log("...two parameter constructor...");
this._x = xOrOrig;
this._y = y;
this._absVal = this._computeAbsVal();
this._label = "P";
} else {
// ── default path ───────────────────
console.log("...default constructor...");
this._x = 0;
this._y = 0;
this._absVal = this._computeAbsVal();
this._label = "O";
}
}
toString() {
return this._label
+ "(" + this._x + ", " + this._y + ")";
}
getAbsVal() { return this._absVal; }
getLabel() { return this._label; }
setLabel(lbl) {
console.log("...setLabel...");
this._label = lbl;
}
_computeAbsVal() {
console.log("...computeAbsVal...");
return Math.sqrt(
Math.pow(this._x, 2)
+ Math.pow(this._y, 2));
}
transpose() {
console.log("...transpose...");
var temp = this._y;
this._y = this._x;
this._x = temp;
}
}//end class OrderedPair
//(P)erhaps (C)lown (N)onsense (I)s (C)onstructive
//(O)nly (T)oward (G)etting (S)ettlers (U)nderwear
public class OrderedPair {
// instance variables — private: enforced by compiler
private double x;
private double y;
private double absVal;
private String label;
// default constructor
public OrderedPair(){
System.out.println("...default constructor...");
x = 0;
y = 0;
absVal = computeAbsVal();
label = "O";
}//default constructor
// two-parameter constructor
// this.x disambiguates field from parameter
public OrderedPair(double x, double y){
System.out.println(
"...two parameter constructor...");
this.x = x;
this.y = y;
absVal = computeAbsVal();
label = "P";
}//two-parameter constructor
// copy constructor
public OrderedPair(OrderedPair orig){
System.out.println("...copy constructor...");
x = orig.x;
y = orig.y;
absVal = computeAbsVal();
label = orig.label + "_transpose";
}//end copy constructor
// override toString
public String toString(){
String temp = label + "(";
temp += x + ", " + y + ")";
return temp;
}//end toString
// getters (accessors)
public double getAbsVal(){ return absVal; }
public String getLabel() { return label; }
// setter (mutator)
public void setLabel(String lbl){
System.out.println("...setLabel...");
//dwr!
label = lbl;
}//end setLabel
// utility methods
public double computeAbsVal(){
System.out.println("...computeAbsVal...");
return Math.sqrt(
Math.pow(x, 2) + Math.pow(y, 2));
}//end computeAbsVal
public void transpose(){
System.out.println("...transpose...");
// classic swap
double temp = y;
y = x;
x = temp;
}//end transpose
}//end class OrderedPair
# One __init__; @classmethod is the copy
# constructor. 'self' is explicit everywhere.
import math
class OrderedPair:
def __init__(self, x=0.0, y=0.0):
"""Default + two-parameter constructor."""
print("...constructor...")
self._x = x
self._y = y
self._abs_val = self._compute_abs_val()
self._label = "O" \
if (x == 0.0 and y == 0.0) else "P"
@classmethod
def from_ordered_pair(cls, orig):
"""Python's substitute for the copy constructor.
@classmethod receives the class as 'cls';
delegates to __init__ for base setup.
"""
print("...copy constructor (classmethod)...")
instance = cls(orig._x, orig._y)
instance._label = orig._label + "_transpose"
return instance
# __str__ = Python's toString()
def __str__(self):
return (self._label
+ "(" + str(self._x)
+ ", " + str(self._y) + ")")
# getters (accessors)
def get_abs_val(self): return self._abs_val
def get_label(self): return self._label
# setter (mutator)
def set_label(self, lbl):
print("...set_label...")
self._label = lbl
# private utility method
def _compute_abs_val(self):
print("...compute_abs_val...")
return math.sqrt(
self._x ** 2 + self._y ** 2)
def transpose(self):
print("...transpose...")
# Pythonic swap — no temp variable needed
self._x, self._y = self._y, self._x
#end class OrderedPair
Why Does Each Version Look Different?
The guiding question for every Cross Training page: “What does each version reveal about the language’s personality?”
One constructor, all three paths. JavaScript allows exactly one constructor per class. Java allows as many as you want, distinguished by their parameter signatures — the compiler picks the right one at compile time. JavaScript makes that choice at runtime instead, using instanceof to detect what kind of argument was passed. The logic is explicit and readable, but it puts the branching burden on you as the programmer.
Private by convention, not enforcement. The underscore prefix on _x and _absVal is a team agreement, not a language rule. Nothing stops a caller from writing ptA._absVal. JavaScript ES2022 introduced true private fields with the # prefix (#x, #absVal), which the engine does enforce — but browser compatibility varies and they are not used here. The key lesson: JavaScript trusts the programmer. Java does not.
toString() is implicit. When you write "origin = " + origin, JavaScript automatically calls toString() on the object. This is identical to Java’s behavior and one of the few places where the two languages feel exactly the same.
Constructor overloading. Java’s three public OrderedPair(...) signatures are completely separate methods. The compiler resolves which one to call based on the argument types at compile time — no branching logic needed at runtime. This is overloading: same name, different signatures. It is one of Java’s most powerful (and most tested) design features.
private is enforced. The commented-out line //System.out.println(ptA.absVal); is not just a style suggestion — it is a compile error. private double absVal means the compiler actively prevents any class other than OrderedPair from reading that field. Encapsulation is not a convention in Java; it is a contract the compiler guarantees.
this.x = x disambiguation. In the two-parameter constructor, the parameter and the field share the same name. this.x refers unambiguously to the field; plain x refers to the parameter. This pattern appears constantly in Java constructors and is worth recognizing on sight.
__init__ with default parameters. Python’s single __init__ handles both the no-arg and two-arg cases through default parameter values: def __init__(self, x=0.0, y=0.0). No branching needed. For the copy constructor, Python uses a @classmethod factory — a method that receives the class itself (as cls) rather than an instance, and returns a freshly constructed object. This is the Pythonic substitute for Java’s overloaded copy constructor.
self is explicit everywhere. Every instance method must list self as its first parameter. Java and JavaScript have implicit this; Python makes the receiver visible. This is not boilerplate — it is a deliberate design decision. Python’s philosophy: explicit is better than implicit. self also appears in every field reference: self._x, self._abs_val. There is no ambiguity about what x refers to — it always refers to the local scope.
Pythonic swap. self._x, self._y = self._y, self._x swaps two values in one line with no temporary variable. Java and JavaScript both require the classic temp = y; y = x; x = temp pattern. Python evaluates the right side completely before any assignment begins — tuple packing and unpacking does the rest. One line. Right intention.
Classes & OOP