# NOTES — six files, one private constructor, and one trap that ships

Compile and run from the directory holding the sources:

```
..\..\..\.toolchain\jdk-21\bin\javac.exe -d out *.java
..\..\..\.toolchain\jdk-21\bin\java.exe -cp out Main
```

Plain `javac` exits 0 and prints nothing. Real output, from exactly this code:

```
== Tariff: named factories, one private constructor ==
standard()                      Tariff[motorbike=1000, car=2000, truck=4000]
perStartedHourRupees(10, 20, 40) Tariff[motorbike=1000, car=2000, truck=4000]
standard() twice, same object?   true
rejected before any Tariff existed: a car rate cannot be negative: -50

== LotConfig: no default arguments, so this(...) and named factories ==
new LotConfig(10)               LotConfig[spots=10, grace=0m, free=0h, Tariff[motorbike=1000, car=2000, truck=4000]]
withGraceMinutes(10, 15)        LotConfig[spots=10, grace=15m, free=0h, Tariff[motorbike=1000, car=2000, truck=4000]]
withFreeHours(10, 1)            LotConfig[spots=10, grace=0m, free=1h, Tariff[motorbike=1000, car=2000, truck=4000]]

== The virtual call from a constructor ==
new PrefixedNumbering(3, "S").spotIds() -> [null1, null2, null3]
new PaddedNumbering(3, "a") threw java.lang.NullPointerException
  message: Cannot invoke "String.toUpperCase()" because "this.prefix" is null
  top frames:
    at PaddedNumbering.label(SpotNumbering.java:67)
    at SpotNumbering.<init>(SpotNumbering.java:25)
    at PaddedNumbering.<init>(SpotNumbering.java:61)

== Initialisation order, printed in the order it happens ==
  new TracedNumbering(1, "S"):
     1  label(1) runs inside SpotNumbering's constructor; prefix is null
     2  field initialiser, declared first
     3  instance initialiser block, declared between the two fields
     4  field initialiser, declared second
     5  constructor body: the first statement that can see prefix=S
  ids: [S1], fields: 2  field initialiser, declared first then 4  field initialiser, declared second

== SafeNumbering: nothing overridable runs during construction ==
new SafeNumbering(3, "S").spotIds() -> [S1, S2, S3]
```

Three lines in there are the lesson. `standard() twice, same object? true`,
`[null1, null2, null3]`, and the order of the numbered trace.

---

## `Tariff.java`

```java
    private static final Tariff STANDARD = new Tariff(1000L, 2000L, 4000L);
```

**One object for the tariff the whole corpus uses.** This is only safe because every field
below is `final` and every field's type is a primitive. Nobody holding `STANDARD` can change
what another holder sees. Make one field non-`final` and this line becomes a shared mutable
global, which is the bug `synchronized` gets added to paper over. The `static` initialiser runs
once, when `Tariff` is first touched, before any of your code that mentions the class.

```java
    private final long motorbikeMinor;
    private final long carMinor;
    private final long truckMinor;
```

**`final` here is what lets `standard()` skip the copy.** Drop it and the class still compiles,
still passes every test in this lesson, and stops being shareable. Nothing in Java warns you.
The invariant is: after any constructor returns, these three values are fixed for the object's
whole life.

```java
    private Tariff(long motorbikeMinor, long carMinor, long truckMinor) {
        this.motorbikeMinor = motorbikeMinor;
        this.carMinor = carMinor;
        this.truckMinor = truckMinor;
    }
```

**`private`, and it is the only writer of any field in the class.** Two things follow. No caller
can build a `Tariff` that skipped validation, and there is exactly one place to look when a rate
is wrong. `javac` enforces the second half: assigning any of these three from a method gives
`error: cannot assign a value to final variable carMinor`.

**`this.` is not decoration here.** The parameters share the field names, so without `this.` the
line `motorbikeMinor = motorbikeMinor;` assigns the parameter to itself. That compiles, and the
field is then reported unassigned, which is the one time the error message saves you.

```java
    public static Tariff standard() {
        return STANDARD;
    }
```

**Returns the field, not `new Tariff(1000L, 2000L, 4000L)`.** `Main` prints
`standard() twice, same object? true` because of this line. `LotConfig`'s test asserts
`assertSame`, not `assertEquals`, so a version that constructs a fresh equal object fails.
A constructor cannot do this. `new` always allocates.

```java
    public static Tariff perStartedHourMinor(long motorbike, long car, long truck) {
        requireChargeable(motorbike, "motorbike");
        requireChargeable(car, "car");
        requireChargeable(truck, "truck");
        return new Tariff(motorbike, car, truck);
    }
```

**Every check runs before `new`.** That is the difference from a validating constructor. The gap
is smaller than it sounds, and it is real. A constructor that throws has already run `super()`
and every field initialiser, so a half-built object existed. It was reachable from anything
those steps handed `this` to. Here, nothing was allocated. `Main` shows the message:
`rejected before any Tariff existed: a car rate cannot be negative: -50`.

**The message names which rate.** `requireChargeable(car, "car")` passes the label because
`IllegalArgumentException: -50` would tell you nothing at 1am. `GapTest` asserts the message
contains `"car"` for exactly that reason.

```java
    public static Tariff perStartedHourRupees(long motorbike, long car, long truck) {
        return perStartedHourMinor(motorbike * 100L, car * 100L, truck * 100L);
    }
```

**Three `long`s, the same three types as the factory above it.** Two constructors with these
signatures do not compile: `error: constructor Tariff(long,long,long) is already defined in class Tariff`.
Two static factories do, because a method's name is part of its identity and a constructor's
name is the class. This is the reason to know static factories exist, and the one with no C++
counterpart, since default arguments meant you only wrote one constructor.

**It delegates rather than calling `new`.** So the validation is inherited rather than copied,
and a fourth vehicle type changes one method. `GapTest` checks that
`perStartedHourRupees(10, -20, 40)` throws, which only passes if this line goes through the
other factory.

```java
    public long minorPerStartedHour(VehicleType type) {
        return switch (type) {
            case MOTORBIKE -> motorbikeMinor;
```

**An exhaustive `switch` over the enum with no `default`.** A fourth `VehicleType` stops
compiling here, which is where a new vehicle should force a decision about its rate. Adding
`default -> 0` would make a new type silently free.

---

## `LotConfig.java`

```java
    public LotConfig(int standardSpots) {
        this(standardSpots, Tariff.standard(), 0, 0);
    }
```

**The whole body is one delegation, and it assigns nothing.** That is deliberate: the four
fields are `final`, and a second assignment anywhere would not compile. So this constructor
cannot drift from the canonical one, cannot skip its validation, and cannot half-apply it.
`GapTest` proves the last part by checking `new LotConfig(0)` throws with `at least one spot`,
a message that only exists in the canonical constructor.

This is also what keeps `contract/Entry.java` to one line. C++ would have used a default
argument and written no second constructor at all.

```java
    public LotConfig(int standardSpots, Tariff tariff, int graceMinutes, int freeHours) {
        if (standardSpots < 1) {
            throw new IllegalArgumentException("a lot needs at least one spot, got " + standardSpots);
        }
```

**Validation before the assignments, not after.** After the assignments the object is built and
throwing leaves a fully-formed invalid object reachable by anything the constructor already
passed `this` to. Here nothing has been assigned and nothing has escaped.

**The message includes the value.** `got 0` is the difference between a one-second diagnosis and
reading the call site.

```java
        this.tariff = Objects.requireNonNull(tariff, "tariff");
```

**`requireNonNull` returns its argument, so the check and the assignment are one statement.**
The invariant: a `LotConfig` never holds a null tariff, so no code downstream needs a null
check. Without it the failure surfaces later, in whichever method first calls
`tariff.minorPerStartedHour(...)`, with a stack trace pointing at the wrong class. The string
`"tariff"` is the message, and it is what tells you which of four arguments was null.

```java
    public static LotConfig withGraceMinutes(int standardSpots, int graceMinutes) { … }
    public static LotConfig withFreeHours(int standardSpots, int freeHours)       { … }
```

**Two `(int, int)` signatures, both legal, because factories have names.** As constructors they
would collide. And the call site reads: `LotConfig.withFreeHours(10, 1)` says which `1` that
is, where `new LotConfig(10, 1)` would not. Curveball 02 is the requirement behind the second
one, so this is not a hypothetical shape.

Note what these two do *not* do: they add no field, no interface, and no layer. Each is one
`return`. That is the level of ceremony a factory should cost. `Vehicle` in `contract/` has a
public record constructor and no factory, and that is correct, because there is one way to
build one and it cannot fail.

---

## `SpotNumbering.java` — the file to read twice

The contract says spot ids are yours to invent: `"S1"`, `"1"`, `"A-01"`. A base class that owns
the numbering and asks the subclass what each label is called is a reasonable-looking split.

```java
    protected SpotNumbering(int count) {
        List<String> ids = new ArrayList<>(count);
        for (int i = 1; i <= count; i++) {
            ids.add(label(i));
        }
        this.spotIds = List.copyOf(ids);
    }
```

**The loop fills a local and the field is assigned once, after it.** Not a style choice.
Assigning the field inside the loop gives two errors at once:
`variable spotIds might be assigned in loop` and `variable spotIds might not have been initialized`.
`javac` cannot rule out zero iterations or two, so it refuses both.

**`List.copyOf` is what makes the field's `final` mean something.** `final` stops the reference
being repointed; it says nothing about the list. Hand out the `ArrayList` and any caller can
renumber the lot. This is the `final`-is-not-`const` trap in its most common form, and J6
returns to it.

**`ids.add(label(i))` is the bug.** `label` is overridable and `this` is a `PrefixedNumbering`,
so the call lands on the override, which reads `prefix`. `PrefixedNumbering`'s constructor has
not reached `this.prefix = prefix` yet, because `super(count)` has to complete first. The field
holds `null`.

The consequence, unedited:

```
new PrefixedNumbering(3, "S").spotIds() -> [null1, null2, null3]
```

String concatenation with `null` produces `"null"`, so the ids look almost plausible and no
exception is thrown. `PaddedNumbering` calls `prefix.toUpperCase()` instead and throws, which
is the luckier outcome. Java 21's message names the field:

```
Cannot invoke "String.toUpperCase()" because "this.prefix" is null
```

**Neither version produces a warning from plain `javac`.** One flag changes that:

```
> javac -Xlint:this-escape -d out lessons/J4/worked/src/*.java
lessons\J4\worked\src\SpotNumbering.java:25: warning: [this-escape] possible 'this' escape before subclass is fully initialized
            ids.add(label(i));
                         ^
1 warning
```

Exactly one warning, on line 25, which is `ids.add(label(i))`. Worth adding to any build where
classes are extensible.

### `TracedNumbering`, and why the order is what it is

```java
    private final String prefix;
    private final String declaredFirst = say("2  field initialiser, declared first");
    { say("3  instance initialiser block, declared between the two fields"); }
    private final String declaredSecond = say("4  field initialiser, declared second");
```

**The instance initialiser block sits between the two fields on purpose.** The trace prints 2,
3, 4 in that order, which is the point: field initialisers and instance blocks are one sequence
in declaration order, not two phases. Moving the block above `declaredFirst` changes the output.

**All of it runs after `super(count)` and before the constructor body.** So the numbered trace
is the full rule:

1. `super(...)` completes, which is where `label(1)` ran and read `null`
2. field initialisers and instance initialiser blocks, top to bottom
3. the constructor body

A field initialiser is a constructor statement `javac` relocates for you. Referring to a field
declared below one gives `error: illegal forward reference`, which is the only visible trace of
the relocation.

---

## `SafeNumbering.java` — the same job, trap-free

```java
    public SafeNumbering(int count, String prefix) {
        this.spotIds = labels(count, prefix);
    }

    private static List<String> labels(int count, String prefix) {
```

**`static` is the load-bearing word.** A `static` method has no `this`, so it cannot read a
field that has no value yet. The compiler enforces it rather than a convention. Try to route an
instance method through `super(...)` and you get
`error: cannot reference this before supertype constructor has been called`.

**The class is `final` and does not extend anything.** Belt and braces: with no subclass there
is no override, so nothing overridable can run during construction. This is the shape
`corpus/parking-lot/reference/src/SpotGrid.java` uses for the identical problem, and it is the
one to reach for in a timed round. A base class that calls back into its subclass is a design
worth avoiding rather than a hazard worth managing.

**`List.copyOf` inside the static helper, so the field is unmodifiable from the moment it is
assigned.** `spotIds()` then hands the field straight out with no copy. One `copyOf` at
construction replaces one per call.
