-
Notifications
You must be signed in to change notification settings - Fork 201
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
RFC: Mapping Struct fields to Json fields #3686
Comments
All that said, the specific use case of giving instructions to the json parser is something we should explicitly. If we have a list of the list of requirements and things we want to let users control, we can come up with the right language design and/or apis for that. I recommend to repurpose this issue to something like "json parsing customization" or something like that and continue from there. As for other types of serialization formats, that's a whole topic we need to cover separately with an RFC. |
I don't like that syntax either... Doesn't feel extendable and IDE friendly (auto completion, etc). A system like that would allow de/ser very simple structures, but what about more complex ones? Structures that contain valid JSON fields should be able to automatically be serialized/deserialized, right? In the case of struct Person {
firstName: str;
lastName: str;
phone: str;
}
impl JsonSerialize for Person {
serialize(person: Person) {
let json = new Json();
json.add("first_name", person.firstName);
json.add("last_name", person.lastName);
json.add("phone_number", person.phone);
return json;
}
} The Wing compiler can associate |
Oh yea for sure no sort of automatic case conversions, maybe I could have been more explicit in the example by mapping
I agree, that was not really the topic I wanted to convey in this RFC, I was more interested in discussing this custom parsing and how to make something thats extensible. Ill clean up the RFC to be more specific.
|
@eladb You've mentioned this before and I'm curious where your feelings on this come from. Most languages I can think of that have annotations/decorators use it both for built-in (std lib) features as well as providing a way for users to create their own. |
I also prefer avoiding annotations/attributes for key language features. One reason is that annotations/attributes ought to be usable in userland, and supporting this would require designing a reflection API of some kind (something that might be better to defer until we have a library ecosystem and we've collected more use cases). There are also several examples where annotations have been used in popular languages in places where a dedicated piece of syntax would be preferable. An obvious one that comes to mind is Java's This isn't to say that every feature should have a dedicated syntax; there will be plenty of use cases in "tail" of language usage. But something like how a struct is JSON serialized/deserialized feels like it could be important enough to have its own syntax to me, given the place |
To play the other side, I'm also not sure how many use cases a dedicated syntax would need to support. Maybe listing them out (and seeing which can already be achieved in Wing today) would helps us figure out if field tags or annotations or some other system is the right call after all. Some examples:
I don't think there's a way to do (1) today in Wing (because the field has a space in its name) but the others might have workarounds? |
@MarkMcCulloh @Chriscbr @eladb @skyrpex I updated this RFC to be more specific to Json conversion. I also suggested another syntax closer to Rust's Serde (since everyone hates Go 😂) I also added in examples of how other languages/libraries handle this problem. Im super open to the idea of adding some sort of more dedicated way to pass instructions to the parser/validator. Just fresh out of suggestions at the moment but Ill ponder more over the weekend. |
Hi, This issue hasn't seen activity in 60 days. Therefore, we are marking this issue as stale for now. It will be closed after 7 days. |
Hi, This issue hasn't seen activity in 60 days. Therefore, we are marking this issue as stale for now. It will be closed after 7 days. |
Hi, This issue hasn't seen activity in 90 days. Therefore, we are marking this issue as stale for now. It will be closed after 7 days. |
Thanks for updating the RFC Hasan! thought I'd share some general thoughts / questions Putting aside the exact syntax, one way to view the options is by asking what we're exposing to the user to customize or override. (Are we giving them control of a schema? Or are we giving them control of a set of parsing or stringifying functions? Or are we giving them control of both, or something in between?) Like you mentioned, in our current implementation, when a user runs Suppose in order to support custom struct fields we added some syntax that lets you change the schema in some way. I'll borrow the syntax from the original issue: struct Person {
#[json(name=["first_name", "fname"])]
firstName: str;
#[json(name=["last_name", "lname"])]
lastName: str;
age: num;
} Now, if you tried parsing the object, an updated schema would be used, so the "first_name" field would be validated as satisfying the schema. However, if the data isn't automatically transformed in some way, you wouldn't be able to access it 😱: let person = Person.fromJson(Json { first_name: "Jeff", last_name: "Bezos", age: 60 });
log(person.firstName); // nil For serialization into JSON, a similar issue could happen. To fix it, we'd need to generate code at compile time that transforms the "firstName" field into "first_name". The other note I want to add is that I think renaming fields is just one example of a custom mapping / serialization option. Some other use cases might be:
I don't know if we necessarily need a solution that solves all of these all at once. But we might want to consider "what kinds of solutions would allow us to support these kinds of customizations generally / without requiring language support for each one"? |
BTW - one other hybrid syntax could be to add some annotation to the struct that references the transformer(s) in some way: @serializer(PersonSerializer)
// or maybe @serializer(new PersonSerializer())
struct Person {
firstName: str;
lastName: str;
age: num;
}
class PersonSerializer {
fromJson(obj: Json): Person => {
let person = Person {
firstName: obj["first_name"].asStr(),
lastName: obj["last_name"].asStr(),
age: obj["age"].asNum(),
};
return person;
}
toJson(self): Json => {
return {
"fist_name": self.firstName,
"last_name": self.lastName,
"age": self.age
};
}
} (I'm not sure if I like this better than any of the other options - but wanted to add it for comparison) |
Feature Spec
Wing now offers a way to define mappings between struct fields and their json field equivalent(s)
This allows an instance of person to be created from an of the following Json objects:
The resulting schema uses "anyOf" to ensure validation
Rational
Currently in Wing when we define a Struct this generates a Json schema that can be used for runtime validation of json -> struct conversions. For example the following Struct:
Produces has a json schema defined as:
which means that a Json object that structurally fulfills the schema will be valid when attempting to convert to an instance of
Person
.However, it will be the case that a Json object may have field names that mismatch the Wing struct definition. Its not a guarantee that all data read from the internet will come in the same case convention as Wing.
Usecases
Alternate approaches
Custom Transformer
Add an optional argument to the
toJson
andfromJson
methods that allow a custom transformer to be passed in.Overriding
fromJson
andtoJson
methodsHow do other languages do this?
Golang (uses struct tags):
Rust (serde):
Java (Jackson):
C# (Newtonsoft.Json):
The text was updated successfully, but these errors were encountered: