-
Notifications
You must be signed in to change notification settings - Fork 25
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
Handle null value without quotes #335
Conversation
A https://recap.build/specs/type/0.1.1/ I don't feel converting the invalid type_dict to a null type is a good idea; it's not part of the spec. It should raise an error, |
@gwukelic LMK if you've got a specific need for this change. Otherwise, I'll close it off in a few days. |
Hi @criccomini, I am running into issues with contracts that have unions. The This works ✅
This does not ❌
But I think Lastly, I don't expect all these changes to be added. This PR is a WIP and I'm currently testing my proposed changes against different contracts. The exact error I am seeing without these changes is |
EDIT: Oof, you're right, the spec DOES show that as valid. That's an oversight on my part! 🤦 It's not meant to be valid syntax--only This issue is an artifact of YAML, which is coercing text into a string for "boolean" since it's not a literal, but it's leaving null as a null type, since
The TOML, for example, doesn't behave this way:
If you were to put Similarly, JSON does not coerce as YAML does. You can set I'm wondering if the real question here is whether we should revisit how we represent nulls/nullable fields. I had a somewhat in-depth conversation with @cpard last week about this very subject. I'm going to paste my comment from that discussion below (it was buried in a private repo). Comically, even I made the IntroI'm glad you're calling this out, because it's worth some discussion. For the AST, I feel strongly we should keep the nullable design as it is now (UnionType of NullType and other types). I think what's jamming you up is the CST, which right now is a mirror of the AST. In YAML, it's something like: # A struct with an optional string field called "secondary_phone"
type: struct
fields:
- name: secondary_phone
type: ["null", "string32"]
default: null This mirrors how Avro handles nullable fields. It's always been a bit goofy as developer ergonomics go. If you don't use the verbose syntax rather than aliases it's even uglier: type: union
types:
- type: null
- type: string
bytes: 128
variable: false
default: null I'm open to optimizing how the CST handles nulls. I can think of three approaches:
nullable: true# A struct with an optional string field called "secondary_phone"
type: struct
fields:
- name: secondary_phone
type: "string32"
nullable: true One thing to call out with something like # A struct with an optional string field called "secondary_phone"
type: struct
fields:
- name: secondary_phone
type: "string32"
nullable: true
default: null optional: true# A struct with an optional string field called "secondary_phone"
type: struct
fields:
- name: secondary_phone
type: "string32"
optional: true This would convert to a union of null/string32 with default null set. default: null with a non-"null" type# A struct with an optional string field called "secondary_phone"
type: struct
fields:
- name: secondary_phone
type: "string32"
default: null In this style, we simply interpret any default: null for a non-null type to implicitly mean union of that null and that type. So the above is seen as: # A struct with an optional string field called "secondary_phone"
type: struct
fields:
- name: secondary_phone
type: ["null", "string32"]
default: null ConclusionI feel like the right answer is probably 2 or 3? I haven't given a ton of thought to implementation, yet. Some might be easier than others. But I'll deal with that later. For now, let's converge on the syntax we want. WDYT? |
@criccomini @gwukelic I think we agree here that the problem is with what syntactic sugar or shorthand to provide for representing optional types. I say optional types because I think that's a more general definition of what we are dealing here with nulls. Also, my understanding here is that optionality at the AST is always a union between a type and a null, empty, unit, (whatever we want to call it) type. But these are implementation details that shouldn't bother the user of Recap. When it comes to what syntactic sugar can be the best, I suggest to consider two things:
Regarding (1), as was primarily working with Recap from the relational angle, I was leaning more into the "nullable", "optional" approach. This comes naturally mainly because of how databases have historically handled the ergonomics of working with null values. But, I don't think that this is the best way to do it. There has been a lot of progress in PL on that stuff and databases are encouraging you to almost instinctively think in terms of data and concrete values when it comes to that stuff and not the semantics of the types. So, my suggestion here is to avoid this path. I took a look on some of the languages out there and how they handle optionality in their type systems. Some examples,
A. Using Optional<> or Optional[] etc. would be the closest to Python and Rust so it has that added benefit if we assume that users will be more familiar with python. B. Languages from group (1) are treating optionality more like an attribute of the type than a different type, (when it comes to syntactic sugar). Hear the "?" is like a shorthand to optional/nullable=true. A feels more "formal" as it exposes syntactically something closer to a type with a parameter and it's also closer to the way Python does it. B is much cleaner in my opinion and offers better ergonomics. At the end it's all about developer ergonomics when it comes to syntactic sugar so there's no right or wrong, just trade offs! All the above are about syntax, but I have a question about semantics too. What's the meaning of a type being optional in Recap? to me there are two definitions of being optional:
What's Recap's definition? |
Per-spec (here):
We can of course change this definition, but this is in-line with what other serdes such as Avro/Proto do. |
@criccomini @cpard thank you for your thoughts and some background. @adrianisk and I talked and we vote for Option 2 ( |
Just catching up on all of this... Optional seems like the way to go to me, with
just being syntactic sugar for
I'm guessing we'd also want to support
? The problem I see with the |
I'm leaning toward Regarding the So, I'm thinking: type: struct
fields:
- name: secondary_phone
type: string32
optional: true Would be valid. When no type: struct
fields:
- name: secondary_phone
type: string32
optional: true
default: "1 (555) 555-5555" Optional unions are also allowed: type: struct
fields:
- name: some_union
type: union
types: ["int32", "float32"]
optional: true In the above case, the union would be converted to: type: struct
fields:
- name: some_union
type: union
types: ["null", "int32", "float32"]
default: null Aliases would continue to support attribute overrides. type: struct
fields:
- name: phone
alias: phone_type
type: string32
- name: secondary_phone
type: phone_type
optional: true In this example, type: struct
fields:
- name: phone
alias: phone_type
type: string32
optional: true
- name: secondary_phone
type: phone_type In this example, This would all be implemented in WDYT? Is this tolerable to y'all? |
Thanks @criccomini! @adrianisk and I think this is great! Feel free to close this PR. |
The current Recap null-field handling is a bit cumbersome. I discussed with @gwukelic, @adrianisk, and @cpard. We decided to add support for an `optional` field to the CST. This will allow us to specify that a field is optional. See the conversation here: #335 Users can now specify an optional field as: ```yaml type: struct fields: - name: secondary_phone type: string32 optional: true ``` This will get treated the same as: ```yaml type: struct fields: - name: secondary_phone type: "union", types: ["null", "string32"], default: null ``` I will update the Recap spec accordingly, as well. Closes #335
The current Recap null-field handling is a bit cumbersome. I discussed with @gwukelic, @adrianisk, and @cpard. We decided to add support for an `optional` field to the CST. This will allow us to specify that a field is optional. See the conversation here: gabledata/recap#335 Users can now specify an optional field as: ```yaml type: struct fields: - name: secondary_phone type: string32 optional: true ``` This will get treated the same as: ```yaml type: struct fields: - name: secondary_phone type: "union", types: ["null", "string32"], default: null ```
I've updated the spec here: @gwukelic mind taking a quick peak to make sure it makes sense? |
The current Recap null-field handling is a bit cumbersome. I discussed with @gwukelic, @adrianisk, and @cpard. We decided to add support for an `optional` field to the CST. This will allow us to specify that a field is optional. See the conversation here: #335 Users can now specify an optional field as: ```yaml type: struct fields: - name: secondary_phone type: string32 optional: true ``` This will get treated the same as: ```yaml type: struct fields: - name: secondary_phone type: "union", types: ["null", "string32"], default: null ``` I will update the Recap spec accordingly, as well. Closes #335, #338 a
The current Recap null-field handling is a bit cumbersome. I discussed with @gwukelic, @adrianisk, and @cpard. We decided to add support for an `optional` field to the CST. This will allow us to specify that a field is optional. See the conversation here: #335 Users can now specify an optional field as: ```yaml type: struct fields: - name: secondary_phone type: string32 optional: true ``` This will get treated the same as: ```yaml type: struct fields: - name: secondary_phone type: "union", types: ["null", "string32"], default: null ``` I will update the Recap spec accordingly, as well. Closes #335, #338
PR is up here: @gwukelic @cpard @adrianisk PTAL |
The current Recap null-field handling is a bit cumbersome. I discussed with @gwukelic, @adrianisk, and @cpard. We decided to add support for an `optional` field to the CST. This will allow us to specify that a field is optional. See the conversation here: #335 Users can now specify an optional field as: ```yaml type: struct fields: - name: secondary_phone type: string32 optional: true ``` This will get treated the same as: ```yaml type: struct fields: - name: secondary_phone type: "union", types: ["null", "string32"], default: null ``` I will update the Recap spec accordingly, as well. Closes #335, #338
The current Recap null-field handling is a bit cumbersome. I discussed with @gwukelic, @adrianisk, and @cpard. We decided to add support for an `optional` field to the CST. This will allow us to specify that a field is optional. See the conversation here: gabledata/recap#335 Users can now specify an optional field as: ```yaml type: struct fields: - name: secondary_phone type: string32 optional: true ``` This will get treated the same as: ```yaml type: struct fields: - name: secondary_phone type: "union", types: ["null", "string32"], default: null ```
This code change will allow
null
values to be used without be surrounded by quotation marks, i.e."null"
.Before this change,
type: null
was not acceptable buttype: "null"
was. With these changes, bothnull
and"null"
will be acceptable syntax. This change will also cover null values inside ofunion
types.Acceptable ✅