-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
added result type #147
added result type #147
Conversation
As an OCaml user, I'd like to voice my support for this. This incompatibility between the standard libs is very painful and this PR would hopefully nudge all of them to be compatible with each other. |
If we add this in pervasive, I'm pretty sure people will want a compatibility layer for old OCaml versions, so we will need an external library anyway and this will use the same opam mechanism than byte. I don't want to wait 2017 to use Result in debian. If everyone agrees on the interface (and I'm quite convinced we can agree on something now that everyone realized the current situation is a huge PITA), I don't see why it should be in the stdlib. And anyway, agreeing on a small external library is exactly as difficult as agreeing on something being integrated in Pervasive. I vote for a mini package, in the repository https://github.com/ocaml and nothing in the stdlib. I have pretty much the same opinion about #80. |
I think one issue with such tiny libraries is who 'owns' them. I'd be happy for small modules that are proposed for the standard library to go under the I do think it's a good idea to include them in stdlib, but a transition package is necessary for this to happen anyway for compatibility reasons. |
In my mind, result is such a close parallel to option, that it strikes me as a truly natural fit with stdlib, and I think it makes sense there. I agree that we'll need a compatibility library for older compiler versions, but there is some unifying effect of putting things in the stdlib, and I think that would be a valuable contribution on its own. |
But even with an external library you'd need your users to have opam installed. In which case, what is preventing from using a recent version of OCaml? The only possible scenario where having an external lib is favorable is if you want to use opam and the system compiler which seems very niche and pointless to me. I think the real advantage of having this in the external lib is that it allows the team be a little less conservative and starting adding useful combinators. |
It's easier to bundle a lib than a future version of Pervasive. |
I kind of agree with @Drup about the need for compatibility with older versions (a type only available for In particular, here, that's no use trying to impose a common |
This patch adds only a type, which I feel makes it appropriate for the stdlib. If you make a separate lib, presumably you will also be providing a bunch functions related to the type. At that point you again start having divergence of opinions.
Which is exactly the problem. We won't reach consensus on what these combinators should be. Well, I see @c-cube is really proposing a library with only a single type definition. Seems a bit extreme. |
@agarwal well, a full module in the stdlib won't just work (nor get merged anyway); a full library outside will make people disagree on who owns it and what should go inside; so a one-type module in the stdlib and a lib version outside (for older versions) would do the trick, I think. |
We already did: everyone includes return, fail, bind, map, join, pp, equal. Just take the intersection of the various libraries, and you already have something non empty and useful enough. People are free to use the bigger libraries for fancy combinators. |
Maybe in that case we could also have an |
Can't take Also, I'm not against |
This is also the case of the option module, and the reason it's not in the stdlib is not that no one proposed it. |
What I like about this is that it's a small step in the direction of agreeing on the type, and avoids more controversial questions of library design. We can all design our own Monad interface and decide how we like to order our arguments, but it's nice that we all agree on the option type. Similarly, it would be great if we could all agree on the result type as well. I strongly prefer the one-line patch (well, two if you count the mli) to something more ambitious. |
By the way, with result in pervasive, the compatibility layer is especially annoying to do. |
It's a fair point. Indeed, I don't have a great idea about how to get both compatibility and having the type be implicitly available everywhere, in the same way option is. We can give up on that, of course, but it seems awkward to have such different handling for option and for result. So, the options are:
I tend to think (3) is the best of these solutions. From the perspective of libraries like Core that provide their own pervasives-like module, these proposals are all equivalent. It's really about the experience of someone using OCaml without any of these extensions. |
There isn't agreement even on these. Some libraries label the arguments and some don't. |
@yminsky Your options 2 and 3 are equivalent if OPAM provides a compatibility module: in 4.02 it would provide the |
Let's see if I understand what you're saying. With approach 2, a In either case, compatible code would have to be careful to only refer This makes me think that solution 2, which is what is in the patch, is |
Hum, what about that: we put the type in pervasive as @yminsky proposed and we put a small opam package with only a this for ≤ 4.02: type ('a,'b) t = Ok of 'a | Error of 'b and this for 4.03: type ('a,'b) t = ('a,'b) result = Ok of 'a | Error of 'b This is a sort of mix of (1) and (2). It doesn't force you to open if you prefer qualified usage to get the compatibility layer (much like the Bytes compatibility layer) and we can put a minimal amount of harmless combinators in it. |
That's precisely what I was thinking, and I agree it's better, for the reasons you said. I'd argue against putting any combinators in it for now. I think we should keep the patch simple, and keep the support in the stdlib parallel between option and result. I think the eventual fate of the compatibility layer is to just be deleted, so keeping other stuff in it is a mistake. |
well, the |
I would argue that the compat module should be a bare minimum synchronization point. There are already several natural places for people to develop opinionated APIs to Result --- Core, Batteries, Bunzli's libraries, Containers. I don't think this compatibility shim should add a new one to the mix. |
It would be interesting to quantify how many people are actually stuck with old versions of OCaml but would still insist to use latest versions of libraries such as the ones mentioned in this discussion. Does anybody have any rough idea of the kind of reasons for people to be in this situation? I can imagine very conservative projects (esp. in industrial settings, or for stable end-user applications) that don't want to upgrade OCaml too often, but are they the kind of projects jumping to adopt new libraries or versions of libraries? If libraries put themselves the constraints of supporting older versions of OCaml, how do they do that? By maintaining a single code base (which means they can't benefit from any improvement to the language or stdlib), by using conditional compilation or maintaining several release branches (in which cases they could easily accomodate a special migration package putting the type in a specific module)? |
The primary reason is upstreaming binary packages into distributions. They hold back widescale adoption of a new compiler version until the slowest (CentOS or Debian) catch up with the new release. Moving those distributions to a multi-version capable model where several compilers could be simultaneously installed is one solution, and OPAM is another. Neither is as perfect as just typing in |
I would have thought that users that rely on binary packages from their distribution would not be the same ones that need to use the most recent versions of libraries. Do you have an idea on how we could quantify the actual need for providing latest versions of libraries through "slow" binary distribution stuck with old versions of OCaml? If the community wants to commit to long-term maintenance of old versions of OCaml, shouldn't this be done by having multiple released versions of libraries (e.g. "Core for OCaml 3.12")? Only important bug fixes or new features would need to be backported (this would also guarantee more stable APIs for people who don't need/want to benefit from bleeding edge features). |
Here's a minimal compatibility package: https://github.com/janestreet/result Responding to Alain: with respect to this PR, I think the compatibility package is warranted: this is a rather fundamental type, and it's easy to see libraries that want some modicum of portability across OCaml versions using it. It's also useful for forward compatibility, i.e., Core can start using this now, and so when OCaml moves to a new version, people using Core with a newer version of OCaml can use the shared type in pervasives. |
Le mardi, 3 mars 2015 à 13:30, Yaron Minsky a écrit :
Would it be possible to define the type in Pervasives_result rather than Result for < 4.03 ? I think the Pervasives_result conveys better the provided compatibility and this is anyway meant to be Otherwise I can change my package name but it's always painful to rename packages once the infrastructure has been setup (I usually try not to squat too common toplevel names by adding a silly naming scheme, but somehow in that case I forgot to do it). Best, Daniel |
Le vendredi, 15 mai 2015 à 20:29, Yotam Barnoy a écrit :
That genericity leads to less readable code if your type is supposed to represent a possibly failing value computation which is what the result type is for.
|
It's not strictly speaking type safety, but it catches less thing since it tends to catch them at use instead of definition. In particular, The anti-typo factor is less important. result is a rather small type (and there is always the correct type alias), so it's less of an issue, but believe me, it's notable in tyxml .... |
So you do loose, but you don't lose. |
On Fri, May 15, 2015 at 3:00 PM, Daniel Bünzli notifications@github.com
|
2015-05-15 15:13 GMT-04:00 Yotam Barnoy notifications@github.com:
Oh yes, None | Some of 'a is clearly as confusing as Blue of 'b | Red of 'a. |
Le vendredi, 15 mai 2015 à 21:13, Yotam Barnoy a écrit :
What kind of reasoning is that. So now you need to maintain in your head a map Left -> Ok, Right -> Error. I call that both less explicit and less readable since a hintless convention has to be absorbed. And then you cannot even be sure that some other library writer will have another opinion about which way is right.
|
I think it's pretty clear that the type discipline around polymorphic variants is more complicated and less good at catching errors than that around ordinary variants. To me, that seems a sufficient argument for using ordinary variants for such a core concept as Ok | Error. The parallelism with option also argues for using the same mechanism in the type system. |
|
Le vendredi, 15 mai 2015 à 21:59, Yaron Minsky a écrit :
FWIW I would also be in favour of keeping an ordinary variant for this. Other than that, this issue should be a reminder that using warnings to resolve PL design issues or disputes is a bad idea, it ends up all of us having different expectation and live with a different programming language. D |
It would be very nice if I could put |
Adding two cents to an already long discussion:
|
Patches welcome, that should be easy to implement. My worry would be user expecting this flag to also enable/disable features of the language (some people have asked for this in the past, and I think it's unreasonable in terms of maintenance burden); maybe just a tag such as |
I created a PR to keep track of this feature request: PR#6873. |
The disambiguation bug was just fixed by Jacques Garrigue. @toots , could you recompile and list the remaining Warnings 41? |
Thanks for the fix @gasche! I'm only seeing the warning in a couple of cases now. Here's one:
Code:
Warning occurs in |
Would writing (If that's not too much work, listing the location of the other cases may help in documenting the kind of code patterns that users would have to change, under the assumption that the type-declaration remains as is for the 4.03 release.) |
Yeah, I can do that. The other case is the following:
|
To be clear, you only get the warning if the |
Yup. |
Switching to Yuasa (deletion) barrier from Dijkstra (insertion) barrier
23a7f73 flambda-backend: Fix some Debuginfo.t scopes in the frontend (ocaml#248) 33a04a6 flambda-backend: Attempt to shrink the heap before calling the assembler (ocaml#429) 8a36a16 flambda-backend: Fix to allow stage 2 builds in Flambda 2 -Oclassic mode (ocaml#442) d828db6 flambda-backend: Rename -no-extensions flag to -disable-all-extensions (ocaml#425) 68c39d5 flambda-backend: Fix mistake with extension records (ocaml#423) 423f312 flambda-backend: Refactor -extension and -standard flags (ocaml#398) 585e023 flambda-backend: Improved simplification of array operations (ocaml#384) faec6b1 flambda-backend: Typos (ocaml#407) 8914940 flambda-backend: Ensure allocations are initialised, even dead ones (ocaml#405) 6b58001 flambda-backend: Move compiler flag -dcfg out of ocaml/ subdirectory (ocaml#400) 4fd57cf flambda-backend: Use ghost loc for extension to avoid expressions with overlapping locations (ocaml#399) 8d993c5 flambda-backend: Let's fix instead of reverting flambda_backend_args (ocaml#396) d29b133 flambda-backend: Revert "Move flambda-backend specific flags out of ocaml/ subdirectory (ocaml#382)" (ocaml#395) d0cda93 flambda-backend: Revert ocaml#373 (ocaml#393) 1c6eee1 flambda-backend: Fix "make check_all_arches" in ocaml/ subdirectory (ocaml#388) a7960dd flambda-backend: Move flambda-backend specific flags out of ocaml/ subdirectory (ocaml#382) bf7b1a8 flambda-backend: List and Array Comprehensions (ocaml#147) f2547de flambda-backend: Compile more stdlib files with -O3 (ocaml#380) 3620c58 flambda-backend: Four small inliner fixes (ocaml#379) 2d165d2 flambda-backend: Regenerate ocaml/configure 3838b56 flambda-backend: Bump Menhir to version 20210419 (ocaml#362) 43c14d6 flambda-backend: Re-enable -flambda2-join-points (ocaml#374) 5cd2520 flambda-backend: Disable inlining of recursive functions by default (ocaml#372) e98b277 flambda-backend: Import ocaml#10736 (stack limit increases) (ocaml#373) 82c8086 flambda-backend: Use hooks for type tree and parse tree (ocaml#363) 33bbc93 flambda-backend: Fix parsecmm.mly in ocaml subdirectory (ocaml#357) 9650034 flambda-backend: Right-to-left evaluation of arguments of String.get and friends (ocaml#354) f7d3775 flambda-backend: Revert "Magic numbers" (ocaml#360) 0bd2fa6 flambda-backend: Add [@inline ready] attribute and remove [@inline hint] (not [@inlined hint]) (ocaml#351) cee74af flambda-backend: Ensure that functions are evaluated after their arguments (ocaml#353) 954be59 flambda-backend: Bootstrap dd5c299 flambda-backend: Change prefix of all magic numbers to avoid clashes with upstream. c2b1355 flambda-backend: Fix wrong shift generation in Cmm_helpers (ocaml#347) 739243b flambda-backend: Add flambda_oclassic attribute (ocaml#348) dc9b7fd flambda-backend: Only speculate during inlining if argument types have useful information (ocaml#343) aa190ec flambda-backend: Backport fix from PR#10719 (ocaml#342) c53a574 flambda-backend: Reduce max inlining depths at -O2 and -O3 (ocaml#334) a2493dc flambda-backend: Tweak error messages in Compenv. 1c7b580 flambda-backend: Change Name_abstraction to use a parameterized type (ocaml#326) 07e0918 flambda-backend: Save cfg to file (ocaml#257) 9427a8d flambda-backend: Make inlining parameters more aggressive (ocaml#332) fe0610f flambda-backend: Do not cache young_limit in a processor register (upstream PR 9876) (ocaml#315) 56f28b8 flambda-backend: Fix an overflow bug in major GC work computation (ocaml#310) 8e43a49 flambda-backend: Cmm invariants (port upstream PR 1400) (ocaml#258) e901f16 flambda-backend: Add attributes effects and coeffects (#18) aaa1cdb flambda-backend: Expose Flambda 2 flags via OCAMLPARAM (ocaml#304) 62db54f flambda-backend: Fix freshening substitutions 57231d2 flambda-backend: Evaluate signature substitutions lazily (upstream PR 10599) (ocaml#280) a1a07de flambda-backend: Keep Sys.opaque_identity in Cmm and Mach (port upstream PR 9412) (ocaml#238) faaf149 flambda-backend: Rename Un_cps -> To_cmm (ocaml#261) ecb0201 flambda-backend: Add "-dcfg" flag to ocamlopt (ocaml#254) 32ec58a flambda-backend: Bypass Simplify (ocaml#162) bd4ce4a flambda-backend: Revert "Semaphore without probes: dummy notes (ocaml#142)" (ocaml#242) c98530f flambda-backend: Semaphore without probes: dummy notes (ocaml#142) c9b6a04 flambda-backend: Remove hack for .depend from runtime/dune (ocaml#170) 6e5d4cf flambda-backend: Build and install Semaphore (ocaml#183) 924eb60 flambda-backend: Special constructor for %sys_argv primitive (ocaml#166) 2ac6334 flambda-backend: Build ocamldoc (ocaml#157) c6f7267 flambda-backend: Add -mbranches-within-32B to major_gc.c compilation (where supported) a99fdee flambda-backend: Merge pull request ocaml#10195 from stedolan/mark-prefetching bd72dcb flambda-backend: Prefetching optimisations for sweeping (ocaml#9934) 27fed7e flambda-backend: Add missing index param for Obj.field (ocaml#145) cd48b2f flambda-backend: Fix camlinternalOO at -O3 with Flambda 2 (ocaml#132) 9d85430 flambda-backend: Fix testsuite execution (ocaml#125) ac964ca flambda-backend: Comment out `[@inlined]` annotation. (ocaml#136) ad4afce flambda-backend: Fix magic numbers (test suite) (ocaml#135) 9b033c7 flambda-backend: Disable the comparison of bytecode programs (`ocamltest`) (ocaml#128) e650abd flambda-backend: Import flambda2 changes (`Asmpackager`) (ocaml#127) 14dcc38 flambda-backend: Fix error with Record_unboxed (bug in block kind patch) (ocaml#119) 2d35761 flambda-backend: Resurrect [@inline never] annotations in camlinternalMod (ocaml#121) f5985ad flambda-backend: Magic numbers for cmx and cmxa files (ocaml#118) 0e8b9f0 flambda-backend: Extend conditions to include flambda2 (ocaml#115) 99870c8 flambda-backend: Fix Translobj assertions for Flambda 2 (ocaml#112) 5106317 flambda-backend: Minor fix for "lazy" compilation in Matching with Flambda 2 (ocaml#110) dba922b flambda-backend: Oclassic/O2/O3 etc (ocaml#104) f88af3e flambda-backend: Wire in the remaining Flambda 2 flags (ocaml#103) 678d647 flambda-backend: Wire in the Flambda 2 inlining flags (ocaml#100) 1a8febb flambda-backend: Formatting of help text for some Flambda 2 options (ocaml#101) 9ae1c7a flambda-backend: First set of command-line flags for Flambda 2 (ocaml#98) bc0bc5e flambda-backend: Add config variables flambda_backend, flambda2 and probes (ocaml#99) efb8304 flambda-backend: Build our own ocamlobjinfo from tools/objinfo/ at the root (ocaml#95) d2cfaca flambda-backend: Add mutability annotations to Pfield etc. (ocaml#88) 5532555 flambda-backend: Lambda block kinds (ocaml#86) 0c597ba flambda-backend: Revert VERSION, etc. back to 4.12.0 (mostly reverts 822d0a0 from upstream 4.12) (ocaml#93) 037c3d0 flambda-backend: Float blocks 7a9d190 flambda-backend: Allow --enable-middle-end=flambda2 etc (ocaml#89) 9057474 flambda-backend: Root scanning fixes for Flambda 2 (ocaml#87) 08e02a3 flambda-backend: Ensure that Lifthenelse has a boolean-valued condition (ocaml#63) 77214b7 flambda-backend: Obj changes for Flambda 2 (ocaml#71) ecfdd72 flambda-backend: Cherry-pick 9432cfdadb043a191b414a2caece3e4f9bbc68b7 (ocaml#84) d1a4396 flambda-backend: Add a `returns` field to `Cmm.Cextcall` (ocaml#74) 575dff5 flambda-backend: CMM traps (ocaml#72) 8a87272 flambda-backend: Remove Obj.set_tag and Obj.truncate (ocaml#73) d9017ae flambda-backend: Merge pull request ocaml#80 from mshinwell/fb-backport-pr10205 3a4824e flambda-backend: Backport PR#10205 from upstream: Avoid overwriting closures while initialising recursive modules f31890e flambda-backend: Install missing headers of ocaml/runtime/caml (ocaml#77) 83516f8 flambda-backend: Apply node created for probe should not be annotated as tailcall (ocaml#76) bc430cb flambda-backend: Add Clflags.is_flambda2 (ocaml#62) ed87247 flambda-backend: Preallocation of blocks in Translmod for value let rec w/ flambda2 (ocaml#59) a4b04d5 flambda-backend: inline never on Gc.create_alarm (ocaml#56) cef0bb6 flambda-backend: Config.flambda2 (ocaml#58) ff0e4f7 flambda-backend: Pun labelled arguments with type constraint in function applications (ocaml#53) d72c5fb flambda-backend: Remove Cmm.memory_chunk.Double_u (ocaml#42) 9d34d99 flambda-backend: Install missing artifacts 10146f2 flambda-backend: Add ocamlcfg (ocaml#34) 819d38a flambda-backend: Use OC_CFLAGS, OC_CPPFLAGS, and SHAREDLIB_CFLAGS for foreign libs (#30) f98b564 flambda-backend: Pass -function-sections iff supported. (#29) e0eef5e flambda-backend: Bootstrap (#11 part 2) 17374b4 flambda-backend: Add [@@Builtin] attribute to Primitives (#11 part 1) 85127ad flambda-backend: Add builtin, effects and coeffects fields to Cextcall (#12) b670bcf flambda-backend: Replace tuple with record in Cextcall (#10) db451b5 flambda-backend: Speedups in Asmlink (#8) 2fe489d flambda-backend: Cherry-pick upstream PR#10184 from upstream, dynlink invariant removal (rev 3dc3cd7 upstream) d364bfa flambda-backend: Local patch against upstream: enable function sections in the Dune build 886b800 flambda-backend: Local patch against upstream: remove Raw_spacetime_lib (does not build with -m32) 1a7db7c flambda-backend: Local patch against upstream: make dune ignore ocamldoc/ directory e411dd3 flambda-backend: Local patch against upstream: remove ocaml/testsuite/tests/tool-caml-tex/ 1016d03 flambda-backend: Local patch against upstream: remove ocaml/dune-project and ocaml/ocaml-variants.opam 93785e3 flambda-backend: To upstream: export-dynamic for otherlibs/dynlink/ via the natdynlinkops files (still needs .gitignore + way of generating these files) 63db8c1 flambda-backend: To upstream: stop using -O3 in otherlibs/Makefile.otherlibs.common eb2f1ed flambda-backend: To upstream: stop using -O3 for dynlink/ 6682f8d flambda-backend: To upstream: use flambda_o3 attribute instead of -O3 in the Makefile for systhreads/ de197df flambda-backend: To upstream: renamed ocamltest_unix.xxx files for dune bf3773d flambda-backend: To upstream: dune build fixes (depends on previous to-upstream patches) 6fbc80e flambda-backend: To upstream: refactor otherlibs/dynlink/, removing byte/ and native/ 71a03ef flambda-backend: To upstream: fix to Ocaml_modifiers in ocamltest 686d6e3 flambda-backend: To upstream: fix dependency problem with Instruct c311155 flambda-backend: To upstream: remove threadUnix 52e6e78 flambda-backend: To upstream: stabilise filenames used in backtraces: stdlib/, otherlibs/systhreads/, toplevel/toploop.ml 7d08e0e flambda-backend: To upstream: use flambda_o3 attribute in stdlib 403b82e flambda-backend: To upstream: flambda_o3 attribute support (includes bootstrap) 65032b1 flambda-backend: To upstream: use nolabels attribute instead of -nolabels for otherlibs/unix/ f533fad flambda-backend: To upstream: remove Compflags, add attributes, etc. 49fc1b5 flambda-backend: To upstream: Add attributes and bootstrap compiler a4b9e0d flambda-backend: Already upstreamed: stdlib capitalisation patch 4c1c259 flambda-backend: ocaml#9748 from xclerc/share-ev_defname (cherry-pick 3e937fc) 00027c4 flambda-backend: permanent/default-to-best-fit (cherry-pick 64240fd) 2561dd9 flambda-backend: permanent/reraise-by-default (cherry-pick 50e9490) c0aa4f4 flambda-backend: permanent/gc-tuning (cherry-pick e9d6d2f) git-subtree-dir: ocaml git-subtree-split: 23a7f73
This PR adds a new result type, with the following signature:
to Pervasives. This is very similar to a type that shows up in many
existing libraries, and should hopefully allow us to converge on one
definition that can be shared. Here are some other known use-cases in
prominent released libraries.
Result library
The first three of these use the polymorphic variant type,
Batteries uses an ordinary variant with this layout:
Core_kernel uses an ordinary variant with this layout:
After some discussion (notably including Daniel Bunzli), it seems like
the ordinary variant approach is better from a perspective of the less
error prone typing discipline of ordinary variants. In particular,
OCaml correctly detects that the following code is broken:
But lets the same code done with polymorphic variants compile without
issues.
The hope is that by putting one of these in the stdlib, we can have
better interoperability between libraries on what seems to be a quite
basic type, without having to use the more complex and error prone
polymorphic variant solution. Bunzli among others have expressed some
concern with needing to pull in a separate package for such a basic
type, which is what motivates moving it to the stdlib.