I think I see what you mean, although to me the general characterization as 
construction/deconstruction is too narrow - there are a zillion ways to pack-in 
and pack-out the tree, some partial, and some lossy etc. The canonical 
pack-in/out is arguably parsing and writing from and to JSON documents.

fromUptyped is way to “pack-in” the tree, transforming maps and lists, where 
leaf elements are directly input to the construction of JSON (leaf) values. 
toUptyped is the functional inverse to "pack-out”, and when we have 
deconstructor patterns we can more clearly and concisely express the 
deconstruction relationship in the switch statement e.g., perhaps like [1]. I 
think it a feature that they directly lean into construction and (currently 
implement) deconstruction of JSON values without much or any embellishment.

This of course punts on the problem of dealing with present, absent, or null 
values of a field. Perhaps that is more suited for data binding use cases?

Paul.

[1]
    public static Object toUntyped(JsonValue src) {
        Objects.requireNonNull(src);
        return switch (src) {
            case JsonObject(Map<String, JsonValue> members)) -> 
members.entrySet().stream()
                    .collect(LinkedHashMap::new, // to allow `null` value
                            (m, e) -> m.put(e.getKey(), 
Json.toUntyped(e.getValue())),
                            HashMap::putAll);
            case JsonArray(List<JsonValue> values)) -> values.stream()
                    .map(Json::toUntyped)
                    .toList();
            case JsonBoolean(boolean value) -> value;
            case JsonNull _ -> null;
            case JsonNumber(Number value) -> value;
            case JsonString(String value) -> value;
        };
    }

On May 19, 2025, at 3:46 PM, Ethan McCue <et...@mccue.dev> wrote:

What I mean by central in this context isn't that it's at the core of things 
and features are built on top of it - as you note it is a valid transformation 
of the hierarchy.

What I mean is that absent other construction/deconstruction apis it is the 
most convenient avenue for those tasks. So code using the API would trend 
towards using it. See Remi's usage of fromUntyped elsewhere in the discussion 
tree.

The thing that the language doesn't have yet is patterns. We have all the 
mechanism for creating objects. The broad issue I see is that, if we take the 
view that >in general< deconstruction should be the dual of construction - the 
mechanics for construction should probably be influenced by how you want people 
pulling these things apart.

Basic example - JsonString.of - that is null hostile for good reason, but it is 
very easy to imagine wanting to write code that deals uniformly with absent, 
null, and string values for a field in an object.

So that puts a pressure - beyond creation ergonomics - on a Json.of that is 
null-tolerant. Since that would be a good place for a dual pattern for pulling 
out a possibly nullable object member.

(but still wouldn't solve for absent ones - I have a doc somewhere with like 15 
options none of which inspire joy and many of which are conditional on exactly 
how patterns ship)

On Mon, May 19, 2025, 3:55 PM Paul Sandoz 
<paul.san...@oracle.com<mailto:paul.san...@oracle.com>> wrote:

>
> This is part of why fromUntyped/toUntyped is uncomfortable - it's choosing 
> one particular encoding of JSON and making it central to the API. Is that 
> really the most important encoding?
>


It's one opinionated kind, a simple bi-directional mapping 
(embedding-projection pair) based on what the json values contain. The 
implementations can be entirely written less than 100 lines of code using the 
public API (there are more lines for the documentation). Users can easily write 
their own and can serve as an example with a bit more exposition in the 
documentation. The methods could be removed and it would not affect anything 
else, so it's not fundamental nor central.

Paul.

Reply via email to