Is there some way to strip variants from output, especially like from nested Records?
type contact = Contact({ number: string, country: string });
type person = Person({ name: string, contact: contact, country: string });
The output of person would have a Variant wrapping the contact field.
My reasoning here is to use Variants instead of modules for lightweight distinct record types. Should I just use modules?
When you say âoutputâ, what do you mean? Like printing to a string or JSON? You want to convert a person value to a string and have it show up as something like { "name": "A", "contact": { "number": "1", "country": ...?
Actually I figured it out that using unboxed variants (@ocaml.unboxed) would remove the variant representation in the JS output, which was what I was aiming for.
Just @unboxedshould be enough.
Also, ReScript records are already typed nominally, the only problem, afaik, is that sometimes the compiler derives the wrong record type from the first field used. But you can disambiguate with module/type annotations.
and do something like this. I must say that this should be used with caution since youâre removing your type constraints. Usually you should use this when you need to send a variable to the JS-side by removing the variants from the output.
For variants with only one constructor and an inline record, then the output is already unboxed. (The @unboxed annotation isnât necessary.)
Iâm interested in why youâre using variants as namespaces instead of modules. Thereâs nothing necessarily wrong with variants, but modules are traditionally the more idiomatic way of doing that. Variants are a bit clunkier. For example, you canât access record fields like a.name without deconstructing a first.
Ahh yes sorry I didnât even bother to test with it removed!
I guess I was looking for a syntactically lighter way to declare records with duplicate fields.
@hoichi is it safe to declare the two records naked?
type contact = { number: string, country: string };
type person =
{ name: string, contact: contact, country: string };
Because I read on stackoverflow â The Ocaml language requires all fields inside a module to have different names. Otherwise, it wonât be able to infer the type of the below functionâ
And while the compiler still compiles Iâm not sure if this was a rule or a suggestion.
Yes I guess.
eg: In let name = variable.name Rescript will infer the closest record type with name field. If that is not what you wanted to use then you need to provide type for variable manually.
Itâs âsafeâ in the way we typically mean safe. I think the SO answer you mention isnât worded very well. There is no requirement that records have unique field names within modules. However, the type checker infers records based on their field names, so it will sometimes (but not always) infer a different record than you expected if there are duplicated field names. This is easy to catch when it happens, though, since the compiler will give you a type error. You can correct it by explicitly annotating the type. This is a case where âif it compiles, it worksâ holds true.
If your main concern is verbose syntax, then I think that using modules as namespaces will be better. Hereâs your example using modules:
module Contact = {
type t = {number: string, country: string}
}
module Person = {
type t = {name: string, contact: Contact.t, country: string}
}
let bob: Person.t = {
name: "bob",
country: "usa",
contact: {number: "555", country: "usa"},
}
// Alternatively:
let bob = {
Person.name: "bob",
country: "usa",
contact: {number: "555", country: "usa"},
}
We need to annotate bob because its record fields are defined a different module, but we donât need to annotate the nested contact field because the typechecker already knows what type that needs to be.
The module version will also be less verbose when youâre accessing fields. Records may need to be annotated sometimes with their module name, but only in cases where the compiler canât infer them. Variants will always need to be destructured to access their contents, though, which can become verbose quickly.
None of this necessarily means you should avoid using variants and inline records, but modules seem to already be built to solve the problem youâre describing.