-
Notifications
You must be signed in to change notification settings - Fork 425
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
Support for ?
operator for option/result types
#1928
Comments
So it looks like the desired effect is a more compact form of the following use of accessor functions. let viewer = x => x#viewer;
let repositories = x => x#repositories;
let edges = x => x#edges;
let nodes = x => x#nodes;
let (|>?) = (x, access) =>
switch (x) {
| None => None
| Some(v) => access(v)
};
let (|>+) = (x, access) =>
switch (x) {
| None => None
| Some(v) => Some(access(v))
};
let test = x => Some(x) |>? viewer |>? repositories |>+ edges |>? nodes; |
Currently what I'm using to do this is to use a bind operator,
But stills a bit overwhelming to write. Would be nice to be able to have some kind to have a more succinct way to write that. Maybe this is more a |
If you don't mind using a ppx syntax extension, both ocaml-monadic and ppx_let provide some shorthand syntax for I'm not aware of anything supporting this now, but |
@cristianoc was the I believe there's a JS proposal for |
@jordwalke the |
Would be awesome to add |
I'm looking into this since the GraphQL workshop @sgrove. let |•| = (result, default_) =>
switch result {
| Some(result) => result
| None => default_
};
let nodes = (result |. viewer |. repositories |. edges |. nodes) |•| [||]; Since we know if each field is optional or not, it would avoid all user defined getters (pretty long) and the I was wondering what the impact would be on the JS bundle size. Aren't |
@Gregoirevda you probably know now, but I'll write it here for others: |
Here is the Javascript Proposal which is using the |
Looking at the swift version, but others as well, it seems that option(t) => option(t)
t => option(t) so strictly speaking it's an extension of the language. This means one needs to reach a little deep to implement it, and can't just be a JSX transform. Also wondering what this means for type inference, and principal types in particular. |
@cristianoc I have no idea if this is feasible but could it be transformed into a switch? For example given the following types: type c = { thing: string };
type b = { c: option(c) };
type a = { b: option(b) };
let a = { b: Some({ c: Some({ thing: "hello" }) }) }; When you write an optional chained expression ie: let z = a?.b?.c.thing Reason would transform this to a switch: let z = switch (a.b) {
| None => None
| Some(b) =>
switch (b.c) {
| None => None
| Some(c) => Some(c.thing)
}
}; This would be great for accessing properties on deeply optional records. |
Also feel like this should only work on optional types rather than with the result type as well. Which I'm guessing would make it easier to make this a syntax expansion? This also aligns with the behaviour in swift and js. |
I started implementing this with the help of @IwanKaramazow |
@Gregoirevda Awesome!! This is probably a seperate change but could be worth keeping in mind. |
@cristianoc we'll only allow it for optionals. Allowing for non-optionals makes loose guess-based usages too easy, e.g. "yeah why not, let's just use it here". Also,
The other concern I have is the coding pattern where folks do: let a = foo?.bar?.baz;
let b = foo?.bar;
... Aka repeatedly accessing a long chain. But maybe it won't be prevalent. Implementation-wise, I'm thinking that we should turn We don't need the version that wraps the value into a Some for now (aka bind) for now. |
Here's a test that a proposal should pass: type t = { a : int, b : option(t) };
let test = (x:t) => x.b.b.a; for appropriate replacements of |
Here's an experiment for auto-unwrapping options when accessing fields: cristianoc/ocaml#1. |
Dealing with deeply nested, highly optional data structures (very common in real-world GraphQL where everything is nullable by default) is fairly tedious right now, and the feedback from the workshop was that having to use
switch
at each subsequent level was very cumbersome, and a custom infix operator was a bit mystical if it was defined inline and then refmt adds a lot of whitespace around it.It might be nice to adopt Rust's
?
operator, possibly even as a simple syntax expansion.The goal would be to turn something like this (real-world example):
Into this:
Rust's operator works on both Result and Option types which would likely be difficult, and Reason also has record-field-access and object-field-access syntax, so there's plenty to consider when introducing syntax support for this.
The text was updated successfully, but these errors were encountered: