summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter16/README.md113
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java20
2 files changed, 133 insertions, 0 deletions
diff --git a/chapter16/README.md b/chapter16/README.md
index a4761297..f21a08a5 100644
--- a/chapter16/README.md
+++ b/chapter16/README.md
@@ -1,2 +1,115 @@
# Chapter 16: Constructors and Final fields
+
+## Constructors
+
+A big problem with the [Chapter 13](../chapter13/README.md) refs is that
+not-null fields always start out `null`. This is fixed in this chapter, where
+a *constructor* syntax is required to initialize `final` and not-null fields.
+
+Fields are initialized in three ways:
+
+1. A default zero/null initialization for fields that allow it. No special
+ syntax is required.
+```
+int x; // x is initialized to 0
+struct Ref { Ref ptr?; }; // Instances of Ref will have ptr initialized to null
+return new Ref.ptr; // Returns a null
+```
+
+2. The type declaration can specify an initial value. Later allocations will
+ start with this value.
+```
+int x = 5; // x is initialized to 5
+struct Point { int x=1; int y=1; }; // Point x and y will start as 1, not 0
+return new Point.x; // Returns a 1
+```
+
+3. The allocation can specify an initial value.
+
+```
+struct Point { int x=1; int y=1; }; // Point x and y will start as 1, not 0
+return new Point { x=3; }.x; // Returns a 3
+```
+
+Not-null and final fields must be initialized before first use and before the
+end of the allocation. They can be initialized in either the declaration or
+allocation. They do not start with the default value, although the
+initialization can be to the default.
+
+```
+struct Person { u8[] name; }
+return new Person; // ERROR: not-null field name not initalized
+```
+
+
+## Initialization code
+
+The parser allows a full Block statement to be parsed in either the type
+declaration or the allocation. Any amount of code is legal, including
+`while` loops and `return`s.
+
+```
+struct Square {
+ flt !side = arg;
+ flt diag = arg*arg/2;
+ // Newtons approximation to the square root, done in a constructor
+ while( 1 ) {
+ // The next-guess variable "next" is not a field in Square,
+ // because it does not appear at the top level
+ flt next = (side/diag + diag)/2;
+ if( next == diag ) break;
+ diag = next;
+ }
+};
+return new Square;
+```
+
+```
+struct Buffer {
+ if( arg < 0 || arg > 1000000 )
+ return null; // Size out of bounds
+ u8[] buffer = new u8[arg];
+};
+return new Buffer;
+```
+
+
+## Final fields
+
+Final fields are declared with a `!` before the name:
+
+```
+int !x = 17; // Final field x
+x = 3; // ERROR: cannot re-assign a final field
+```
+
+```
+struct Person { u8[]? !name; }
+return new Person { name = null; }; // OK: final name is assigned
+```
+
+```
+struct Point { int !x; int !y; int !z; }
+return new Point { x=arg; y=z; z=x; } // ERROR: final field z used before initialized
+```
+
+```
+struct Point { int x; int y; int z; }
+return new Point { x=arg; y=z; z=x; } // Ok: x=arg, y=0, z=arg
+```
+
+
+### Multiple declarations of the same type
+
+Also new this chapter is allowing multiple declarations with the same type, as
+is commonly seen in other languages:
+
+```
+int x,y; // Two int variables declared
+struct Point { int x,y,z; } // Three fields declared
+```
+
+```
+int !x=3,!y=5; // Two int variables declared, both are final and initialized
+```
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java
index 7cd1604b..c4f9795f 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java
@@ -173,4 +173,24 @@ return next.i;
assertEquals(2L, Evaluator.evaluate(stop, 11));
}
+ @Test
+ public void testSquare() {
+ Parser parser = new Parser(
+"""
+struct Square {
+ flt !side = arg;
+ flt diag = arg*arg/2;
+ while( 1 ) {
+ flt next = (side/diag + diag)/2;
+ if( next == diag ) break;
+ diag = next;
+ }
+};
+return new Square;
+""");
+ StopNode stop = parser.parse().iterate();
+ assertEquals("return Square;", stop.toString());
+ assertEquals("Obj<Square>{side=3.0,diag=1.7320508075688772}", Evaluator.evaluate(stop, 3).toString());
+ assertEquals("Obj<Square>{side=4.0,diag=2.0}", Evaluator.evaluate(stop, 4).toString());
+ }
}