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