Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change refcap of JsonDoc to ref for better usability #2747

Merged
merged 2 commits into from
Jun 18, 2018
Merged

Change refcap of JsonDoc to ref for better usability #2747

merged 2 commits into from
Jun 18, 2018

Conversation

mfelsche
Copy link
Contributor

@mfelsche mfelsche commented Jun 5, 2018

JsonType has not been sendable anyways as JsonObject and JsonArray have been of refcap ref in JsonType,
so this only changes JsonDoc to be non-sendable, which should only have very little effect.

My first iteration was to make JsonDoc, JsonObject and JsonArray iso but this turned out to be cumbersome to use (especially when traversing into nested structures).
The other possibility would be to make all elements of JsonType val but this also turns out to be a little limiting when constructing a JSON structure, so i went with
the least invasive way for now.

Also added some package docs.

@mfelsche mfelsche added the changelog - changed Automatically add "Changed" CHANGELOG entry on merge label Jun 5, 2018
@SeanTAllen
Copy link
Member

I think it makes sense to fork off the json library stuff into an external package and work on it there where it is free from having to go through the RFC process.

@mfelsche
Copy link
Contributor Author

mfelsche commented Jun 5, 2018

I thought this is a principle of least surprise thingy, so in this particular case i thought its ok to bypass the RFC process.

@SeanTAllen
Copy link
Member

"only have very little effect."

I'm not sure this is a principal of least surprise and it is a breaking change. It merits a discussion.

When I first read the PR, I thought this was the first of multiple changes, thus my, perhaps "outside the RFC" process comment. If its the only change then that can be ignored.

Still, I think this needs to be discussed. This will quite possibly break folks code, its an API change, I don't see how its least surprise and its unclear to be what the usability gains that come from this are (and what usability will be lost).

For example, with this change, I parse some Json in a TCPConnectionNotify. How do I send that to another actor?

@mfelsche
Copy link
Contributor Author

mfelsche commented Jun 6, 2018

Let me illustrate the usability improvement:

The current state is, if i want to parse json and access the data structure, i am doomed:

use "json"
actor Main
  new create(env: Env) =>
    try
      let doc = JsonDoc
      doc.parse("""{"array": [1, "str", true]}""")
      let obj = doc.data as JsonObject
    end

Surprisingly this doesn't compile, but fails with:

Error:
main.pony:7:26: this capture violates capabilities
      let obj = doc.data as JsonObject
                         ^
    Info:
    main.pony:7:29: match type: JsonObject ref
          let obj = doc.data as JsonObject
                                ^
    main.pony:7:20: pattern type: (F64 val | I64 val | Bool val | None val | String val | JsonArray tag | JsonObject tag)
          let obj = doc.data as JsonObject

As JsonDoc is returned from the constructor as iso, i am not able to access its data field in case of JsonArray and JsonObject because they are defined as ref in JsonType. Through an iso container i can only see them as tag because they might leak. This is very confusing and limits the usability of JsonDoc very much.
This can easily be fixed by assigning JsonDoc like so:

let doc: JsonDoc = JsonDoc

Here is is automatically "downgraded" to ref and is thus usable. So we have a working example just by explicitly writing the type, no explicit refcaps in the code up to know. I find this very confusing and it already hit more than one user. Another solution is to recover the constructed JsonDoc down to ref, which is also cumbersome.

The main advantage of having JsonDoc as iso is that it is sendable. Nonetheless on the receiving side one has to recover to ref to be able to read the fields again. So this is a one-way operation, after that it won't be sendable anymore. Which is fine.

The change in this PR:

  • makes the example above compile, which i think should be the intended usage of the package
  • removes confusion by making the JsonDoc functional without a special recover or explicit type
  • if one wants to have the JsonDoc being sendable, then it is easily recoverable to iso:
let sendable_doc = recover iso JsonDoc.>parse(json_string) end

@SeanTAllen
Copy link
Member

ok, im ok with this @mfelsche. Your explanation on the sync call convinced me.

@SeanTAllen SeanTAllen added the do not merge This PR should not be merged at this time label Jun 6, 2018
@SeanTAllen
Copy link
Member

Adding "DO NOT MERGE" that can be removed after 0.22.6 is released

@SeanTAllen SeanTAllen removed the do not merge This PR should not be merged at this time label Jun 7, 2018
@SeanTAllen
Copy link
Member

Can you add release notes to this @mfelsche before its merged?

@mfelsche
Copy link
Contributor Author

mfelsche commented Jun 8, 2018

Release notes draft

The json package got rid of some inconveniences you could encounter when using JsonDoc to parse JSON and access the parsed representation. This was due to the constructor of JsonDoc returning instances with an iso reference capability and having the actual JSON data inside being ref (in some cases). For ensuring safety the compiler does not allow to access ref fields from an iso reference (they are being seen as tag). This could have led to confusing error messages.

This is all gone now, JsonDoc will be created with a ref reference capability. That means it is not sendable by default anymore, but now much much more usable:

use "json"
actor Main
  new create(env: Env) =>
    try
      let doc = JsonDoc
      doc.parse("""{"array": [1, "str", true]}""")
      let obj = doc.data as JsonObject
    end

mfelsche added 2 commits June 8, 2018 10:10
JsonType has not been sendable anyways as JsonObject and JsonArray have been of refcap ref in JsonType,
so this only changes JsonDoc to be non-sendable, which should only have very little effect.

My first iteration was to make JsonDoc, JsonObject and JsonArray iso but this turned out to be cumbersome to use (especially when traversing into nested structures).
The other possibility would be to make all elements of JsonType val but this also turns out to be a little limiting when constructing a JSON structure, so i went with
the least invasive way for now.
@SeanTAllen
Copy link
Member

SeanTAllen commented Jun 16, 2018

I dont feel qualified to merge this. Waiting on someone who feels more qualified.

@jemc @sylvanc perhaps?

@jemc jemc merged commit f524eed into master Jun 18, 2018
@jemc jemc deleted the json-ref branch June 18, 2018 02:28
ponylang-main added a commit that referenced this pull request Jun 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog - changed Automatically add "Changed" CHANGELOG entry on merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants