import java.util.*; sealed interface AncTree permits Unknown, Child { int size(); AncTree changeName( /* AncTree this, */ String before, String after ); } record Unknown() implements AncTree { public int size(/*Unknown this*/) { return 0; } public Unknown changeName( /* AncTree this, */ String before, String after ) { return this; } } record Child(String name, int yob, String eye, AncTree ma, AncTree pa) implements AncTree { public int size(/*Unknown this*/) { return this.ma().size() + 1 + this.pa().size(); } public Child changeName(/*Child this,*/ String before, String after ) { return new Child( this.name.equals(before) ? after : this.name, this.yob(), this.eye(), this.ma().changeName(before,after), this.pa().changeName(before,after) ); } } class TestAncTree { static void testSize() { assert( unk.size() == 0 ); assert( jackie.size() == 1 ); assert( marge.size() == 2 ); assert( homer.size() == 3 ); assert( lisa.size() == 6 ); } static void testChangeName() { assert unk.changeName( "Homer", "El Homero" ).equals( unk ); assert jackie.changeName( "Homer", "El Homero" ).equals( jackie ); assert marge.changeName( "Homer", "El Homero" ).equals( marge ); assert homer.changeName( "Homer", "El Homero" ).equals( new Child( "El Homero", homer.yob(), homer.eye(), homer.ma().changeName( "Homer", "El Homero" ), homer.pa().changeName( "Homer", "El Homero" ) ) ); assert bart.changeName( "Homer", "El Homero" ).equals( new Child( "Bart", bart.yob(), bart.eye(), marge, new Child( "El Homero", homer.yob(), homer.eye(), mona, abe ) ) ); } static void printSome() { System.out.printf( "%s\n", new Child("marge", 1956, "blue", new Child( "jackie", 1917, "brown", new Unknown(), new Unknown() ), new Unknown() ) ); } // fields of class `Test`: static AncTree unk = new Unknown(); static AncTree jackie = new Child("jackie", 1917, "brown", unk, unk ); static AncTree marge = new Child("marge", 1956, "blue", jackie, unk ); static AncTree abe = new Child( "Abe", 1920, "blue", unk, unk ); static AncTree mona = new Child( "Mona", 1929, "brown", unk, unk ); static Child homer = new Child( "Homer", 1955, "brown", mona, abe ); static Child bart = new Child( "Bart", 1979, "brown", marge, homer ); static AncTree lisa = new Child( "Lisa", 1980, "blue", marge, homer ); static AncTree maggie = new Child( "Maggie", 1982, "brown", marge, homer ); public static void main(String... __) { testAll(); } static boolean TEST_VERBOSE = true; static void testAll() { confirmAssertionsEnabled(); printSome(); testSize(); } static void confirmAssertionsEnabled() { boolean ea = true; try { assert false; ea = false; // If we made it here, assertions weren't actually enabled, in the jvm! } catch (AssertionError err) { /* I meant for this to happen... */ } if (!ea) { String errMsg = "Assertions not enabled; can't test.\n" + " To test, re-run jvm with `java --enableassertions …` or `java -ea …`.\n"; String errMsgTips = " (I recommend *always* running with `java -ea …`.)\n" + " (I also recommend using jUnit instead of raw `assert`s, for testing !-)\n"; throw new AssertionError(errMsg + errMsgTips); } if (TEST_VERBOSE) { System.out.println( "Assertions enabled." ); } } }