Skip to content

Commit f6291f0

Browse files
committed
Detail the JSON getter design options.
This sketches the consideration for adding `apply()` methods to JSON, together with potential alternatives. ponylang/ponyc#3922
1 parent b0294c8 commit f6291f0

File tree

1 file changed

+103
-16
lines changed

1 file changed

+103
-16
lines changed

text/0000-json-getters.md

+103-16
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,126 @@ Introduce "getters" into the JSON package. Specifically access methods for
1010

1111
# Motivation
1212

13-
TODO Why are we doing this? What use cases does it support? What is the expected outcome?
13+
Currently the interaction between the JSON API and the Pony reference
14+
capability type system makes it difficult to work with JSON documents that need
15+
to be mutated after they have been created.
16+
17+
By introducing getter methods it will be possible to leverage viewpoint
18+
adaptation to enable mutations when the caller site holds a mutable reference,
19+
but to enforce immutability when the calling alias is a `val` or `box`.
20+
21+
Additionally, a caller with an `iso` reference will be able to perform
22+
mutations to the document and then recover and `iso` reference afterwards.
1423

1524
# Detailed design
1625

17-
TODO This is the bulk of the RFC. Explain the design in enough detail for somebody familiar with the language to understand, and for somebody familiar with the compiler to implement. This should get into specifics and corner-cases, and include examples of how the feature is used.
26+
The implementation consists of using the `apply()` style access to introducing
27+
three getters, into `JsonDoc`, `JsonObject` and `JsonArray` respectively:
1828

19-
# How We Teach This
29+
- document data access: `fun apply(): this->JsonType! => ...`,
30+
- object data access: `fun apply(): this->Array[JsonType]! => ...`,
31+
- array data access: `fun apply(): this->Map[String, JsonType]! => ...`.
32+
33+
These access methods can then be used via direct calls or via syntactic sugar
34+
calls.
2035

21-
TODO What names and terminology work best for these concepts and why? How is this idea best presented? As a continuation of existing Pony patterns, or as a wholly new one?
36+
# How We Teach This
2237

23-
Would the acceptance of this proposal mean the Pony guides must be re-organized or altered? Does it change how Pony is taught to new users at any level?
38+
The examples in the JSON inline documentation can be extended or changed to
39+
demonstrate the usage of the getter methods.
2440

25-
How should this feature be introduced and taught to existing Pony users?
41+
The access methods, themselves, will be documented.
2642

2743
# How We Test This
2844

29-
TODO How do we assure that the initial implementation works? How do we assure going forward that the new functionality works after people make changes? Do we need unit tests? Something more sophisticated? What's the scope of testing? Does this change impact the testing of other parts of Pony? Is our standard CI coverage sufficient to test this change? Is manual intervention required?
30-
31-
In general this section should be able to serve as acceptance criteria for any implementation of the RFC.
45+
Unit tests that cover both mutable access and immutable access, as well is the
46+
recovery of `iso` documents after mutation.
3247

3348
# Drawbacks
3449

35-
TODO Why should we *not* do this? Things you might want to note:
50+
This is a purely additive change, so it does not incur in major risk in terms of
51+
existing code. Additionally, the code complexity is low and should be easy to
52+
maintain.
53+
54+
## Uptake and entrenchment
55+
56+
However, if there is uptake following these additions, the approach will likely
57+
become entrenched, and therefore difficult to revert. Therefore, we need to be
58+
comfortable with this approach going forward.
3659

37-
* Breaks existing code
38-
* Introduces instability into the compiler and or runtime which will result in bugs we are going to spend time tracking down
39-
* Maintenance cost of added code
60+
## Syntactic sugar oddities
61+
62+
By relying on the `apply()` syntactic sugar it is possible to write expressions
63+
that are a little contrived:
64+
65+
```pony
66+
(jdoc_ref() as JsonObject)()("other_stuff") = "hello"
67+
```
68+
69+
which might be more easily read if written as:
70+
71+
```pony
72+
(jdoc_ref() as JsonObject).apply()("other_stuff") = "hello"
73+
```
4074

4175
# Alternatives
4276

43-
TODO What other designs have been considered? What is the impact of not doing this?
44-
None is not an acceptable answer. There is always to option of not implementing the RFC.
77+
The basic approach of adding "getter" access methods seems quite reasonable.
78+
However, the issue of method naming is really the point where alternative could
79+
be considered.
80+
81+
## The current recommendation
82+
83+
A purely additive change using the `apply()` syntactic sugar for access. This
84+
allows one to write:
85+
86+
```pony
87+
try
88+
let obj = (json_doc() as JsonObject)
89+
obj()("more") = "stuff"
90+
end
91+
```
92+
93+
## Additionally include `update()`
94+
95+
That is, include an `update(value: JsonDoc): this->JsonType! => ...` method to
96+
allow for setting the underlying `data` field.
97+
98+
## Convert the `data` field to private
99+
100+
The above recommendation is a non-breaking change. Therefore, the current `data`
101+
field, which is public has be left as-is. However, it might be better
102+
standardise on using the access methods and make the data field private. That
103+
is, rename the field to:
104+
105+
- `_data`
106+
107+
The drawbacks of this approach are:
108+
109+
- it becomes a breaking change for all existing code,
110+
- it would require the addition of a setter (such as introducing `update(...)`).
111+
112+
## Use `data()` as the access method
113+
114+
If make the data field private, we can consider using `data` as the access
115+
method name. In this case we would not provide the syntactic sugar, but we would
116+
still solve the core problem of data mutation.
117+
118+
However, the drawback of this approach is that a separate "setter" may be
119+
needed.
120+
121+
## Dual access with `apply()` and `data()`
122+
123+
Given that the syntactic sugar approach can sometime look odd, we could consider
124+
providing both `apply()` and `data()`. However, the drawbacks of this approach
125+
are:
126+
127+
- it burdens the API user with the choice of calling `data()` or using the sugar
128+
(or even calling `apply()`,
129+
- it would still require providing a setter of some form.
130+
45131

46132
# Unresolved questions
47133

48-
TODO What parts of the design are still TBD?
134+
Should a deeper design review be carried out? Otherwise, the alternatives,
135+
above, should cover the bulk of the potential questions.

0 commit comments

Comments
 (0)