My experience building a path-finding algorithm using Amber

Brian Goetz brian.goetz at oracle.com
Wed Apr 26 14:36:14 UTC 2023


Thanks for the nice success story and the kind words.  A few comments:

> Since all elements of this structure were either sealed, a record, or 
> an enum, that meant that my domain of possible types (and thus, 
> solutions) was very bounded. That boundedness made reasoning about my 
> domain much easier.

This is the power of "make illegal states unrepresentable".  By using 
the type system to represent only the valid states of your domain, code 
can focus on the happy path.

I want to dig a little into the one "still could be improved" comment:

> * Converting untyped data into typed data still feels frustrating and 
> difficult. I was able to bypass most of it this time around because, 
> thankfully, this project had very little conversion (whereas my 
> previous project [2] was completely built around that concept)

Indeed, there is more to go here.  The good news is that this challenge 
is a big part of why we embarked on the pattern matching story in the 
first place.  We've gotten far enough on this story that it has enabled 
some of the things you talk about, but we still have a ways to go.

Untyped data is a fact of life; Java is not a bubble, and we will always 
be dealing with unstructured user input, untyped documents like JSON, or 
typed data from another type system, such as SQL result sets or XML 
which rigorously uses schema to enforce types.  Even if an XSD tells us 
that a given element or attribute is of type `xsd:integer`, that doesn't 
mean "signed 32 bit int".  And as program units get "smaller" (break up 
them monoliths), all the code gets "closer to the boundary", and at the 
boundary, things are untyped.

There are several approaches to untyped data taken by Java programs, all 
of which are pretty limited:

  - Deal with it directly as untyped data.  This makes our Java programs 
stringly typed.

  - Try to map it automatically via ORMs, JAXB, and similar data binding 
mechanisms.  This is practical for semi-typed data, but often runs out 
of gas before we're done.

  - Painstakingly unpack it into Java data using imperative tools like 
JSON-P.  This typically results in large masses of error-prone and 
brittle code (Does it have a key called X?  Is that key mapped to an 
integer?  Is that integer within range of `int`?).  It is not uncommon 
to see 50-100 lines of awful "unpacking" code followed by a few lines of 
clean "business logic" and then some more "repacking code".  This often 
makes me wonder "Where's the Beef?"

To deal with untyped data, we need an organized way to define the 
boundary.  To avoid descending into a rat's nest of horrible imperative 
checks like the third solution, our boundary management tools need to 
*compose*.

Pattern matching composes.  If I'm trying to match `"x": "3"` to extract 
the int value, I need a way to express "key X", "maps to double", 
"double can be converted to int" in a single go, not treat it as three 
separate sources of error, and ignore the parts of the structure I am 
not interested in.  The key thing the language was missing to get there 
was a flexible, composable, fused test-and-conditionally-extract 
operation. More to come!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230426/7411ecf4/attachment.htm>


More information about the amber-dev mailing list