diff options
| -rw-r--r-- | chapter16/README.md | 113 | ||||
| -rw-r--r-- | chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java | 20 |
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()); + } } |
