[HN Gopher] PR to Merge Multicore OCaml
       ___________________________________________________________________
        
       PR to Merge Multicore OCaml
        
       Author : c-cube
       Score  : 334 points
       Date   : 2021-12-21 15:17 UTC (7 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | sadiq wrote:
       | As usual, happy to answer any questions.
        
         | Zababa wrote:
         | I've searched a bit for this and haven't been able to find a
         | good answer. Let's say that I have m tasks that I want to run
         | concurrently on n cores, for example handling HTTP requests or
         | searching for something in files. I'd also like to not have to
         | manage manually how the tasks are going to be distributed.
         | Basically, have the same experience as when writing Go code. Is
         | there a way to do this in multicore OCaml? I've found the task
         | pool in domainslib [1] but I'm not sure if it's what I'm
         | looking for.
         | 
         | [1]: https://github.com/ocaml-
         | multicore/domainslib/blob/master/li...
        
           | sadiq wrote:
           | You could use eio with an event loop per domain and the
           | domain manager to distribute work to other domains. The
           | restriction at the moment is that the tasks you spin off to
           | other domains can't do asynchronous io.
           | 
           | There is work on-going at the moment to bridge or even unify
           | eio (concurrency via effects) and domainslib (nested
           | parallelism via domains and effects) but it's a few months
           | out.
        
             | talex5 wrote:
             | To clarify that, there are two systems here:
             | 
             | - domainslib schedules all tasks across all cores (like
             | Go).
             | 
             | - eio keeps tasks on the same core (and you can use a
             | shared job queue to distribute work between cores if you
             | want).
             | 
             | Eio can certainly do async IO on multiple cores.
             | 
             | Moving tasks freely between cores has some major downsides
             | - for example every time a Go program wants to access a
             | shared value, it needs to take a mutex (and be careful to
             | avoid deadlocks). Such races can be very hard to debug.
             | 
             | I suspect that the extra reliability is often worth the
             | cost of sometimes having unbalanced workloads between
             | cores. We're still investigating how big this effect is.
             | When I worked at Docker, we spent a lot of time dealing
             | with races in the Go code, even though almost nothing in
             | Docker is CPU intensive!
             | 
             | For a group of tasks on a single core, you can be sure that
             | e.g. incrementing a counter or scanning an array is an
             | atomic operation. Only blocking operations (such as reading
             | from a file or socket) can allow something else to run. And
             | eio schedules tasks deterministically, so if you test with
             | (deterministic) mocks then the trace of your tests is
             | deterministic too. Eio's own unit-tests are mostly expect-
             | based tests where the test just checks that the trace
             | output matches the recorded trace, for example.
             | 
             | The Eio README has more information, plus a getting-started
             | guide: https://github.com/ocaml-
             | multicore/eio/blob/main/README.md
        
             | Zababa wrote:
             | Thank you for the clear explanation!
        
           | vphantom wrote:
           | I think libraries like Lwt will be the ones to offer the
           | level of abstraction which you're describing. I too would
           | like to see the simplicity of goroutines make it into OCaml 5
           | ASAP.
        
         | jpf0 wrote:
         | A bunch of questions: Is multi-threading happening at the level
         | of user-defined functions? How are threads scheduled? What's
         | the underlying method or library for enabling multi-threading
         | (Cilk, openMP, some LWT library...)? To what extent has this
         | level of granularity been tested against other levels of nested
         | parallelism (e.g. SIMD or otherwise parallel operators)? Have
         | you tested performance by OS, and if so, have you noted any
         | necessary OS-level modifications related to thread management?
         | Is this part of a broader roadmap for accelerator integration?
        
           | sadiq wrote:
           | 1. Domains are the unit of parallelism. A domain is
           | essentially an OS thread with a bunch of extra runtime book-
           | keeping data. You can use Domain.spawn
           | (https://github.com/ocaml-multicore/ocaml-
           | multicore/blob/5.00...) to spawn off a new domain which will
           | run the supplied function and terminate when it finishes.
           | This is heavyweight though, domains are expected to be long-
           | running.
           | 
           | 2. Domainslib is the library developed alongside multicore to
           | aid users in exploiting parallelism. It supports nested
           | parallelism and is pretty highly optimised
           | (https://github.com/ocaml-multicore/domainslib/pull/29 for
           | some graphs/numbers). The domainslib repo has some good
           | examples: https://github.com/ocaml-
           | multicore/domainslib/tree/master/te...
           | 
           | 3. We've not tested against other forms of parallelism. There
           | isn't anything stopping you exploiting SIMD in addition to
           | parallelism from domains.
           | 
           | 4. No, we've not compared performance by OS.
           | 
           | 5. No plans for the multicore team to look at accelerator
           | integration at the moment.
        
         | pdimitar wrote:
         | Is the previous plan for adding effects in OCaml 5.1 still in
         | place?
         | 
         | I am very excited not only for the native parallelism that's
         | coming in 5.0 but also about the effect handlers! I am sure
         | many others are looking to start creating very interesting
         | things with them, e.g. Rust-alike async capabilities or
         | Erlang's preemptive green threads / actors runtime.
        
           | sadiq wrote:
           | 5.00 (the first release with multicore) will include effects!
           | 
           | More info: https://discuss.ocaml.org/t/multicore-ocaml-
           | september-2021-e...
        
             | jasone wrote:
             | Yes, but note the absence of syntactic support. Effects
             | will be usable for writing libraries and experimentation,
             | but routine use won't be very ergonomic until a later
             | release.
        
               | simplify wrote:
               | Considering the hard part of effects is implementing them
               | at the language level, deferring on syntax is a good
               | problem to have.
        
             | pdimitar wrote:
             | Oh. I haven't followed lately. Thanks a lot for the updated
             | info!
             | 
             | Really looking forward to what the community will build
             | with OCaml 5.00! IMO it will shoot the language straight
             | into the mainstream and I can't wait. OCaml is applicable
             | for like 90% what's out there, including as a Python
             | replacement. And its syntax is often much terser than Rust
             | (although the higher-level typing constructs can be
             | confusing to read).
             | 
             | After that, all that's left is a tool like Elixir's mix or
             | Rust's cargo and the language is basically not only in the
             | 21st century but much farther than _many_ others! Looking
             | forward to it.
        
         | rwmj wrote:
         | I'm slightly concerned if this means changing C extensions (of
         | which we have rather a lot).
         | 
         | We only have a few places that use "naked" pointers, which are
         | in any case deprecated, and we should be able to fix those
         | easily enough.
         | 
         | Mostly the rest are fairly ordinary extensions that just call C
         | functions and use the usual CAMLparam stuff.
         | 
         | We do have a few places that register global roots. And several
         | packages that do callbacks from C back to OCaml. We also use
         | @@noalloc a lot.
         | 
         | Is there anything else? Since there's so much code, what should
         | I be grepping for to find code that might be of concern?
         | 
         | Edit: Some examples of simple stuff:
         | 
         | https://github.com/libguestfs/libguestfs-common/blob/master/...
         | https://github.com/libguestfs/libguestfs-common/blob/master/...
         | https://github.com/libguestfs/libguestfs-common/blob/master/...
         | 
         | More complex stuff:
         | 
         | https://gitlab.com/nbdkit/nbdkit/-/tree/master/plugins/ocaml
         | http://oirase.annexia.org/tmp/ocaml/
        
           | sadiq wrote:
           | To echo what avsm said, our intention is to preserve the C
           | API. With the exception of naked pointers, if you follow the
           | rules around the existing C API then your extensions should
           | continue to work in sequential code running on 5.0.
           | 
           | We have a scheduled build and test of every package in opam
           | with multicore: http://check.ocamllabs.io:8082/ to try to
           | shake out C API incompatibilities and that's proved fruitful.
           | 
           | If you do find things that don't work on 5.0, please let us
           | know (and if you can, get it in to opam so we test it
           | automatically!).
        
           | avsm wrote:
           | You may find the "nnpchecker" configure option in 4.13.0
           | useful. This will print a detected use of naked pointers to
           | stderr, which can hopefully be triggered by test suites.
           | 
           | Noalloc and registering roots should all be the same, as are
           | callbacks (for sequential code, which all existing code will
           | be)
        
       | 2wrist wrote:
       | Great stuff!!
        
       | VitalyAnkh wrote:
       | Oh the PR is so huge. Would this be difficult to review?
        
         | brabel wrote:
         | It's probably a final PR from multiple smaller, reviewed ones,
         | I would guess.
        
       | sideeffffect wrote:
       | I don't know much about OCaml, only Scala and Cats
       | Effect/ZIO/Monix, but would appreciate if I could get a gist of
       | what Multicore OCaml brings to the table.
       | 
       | Is there somebody who's familiar with both worlds and could
       | compare them and explain how Multicore OCaml (and possibly the
       | new effect system) work?
       | 
       | Thanks in advance!
        
       | michaelmcmillan wrote:
       | Finally a PR worthy of Hacktoberfest.
        
       | gmfawcett wrote:
       | The multicore team has done an excellent job of communicating
       | their plans and progress over the past few years. Innovative
       | research, solid engineering, and a top-notch communications game.
       | Whether or not you care about Ocaml, many other SE projects could
       | learn a lot from studying this team.
        
         | eatYourFood wrote:
         | > could learn a lot from studying this team.
         | 
         | How? Where?
        
           | gmfawcett wrote:
           | Fair question! Here's a good place to start, they've been
           | doing monthly progress reports here since January 2020:
           | 
           | https://discuss.ocaml.org/tag/multicore-monthly
           | 
           | There have also been presentations, videos, academic papers,
           | etc., which should all be documented in the monthly reports.
        
       | dang wrote:
       | Past related threads:
       | 
       |  _Multicore OCaml: October 2021_ -
       | https://news.ycombinator.com/item?id=29238972 - Nov 2021 (12
       | comments)
       | 
       |  _Effective Concurrency with Algebraic Effects in Multicore
       | OCaml_ - https://news.ycombinator.com/item?id=28838099 - Oct 2021
       | (59 comments)
       | 
       |  _Multicore OCaml: September 2021, effect handlers will be in
       | OCaml 5.0_ - https://news.ycombinator.com/item?id=28742033 - Oct
       | 2021 (3 comments)
       | 
       |  _Multicore OCaml: September 2021 - Effect handlers will be in
       | OCaml 5.0_ - https://news.ycombinator.com/item?id=28719088 - Oct
       | 2021 (3 comments)
       | 
       |  _Adapting the OCaml Ecosystem for Multicore OCaml_ -
       | https://news.ycombinator.com/item?id=28440385 - Sept 2021 (1
       | comment)
       | 
       |  _Adapting the OCaml Ecosystem for Multicore OCaml_ -
       | https://news.ycombinator.com/item?id=28373155 - Aug 2021 (21
       | comments)
       | 
       |  _Multicore OCaml: July 2021_ -
       | https://news.ycombinator.com/item?id=28039219 - Aug 2021 (14
       | comments)
       | 
       |  _Multicore OCaml: May 2021_ -
       | https://news.ycombinator.com/item?id=27480678 - June 2021 (27
       | comments)
       | 
       |  _Multicore OCaml: April 2021_ -
       | https://news.ycombinator.com/item?id=27140522 - May 2021 (89
       | comments)
       | 
       |  _Multicore OCaml: Feb 2021 with new preprint on Effect Handlers_
       | - https://news.ycombinator.com/item?id=26424785 - March 2021 (29
       | comments)
       | 
       |  _Multicore OCaml: October 2020_ -
       | https://news.ycombinator.com/item?id=25034538 - Nov 2020 (9
       | comments)
       | 
       |  _Multicore OCaml: September 2020_ -
       | https://news.ycombinator.com/item?id=24719124 - Oct 2020 (43
       | comments)
       | 
       |  _Parallel Programming in Multicore OCaml_ -
       | https://news.ycombinator.com/item?id=23740869 - July 2020 (15
       | comments)
       | 
       |  _Multicore OCaml: May 2020 update_ -
       | https://news.ycombinator.com/item?id=23380370 - June 2020 (17
       | comments)
       | 
       |  _Multicore OCaml: March 2020 update_ -
       | https://news.ycombinator.com/item?id=22727975 - March 2020 (37
       | comments)
       | 
       |  _Multicore OCaml: Feb 2020 update_ -
       | https://news.ycombinator.com/item?id=22443428 - Feb 2020 (80
       | comments)
       | 
       |  _State of Multicore OCaml [pdf]_ -
       | https://news.ycombinator.com/item?id=17416797 - June 2018 (103
       | comments)
       | 
       |  _OCaml-multicore now at 4.04.2_ -
       | https://news.ycombinator.com/item?id=16646181 - March 2018 (4
       | comments)
       | 
       |  _A deep dive into Multicore OCaml garbage collector_ -
       | https://news.ycombinator.com/item?id=14780159 - July 2017 (89
       | comments)
       | 
       |  _Lock-free programming for the masses_ -
       | https://news.ycombinator.com/item?id=11907584 - June 2016 (29
       | comments)
       | 
       |  _Lock-free programming for the masses_ -
       | https://news.ycombinator.com/item?id=11893911 - June 2016 (4
       | comments)
       | 
       |  _OCaml 4.03 will, "if all goes well", support multicore_ -
       | https://news.ycombinator.com/item?id=9582980 - May 2015 (113
       | comments)
       | 
       |  _Multicore OCaml_ - https://news.ycombinator.com/item?id=8003699
       | - July 2014 (1 comment)
        
         | laylomo2 wrote:
         | dang
        
       | noncoml wrote:
       | I really didn't think I'd see the day.
        
       | [deleted]
        
       | eatonphil wrote:
       | Congrats!
        
       | sharmin123 wrote:
        
       | nicolashahn wrote:
       | If OCaml gets good tooling and ecosystem I'm totally in. I've
       | heard it's close to Rust but GCed and that sounds extremely
       | enticing.
        
         | jasone wrote:
         | I started using OCaml in 2017, and had a rough start. But since
         | then Dune (https://dune.build/) and the now-excellent LSP
         | implementation have resolved the biggest issues I had. I
         | haven't had such a pleasant development environment since Turbo
         | Pascal! (To be fair, IntelliJ was also pretty good other than
         | the shortcomings of Java.)
        
           | sideeffffect wrote:
           | Since you mentioned using IntelliJ, I can't resist asking the
           | question: Have you played with Scala too? If yes, how would
           | you compare OCaml to it?
        
         | nestorD wrote:
         | Tooling got me from Ocaml to F#, I would recommend it if that
         | is a criteria for you.
        
         | devmunchies wrote:
         | I definitely will use it as my primary server language on side
         | projects after it has a standardized async lib (effect handlers
         | and eio). I was also hoping that rust would be my primary lang
         | but its a little too verbose with all the "<>" for it to be my
         | guilty pleasure. Been dabbling in OCaml since 2018.
        
         | wk_end wrote:
         | It's similar to Rust in certain respects, but it feels very
         | different in several others.
         | 
         | * There's no ownership tracking. This might be obvious - it
         | doesn't need it, it has GC - but is actually kind of
         | unfortunate; even in GC'd languages, linearity can be used to
         | safely model state machines/typestate or for optimization.
         | 
         | * There's no traits/ad-hoc polymorphism at all.
         | 
         | * There's no impls, though a common pattern with a similar feel
         | is to define types inside modules with the actual
         | implementation of the type hidden, and provide an interface via
         | functions to create or interact with instances of the type.
         | 
         | * It uses exceptions for error handling (when it doesn't use an
         | option type) and even as a lightweight control flow mechanism.
         | And now there's algebraic effects as well.
         | 
         | * It has an extraordinarily powerful module system, with
         | functors (pass modules into other modules to produce new
         | modules) and first-class modules (modules that exist as values
         | at run-time that can be passed around to functions).
         | 
         | * It has some more advanced type machinery - GADTs, polymorphic
         | variants, and a very interesting, powerful, almost completely
         | unused object system.
         | 
         | * This bleeds a little into "ecosystem" and a little into "no
         | ad-hoc polymorphism" and a little into the oddness of the
         | syntax and a little into subjectivity, but in general doing
         | really bog-standard imperative stuff in OCaml, while possible,
         | tends to feel more awkward than it does in Rust.
        
         | c54 wrote:
         | I like OCaml a lot but I agree that it suffers from this
         | tooling/ecosystem problem. Even un-fancy languages with good
         | tooling are just going to win, at the end of the day. Go is the
         | main example of this. Rust also has great tooling that's gotten
         | better over time.
         | 
         | I think over time Jane Street will (continue to) open source
         | more of its libraries, and hopefully soon will also migrate
         | onto Dune (internally they use jenga[0]). This should mean that
         | the ecosystem within Jane Street more closely matches the
         | external environment and tooling should get better as they push
         | patches upstream.
         | 
         | Hopefully.
         | 
         | [0] https://discuss.ocaml.org/t/does-jenga-have-more-features-
         | th...
        
           | wk_end wrote:
           | I mean, maybe. But Core and Async have been open source for a
           | long time, and there's still plenty of people out there using
           | Batteries/Containers/Iter/BOS/Lwt.
        
       | jabl wrote:
       | Is there an ELI5 writeup somewhere about what's so nice about
       | algebraic effects?
       | 
       | I skimmed through some preprint on arxiv, and I got the
       | impression that one could implement async/await as well as
       | something like green threads if you select a suitable runtime.
       | But beyond implementing other concurrency abstractions, why
       | should I care?
        
         | classified wrote:
         | https://speakerdeck.com/kayceesrk/effect-handlers-in-multico...
        
         | simplify wrote:
         | The short answer is, algebraic effects allow you to build your
         | own abstractions _like_ async /await. That's extremely
         | powerful.
        
       | rackjack wrote:
       | Whoa, earlier than I expected (didn't think we'd see the PR
       | within the year). Exciting!!
        
       | ijustboughtit wrote:
       | Last time (ca. 1 year ago) I tried learning OCaml, I ended up
       | reading the beta version of Real World OCaml 2nd Ed. IIRC and for
       | some reason all I remember now is that I didn't feel confident
       | regarding the learning material.
       | 
       | The RWO-website https://dev.realworldocaml.org claims that the
       | 2nd. Ed. has been published in Q4 2021, but I can't find it
       | anywhere. Can somebody with experience tell me if RWO 2nd Ed. is
       | the way to go?
        
         | avsm wrote:
         | (Coauthor of RWO here)
         | 
         | We are just finishing edits of a few chapters (the tooling,
         | testing and GADT ones), and then it'll be off to the publishers
         | early in the new year. The online one is therefore pretty up to
         | date.
         | 
         | There's also a thread on the OCaml forums on this topic with
         | more suggestions: https://discuss.ocaml.org/t/how-do-you-stay-
         | productive-in-oc...
        
       | keewee7 wrote:
       | F# is a ML/OCaml with solid concurrent and parallel programming
       | features and has been multiplatform since Microsoft released .Net
       | Core 1.0 in 2016.
        
         | klibertp wrote:
         | > F# is a ML/OCaml
         | 
         | No. F# is an ML dialect, like OCaml. But, you should be aware
         | that the "O" in "OCaml" actually means something. OCaml comes
         | with beautiful object system that's prototypal in nature and
         | structurally typed integrated into the language. F# on the
         | other hand has the object system inherited from .NET, and it's
         | simplistic in comparison.
         | 
         | Also, modules and functors.
         | 
         | So, no, F# is not OCaml. If you absolutely need to use .NET,
         | and know some ML, you can reach for F#, but its limitations
         | will drive you nuts quickly. F# is for C# programmers - they
         | have "full power of .NET" still accessible, plus a few nice
         | things like HM type inference, immutability by default, and
         | maybe computational expressions.
        
           | bmitc wrote:
           | I completely disagree that F# is for C# developers. For one,
           | C# developers are usually fine sticking with C# and its
           | massive ecosystem. F# and .NET more seamlessly run everywhere
           | than Ocaml, which last time I tried is a lot of trouble on
           | Windows. F# has had multicore support from the beginning and
           | hasn't needed a multi-year development process to get there.
           | 
           | I'd like to learn Ocaml (more than just the parts I've
           | learned from F# and SML), but F# is by no means a simplistic
           | language in terms of what you can accomplish. It's easily one
           | of the best designed and most pragmatic languages out there.
           | From the syntax I have seen, F# is cleaner than Ocaml.
           | 
           | > F# is an ML dialect, like OCaml
           | 
           | That's kind of splitting hairs. The object system is
           | different for obvious reasons. F# clearly started as a port
           | of a subset of Ocaml to .NET and was even valid Ocaml code
           | for some time in the early days. That's exactly a dialect.
        
           | pbiggar wrote:
           | But basically no one uses the object part of OCaml
        
             | pjmlp wrote:
             | For various levels of no one.
        
               | rackjack wrote:
               | GTK comes to mind
        
           | pjmlp wrote:
           | F# is not really for C# programmers, C# programmers just get
           | by the F# features that keep being copied into C#.
           | 
           | F# is an ML that is kind of allowed to play on .NET because
           | in a given moment management accepted to integrate it into
           | Visual Studio, and keeps looking for the golden spot that it
           | will take it beyond the VB/C# shadow, always a second thought
           | when the .NET team designs new architecture features only
           | taking VB and C# into consideration.
           | 
           | F# twittersphere is its own bubble, not always with nice
           | opinions about Microsoft and the .NET platform it depends on.
        
         | gmfawcett wrote:
         | F# is a great language, and definitely an ML. But it falls a
         | bit short of being an OCaml. :) The type-system features are
         | quite different -- e.g. F# has no functors and no GADTs, at
         | least not the last time I checked. I think that F# has a
         | different feel and perhaps a different target audience.
        
           | [deleted]
        
       | [deleted]
        
       | Kototama wrote:
       | I'm excited. Haskell gets a lot of attention but I have the
       | feeling that OCaml may be better for _engineers_.
        
         | ghostwriter wrote:
         | How can parallel untracked mutations of untracked state be
         | better for engineers?
        
           | grumpyprole wrote:
           | It may not remain untracked, hopefully types for algebraic
           | effects will land in the future.
        
           | ernst_klim wrote:
           | > How can parallel untracked mutations of untracked state be
           | better for engineers?
           | 
           | What is untracked? Is                   unsafePerformIO
           | (printLn ...)
           | 
           | tracked? What is tracked? Is                   foo :: IO ()
           | 
           | thread-safe? Maybe, maybe not. What meaningful information
           | does this signature says to me? That it does some IO? That's
           | an extremely useless information, especially if most of your
           | code is IO something.
           | 
           | What granularity does IO have? Does                   foo ::
           | IO ()
           | 
           | throws any exceptions? Maybe, maybe not.
           | 
           | The need for effect tracking for writing correct programs is
           | way overstated by some Haskell programmers. It's usually much
           | more prudent to write DSLs which hide effects like variable
           | mutations and logging, than expose them.
           | 
           | For example you can start your program with a pure correct-
           | by-construction core DSL, and then add logging, mutable
           | variables where needed underneath the DSL's terms without
           | breaking the semantics of the DSL. With effect tracking you
           | are doomed to either reinvent custom effects to be able to
           | switch interpreters painlessly, or you'll need to break the
           | DSL by the addition of effects.
           | 
           | Neither is prudent in real world, neither gives more value
           | than takes. What is really funny is that some Haskell
           | programmed believe that logging should be tracked, but
           | allocation apparently should not (yes, it's a side effect).
           | 
           | Where in fact all the "effects" are need to be tracked only
           | when they are meaningful, i.e. when they are part of our
           | DSL's semantics, and not some hidden part of the interpreter
           | I don't need to know about.
           | 
           | Imagine a theorem prover function which creates a conjunction
           | of two terms:                   val conj : term -> term ->
           | term
           | 
           | It doesn't matter if it allocates or logs, at the precision
           | that is interesting to us, it's just a function creating a
           | conjunction of two terms.
        
             | ghostwriter wrote:
             | > unsafePerformIO (printLn ...)
             | 
             | This repetitive talking point is getting boring. Go figure
             | whether it's tracked now:                   {-# LANGUAGE
             | Safe #-}         -distrust-all-packages
             | 
             | > What meaningful information does this signature says to
             | me? That it does some IO? That's an extremely useless
             | information, especially if most of your code is IO
             | something.
             | 
             | That's an extremely narrow view which you wouldn't have if
             | you ever tried to implement a safe sandboxed environment.
             | 
             | > What granularity does IO have? Does [...] throws any
             | exceptions? Maybe, maybe not.
             | 
             | what does it have to do with tracked parallel mutations?
             | 
             | > Neither is prudent in real world, neither gives more
             | value than takes
             | 
             | define prudent and define real-world.
             | 
             | > It doesn't matter if it allocates or logs
             | 
             | have you heard about referential transparency? It's the
             | thing your "theorem prover" example does not have.
        
           | naasking wrote:
           | > How can parallel untracked mutations of untracked state be
           | better for engineers?
           | 
           | It basically requires eager evaluation which, believe it or
           | not, is a huge ergonomic win for people wanting to work on
           | practical problems.
           | 
           | OCaml also preserves the concise syntax and great type
           | inference you get in Haskell.
           | 
           | All in all, a more pragmatic set of tradeoffs I'd say,
           | although it certainly has its own problems.
        
           | sidkshatriya wrote:
           | There are many paradigms in programming. Each have their
           | strengths. A purely functional approach ala Haskell is not
           | the only way. Based on your comment, it would seem no one
           | should use C/C++. Yet many do. It depends on what you want to
           | achieve, what is your abstraction budget, your performance
           | requirement, legacy code...
           | 
           | OCaml offers a pragmatic functional approach to programming.
           | And now you are going to be able to have your OCaml code run
           | in a truly parallel fashion on your multicore CPU.
           | 
           | In the future there are plans to add typing to effects
           | though. (There is support for effects currently but its
           | untyped and experimental). When that happens you can track
           | changes to state (which is a kind of "effect") if you want
           | to...
        
             | ghostwriter wrote:
             | > A purely functional approach ala Haskell is not the only
             | way.
             | 
             | that wasn't the OP's argument though, the argument was that
             | OCaml is somehow generally better for engineers.
             | 
             | > OCaml offers a pragmatic functional approach to
             | programming.
             | 
             | an evaluation of something as pragmatic depends purely on
             | what one whishes to practice. There's no universally
             | objective notion of pragmatism.
             | 
             | > And now you are going to be able to have your OCaml code
             | run in a truly parallel fashion on your multicore CPU.
             | 
             | no, it won't be able to do that automatically. Your code
             | will have to respect certain invariants to function
             | properly, and you as a developer will have to enforce these
             | invariants with the available tooling at hand. Haskell has
             | purity, guaranteed STM, and `par` labels for that. OCaml
             | doesn't have those and the existing codebases will have to
             | eliminate their thread-unsafe public interfaces first.
             | 
             | > When that happens you can track changes to state
             | 
             | how are you planning to track state changes without purity?
        
               | sidkshatriya wrote:
               | > > And now you are going to be able to have your OCaml
               | code run in a truly parallel fashion on your multicore
               | CPU.
               | 
               | > no, it won't be able to do that automatically. [...]
               | 
               | I was comparing it to the old situation in OCaml is that
               | it was _impossible_ to have threads that were executing
               | pure OCaml code and were _not_ IO bound to execute truly
               | parallely. That limitation is removed.
               | 
               | To me it is pretty obvious that you will need to use
               | things like atomics, thread safe data-structures, mutexes
               | etc. to ensure your code runs properly in multicore
               | OCaml. It was implicit in my response. But I should have
               | been more explicit.
               | 
               | > that wasn't the OP's argument though, the argument was
               | that the OCaml is somehow generally better for engineers.
               | 
               | Engineers tend to be pragmatic. OCaml is pragmatic. So in
               | quick short form, OCaml may be better to solve a certain
               | kind of problem than something that is more pure and
               | abstract like Haskell. It was intended as an informal
               | argument and not an argument in a court of law :-).
        
               | youerbt wrote:
               | > pure and abstract
               | 
               | Like math? Engineers would rather not use math?
               | 
               | > It was intended as an informal argument
               | 
               | Maybe. But at this point it just looks like a mean dig at
               | Haskell. A better word would be opinionated. Haskell is
               | opinionated, and that is fine.
               | 
               | The biggest bait in this thread is using the term
               | "engineers". It should rather be: people trained in
               | imperative programming in mainstream imperative
               | languages. Then it makes sense.
        
             | ModernMech wrote:
             | > Based on your comment, it would seem no one should use
             | C/C++
             | 
             | Maybe, there are better options out there these days for
             | parallel and concurrent programs. Parallel programming in C
             | and C++ is extremely fraught for the very reasons the
             | parent brings up. There are so many footguns, starting from
             | the fact that the favorite debugging method of C
             | programmers, printf(), is not even thread safe.
             | 
             | It's so bad that Rust markets as a feature "fearless
             | concurrency", capitalizing on the recognition that the
             | prevailing emotional state of a C or C++ dev writing
             | concurrent or parallel programs is one of _fear_.
             | 
             | And the very thing that makes Rust concurrency fearless
             | over C and C++ is that borrowing and mutability are
             | explicitly tracked. As we enter a world where over a dozen
             | CPU cores are the norm, we are learning what works and what
             | doesn't in writing programs for these machines, and
             | integrating those learnings into new languages.
        
               | pjmlp wrote:
               | One detail that usually is left out of the fearless
               | concurrency story is that it only works in-process across
               | threads, it does very little to help in distributed
               | concurrency across multiple processes accessing shared
               | data, eventually written in various languages.
               | 
               | Which in the age of micro-services is quite relevant as
               | well.
               | 
               | Definitely better than other languages, still doesn't
               | prevent one to actually think about end-to-end overall
               | system design.
        
               | nomel wrote:
               | > starting from the fact that the favorite debugging
               | method of C programmers, printf()
               | 
               | Most everyone I know uses a debugger. Maybe you're mostly
               | exposed to beginner programmers?
        
               | pjmlp wrote:
               | There are couple of them that share this kind of
               | opinions, https://lkml.org/lkml/2000/9/6/65
        
               | nomel wrote:
               | I sympathize with what he's saying, and I imagine he's
               | correct, for his context, but some of us don't work on
               | never-ending code and just want to write the best code we
               | can, as quickly as possible, so we can move on to the
               | next challenge. For those that are more pragmatic, and
               | enjoy working on the hard problems the code is trying to
               | solve rather than the hard problems of the code, using a
               | debugger can be beneficial.
        
               | slaymaker1907 wrote:
               | I prefer printf because it works pretty much anywhere,
               | handles concurrency by default (as in you can see the
               | interleavings, though the log call itself is locked), and
               | allows me to have a custom tailored view of the state I
               | want to see.
               | 
               | The last point may not be obvious, but debuggers have
               | tons of noise for complex programs. In practice I just
               | want to see how my program state changes over time while
               | a debugger shows the entire program state or a large
               | subset of it.
               | 
               | I think the future of debugging is going to be structured
               | program state logging. Ideally we should be able to take
               | our logs and partially reconstruct program state over
               | time. For example, in addition to source location, we
               | should save the lexical information for each variable
               | logged so you can have interactivity with your logs and
               | source code.
        
           | hedora wrote:
           | I assume they were referring to the strong OCaml ecosystem
           | (and collection of C/C++ bindings), not the relative merits
           | of the threading systems.
        
             | wk_end wrote:
             | The OCaml ecosystem is not particularly strong compared to
             | Haskell (or most other languages).
        
         | [deleted]
        
         | jamespwilliams wrote:
         | Agreed. Being able to drop seamlessly into an imperative style
         | is very useful.
         | 
         | I'm someone who isn't an experienced functional programmer, or
         | that deeply knowledgeable about type systems and category
         | theory etc, but OCaml is still approachable to me, I feel I can
         | get stuff done in it. I didn't feel that way with Haskell - I
         | tried, but found the number of ways to do things overwhelming,
         | and a lot of it felt very theoretical. Of course, Haskell's
         | pureness is an impressive and interesting feature; but it isn't
         | for me.
         | 
         | OCaml also has much better systems programming abilities
         | compared with Haskell, IMO. It feels like OCaml is the Rust of
         | the functional programming world (and this is no accident, the
         | Rust compiler was first implemented in OCaml in fact).
         | 
         | This is all completely subjective of course.
        
         | DonaldPShimoda wrote:
         | Totally agree. OCaml is, in general, a better choice for
         | engineering and real-world application. I think Haskell gets a
         | lot of attention because it's _interesting_ (for lack of a
         | better word). I don 't mean "OCaml is a boring language", but
         | rather "Haskell was specifically designed as a playground for
         | advanced ideas in type theory, so lots of weird things happen
         | in that ecosystem." For doing personal projects for fun, I'd
         | rather work with Haskell, but for getting things done probably
         | not.
        
         | gmfawcett wrote:
         | Please let's just all be friends. :) It's fair game to discuss
         | and differentiate the two languages on features, but "better
         | for engineers" is going to take us right into the valley of
         | flame-wars, by way of No-True-Scotsman town. :)
         | 
         | Haskell and OCaml are both brilliant languages, with excellent
         | feature sets and amazing dev teams... and lots of "engineers"
         | who like them.
        
           | yawaramin wrote:
           | Note the difference:
           | 
           | Kototama: ...I have the feeling that OCaml may be better for
           | _engineers._
           | 
           | You: let's not say that OCaml is better for engineers.
           | 
           | People are allowed to feel things.
           | 
           | But I'll give you a concrete reason why OCaml actually can be
           | better for engineers: named and optional arguments. This
           | single feature does wonders for code readability and
           | maintainability.
           | 
           | Actually I'll throw in a bonus reason: no laziness by default
           | i.e. small and simple, predictable runtime that behaves
           | almost exactly like a C executable.
        
             | light_hue_1 wrote:
             | Named arguments exist, https://hackage.haskell.org/package/
             | named-0.3.0.1/docs/Named... That's just one example.
             | 
             | But yes. Optional arguments are a big problem at scale. And
             | laziness is the worst antifeature I could imagine.
             | 
             | But. You can disable laziness and get great performance.
             | You just need to be careful when using libraries and pick
             | ones that have the right strictness.
             | 
             | A strict Haskell would be a killer language.
        
               | pharmakom wrote:
               | > You just need to be careful when using libraries and
               | pick ones that have the right strictness.
               | 
               | Honestly a deal breaker
               | 
               | > A strict Haskell would be a killer language.
               | 
               | PureScript may be this language!
        
             | rackjack wrote:
             | Also, OCaml has records. Haskell has """records""".
        
         | dleslie wrote:
         | OCaml benefits from not looking like operator stew.
        
           | sidkshatriya wrote:
           | Actually OCaml has more operator stew than Haskell. Haskell's
           | use of typeclasses/HKT avoids a lot of operator/function-name
           | noise in the code.
           | 
           | Where OCaml wins is that it does not hate mutation. This
           | makes the code more impure but simpler. Sometimes just
           | incrementing a mutable variable makes more sense than
           | introducing a state monad!
        
             | yawaramin wrote:
             | I'd even argue that OCaml has way less operator stew than
             | Haskell if we include Haskell's strictness annotations,
             | type class instance selectors, and the large number of
             | operators they have in the standard library. By comparison
             | OCaml has a very modest number of operators.
        
             | bitwize wrote:
             | Yes, but is incrementing a mutable variable properly
             | constrained and typed?
        
               | [deleted]
        
               | DonaldPShimoda wrote:
               | What does this even mean?
               | 
               | OCaml's variables are immutable. To use mutation, you
               | have to do so explicitly with the `ref` type, e.g.:
               | let box = ref 0 in         print_endline ("box value: "
               | ++ int_of_string !box);         box := !box + 1;
               | print_endline ("box value: " ++ int_of_string !box)
               | 
               | will print first `0` and then `1`. You cannot put a non-
               | integer into the box because the box has type `int ref`,
               | meaning only values of type `int` can be put into it with
               | the `:=` operator.
        
               | kccqzy wrote:
               | GP is (rhetorically, I assume) asking about whether or
               | not the action of incrementing the mutable variable is
               | typed, not that the variable itself is typed.
               | 
               | For example in normal Haskell the code that uses mutation
               | and code that does not use mutation have different types.
               | A function may have the type                   f :: Int
               | -> Int
               | 
               | but with mutation it can become                   f ::
               | Int -> ST s Int
               | 
               | or                   f :: Int -> IO Int
               | 
               | or                   f :: Int -> STM Int
               | 
               | depending on the circumstances. That's not the case in
               | OCaml. The kind of mutation in OCaml references is the
               | most similar to Haskell's ST monad (not to be confused
               | with State or StateT), but in Haskell the type tells us a
               | mutation is happening inside the function call.
        
             | ghostwriter wrote:
             | You don't have to introduce a state monad to increment a
             | mutable variable in Haskell, you can do that with IORefs
             | pretty much the same way you do it in OCaml. But in a
             | multi-core environment you will eventually want a
             | guaranteed STM.
        
               | sidkshatriya wrote:
               | You are correct. However, IORefs are not idiomatic in
               | "normal" Haskell. However, mutable variables are very
               | much accepted in OCaml.
               | 
               | Adding mutability to the mix via IORefs + Haskell's
               | laziness by default means you don't _really_ know when a
               | particular IORef mutation may really be executed.
               | 
               | In OCaml, evaluation is eager and you know when it will
               | happen. Even when you introduce bangs and special Haskell
               | language extensions, fully removing laziness from your
               | code in Haskell is difficult.
               | 
               | TL;DR: Because of Haskell's laziness you are in some ways
               | forced to be purely functional. OCaml allows you to
               | embrace mutation in ways Haskell does not, in my view.
               | 
               | > But in a multi-core environment you will eventually
               | want a guaranteed STM.
               | 
               | You actually may not always always want STMs. STMs are
               | awesome but something more basic like locks may do the
               | job. It can be more performant to use, say, a mutex. If
               | STMs were superior on every parameter they would have
               | taken over the world. They have not -- they are good in
               | some scenarios and not so good in others...
        
               | ghostwriter wrote:
               | > Even when you introduce bangs and special Haskell
               | language extensions, fully removing laziness from your
               | code in Haskell is difficult.
               | 
               | Why would one prefer to fully remove laziness?
               | 
               | > TL;DR: Because of Haskell's laziness you are in some
               | ways forced to be purely functional. OCaml allows you to
               | embrace mutation in ways Haskell does not, in my view.
               | 
               | unless there's a strive to be more on the side of the
               | Safe[1] language subset, Haskell can be told to embrace
               | the same mutation property with a combination of
               | `unsafePerformIO` and `seq`. People tend to avoid it
               | because the language offers a tooling to achieve better
               | mutation properties. Overall, my argument here is that
               | OCaml's idiomatic approach to permissible mutations
               | doesn't seem to be a competitive advantage when it comes
               | to software development in general, but rather a flavour
               | that imperative programmers prefer due to their
               | familiarity with the concept.
               | 
               | > You actually may not always always want STMs.
               | 
               | Whenever there's a non-trivial retry policy, one should
               | prefer to choose STM + queues over debugging adventures
               | with Locks and Mutexes. Almost all of multithreaded
               | software I can immediately think of have non-trivial
               | retrying logic.
               | 
               | [1] https://ghc.gitlab.haskell.org/ghc/doc/users_guide/ex
               | ts/safe...
        
               | emmelaich wrote:
               | > Why would one prefer to fully remove laziness?
               | 
               | Far from an Ocaml/Haskell expert, but is it that laziness
               | makes resource use less predictable?
        
               | ghostwriter wrote:
               | Laziness on itself does not prevent one from properly
               | evaluating resource utilisation. In fact, laziness helps
               | in resource preservation. But what makes it less
               | predictable is various optimisation techniques that come
               | to aid the lazy environment: strictness analysis, rewrite
               | rules, and stream fusion[1][2]. They may change
               | significantly between compiler releases and affect the
               | previously optimised codebase.
               | 
               | [1] https://wiki.haskell.org/GHC_optimisations
               | 
               | [2] https://markkarpov.com/tutorial/ghc-optimization-and-
               | fusion....
        
             | yodsanklai wrote:
             | I'd say OCaml wins in term of operators and maybe as a
             | language until you start using monads. My entirely
             | subjective feeling is that modern OCaml codebases use more
             | and more monads, the language is becoming less elegant and
             | tedious as a result.
        
               | WastingMyTime89 wrote:
               | The introduction of let+ and let* made using monads
               | fairly elegant in my opinion but this is a recent
               | addition so you might have never seen it used. Outside of
               | concurrent code monads are not that common in my
               | experience.
        
               | rackjack wrote:
               | Module hell?
        
           | throwaway894345 wrote:
           | When I tried to dabble in OCaml, it definitely looked like
           | operator stew to me, but I'm coming to it from the C, Python,
           | JS, etc world so maybe Haskell is even worse in this regard?
        
             | yodsanklai wrote:
             | I'd say that the learning curve in Haskell is much steeper.
        
             | saghm wrote:
             | OCaml definitely has a lot of built-in operators, but
             | Haskell makes it absurdly easy to define your own operators
             | as well, with built-in syntax for using binary operators as
             | prefix functions and vice-versa. I'm not sure there's a
             | definitive answer, but that's probably in large part
             | because the idea of "operator stew" is pretty subjective.
        
               | mcintyre1994 wrote:
               | Ocaml makes it super easy to define your own operators as
               | well. I was debugging a performance issue in an Ocaml
               | codebase when I was very junior and new to the language,
               | and proudly reported my finding that we shouldn't be
               | using the (**) power operator in some algorithm but just
               | multiplying and surely this was the cause of the problem.
               | Turned out somebody had defined (**) as 64-bit multiply
               | :)
               | 
               | That said I don't know Haskell to compare!
        
               | jimbokun wrote:
               | > Turned out somebody had defined (*) as 64-bit multiply
               | :)
               | 
               | Well I don't think you should have been the one
               | embarrassed in that scenario.
        
             | _old_dude_ wrote:
             | You can try reason first, it's a frontend for OCaml with a
             | C-like syntax
             | 
             | https://medium.com/@asankhaya/reason-with-
             | ocaml-b75697a6c00b
        
               | throwaway894345 wrote:
               | Yeah, I played around with Reason but at the time the
               | tooling kind of sucked and it only seemed to be used to
               | generate JavaScript via BuckleScript. Not sure if things
               | are better these days or not.
        
         | baby wrote:
         | I see Rust as an imperative language with functional support,
         | and OCaml as a functional language with imperative support
        
       | sidkshatriya wrote:
       | Some questions:
       | 
       | - Is merging this PR going to be more or less a formality now?
       | I'm assuming subsequent PRs will make further improvements/fix
       | any further bugs discovered. When is the merge to trunk likely to
       | happen?
       | 
       | - (Not that it really matters, but I'm curious). Will this PR be
       | merged as-is with nearly 4000 commits or will it be squashed? The
       | history exists in the multicore repo but will the history be
       | brought into the ocaml repo?
        
         | sadiq wrote:
         | 1. Before multicore got to this PR stage it went through two
         | phases of detailed review by the core team. A summary of this
         | is on November's Multicore Monthly:
         | https://discuss.ocaml.org/t/multicore-ocaml-november-2021-wi...
         | . The tasks coming out of that which are marked post-MVP will
         | be follow-up PRs before the 5.00 release.
         | 
         | 2. That is unclear at the moment. There's a lot of useful
         | history in those commits (which link out to issues and PRs on
         | ocaml-multicore's repo) but at the same time, it also includes
         | a lot of experiments that were ultimately backed out.
        
       | pjmlp wrote:
       | Great news! Congratulations to everyone involved.
        
       | lgrialn wrote:
       | Hurray!
       | 
       | My wish for Ocaml is that it could somehow be popular enough to
       | have more... casual users, let's say. I enjoy playing with it
       | more than any other language I've run into, but everyone else
       | falls so deeply into it that I don't generally follow their
       | discussions very well. (Maybe I'll fall in deep myself in time,
       | but it remains to be seen.)
        
         | ModernMech wrote:
         | I don't know if you've seen this language yet and I haven't
         | used it, but Grain seems to take a lot of inspiration from
         | Reason. Seems like they are trying to target a more casual
         | audience.
         | 
         | https://grain-lang.org
        
         | Ericson2314 wrote:
         | Someone needs to get OCaml running on the Go runtime, so it can
         | be an F# for that ecosystem.
        
           | ernst_klim wrote:
           | This is a very bad idea considering Go runtime is optimized
           | for way less allocations due to 1) how good Go in stack
           | allocation is and 2) how mutable everything is.
           | 
           | OCaml on the other hand has an extremely well optimized
           | runtime for lots of small heap allocations (typical in FP),
           | and produces good asm code for functional patterns.
        
           | whimsicalism wrote:
           | What's the motivation? OCaml is roughly as performant as Go.
        
             | Ericson2314 wrote:
             | Pure naked grab at more users. I don't mean to imply there
             | any anything better about Go's runtime at all.
        
           | yawaramin wrote:
           | With all the problems arising from leaky abstractions and
           | trying to adapt to a foreign runtime? Imho there's no point.
           | Especially now that OCaml Multicore is on the way. A much
           | better effort, for anyone interested, would be to vastly
           | simplify the OCaml build and package management story to be
           | more Go-like.
        
             | Ericson2314 wrote:
             | > With all the problems arising from leaky abstractions and
             | trying to adapt to a foreign runtime?
             | 
             | Huh? The point is Go might be a lousy language, but I can't
             | think of anything OCaml _needs_ to do that the Go runtime
             | cannot do. This wouldn 't be leaky and the FFI could be
             | quite good.
             | 
             | > Especially now that OCaml Multicore is on the way.
             | 
             | As I wrote in the other reply, this would be a naked ploy
             | for new users, and flexing the language isn't wedded to a
             | single run time.
             | 
             | Multicore OCaml isn't just a runtime change, but also
             | demonstration of the new effects indicating that the
             | language can do parallelism without bad concurrency
             | problems. All that language-side work carries over to the
             | other runtime: you get to show off Goroutines done more
             | safely!
        
               | c-cube wrote:
               | Does Go's runtime do generational collection? No. Does it
               | support tailcalls? I have no idea but I doubt so. Without
               | these there cannot be any chance for OCaml-on-go; more
               | blockers would probably come to mind quite quickly.
        
       ___________________________________________________________________
       (page generated 2021-12-21 23:01 UTC)