1. 56
  1.  

  2. 31

    This is interesting ’cause I came to Rust from (mainly) OCaml back when Rust was new, and my complaints were pretty different. My main memory is that I had lots of issues with closures, which now seem to be mostly smoothed over by impl Trait, better type inference, and better lifetime inference.

    In retrospect, my experience was that writing Rust like it is OCaml is not much better than writing OCaml. Rust is good at lots of things when doing this, but they’re all things that OCaml is good at, and you run into bunches of inconveniences because OCaml is designed to be written in that style and Rust is not. To make Rust better than OCaml, you have to write it like Rust, and that’s only worth it if you want the things Rust is good at which OCaml isn’t: mainly, IMO, control of memory via borrow checking. Without that you just get a weird-looking, very inconvenient OCaml. Looking at the “things to like about Rust” it’s community, libraries, tooling, more tooling, aesthetics… oh yeah, and macros. Only one actual language feature. Not that the ecosystem around the language isn’t important and worth being a priority, but the actual language feature is pretty far down the list.

    Mutability in Rust is also one of those things you have to embrace, coming from an immutable language. im is an extremely nice tool, but in my experience mainly useful for only certain things like sharing data between Erlang-like actors. The thing to realize is that the Problem with mutability comes from shared (aliased), mutable data. Immutable-by-default languages deal with that Problem by keeping mutability to a minimum. The whole point of Rust is that it deals with the same Problem by keeping sharing to a minimum, and it works just as well.

    So yeah, you CAN write Rust with Rc’s everywhere and lots of immutability. But apart from the Rust ecosystem itself, IMO there isn’t much to gain by doing that vs just writing OCaml, and OCaml is better at writing OCaml than Rust is.

    That said, a lot of the things they label as sucking about Rust are definitely problems:

    • I was bitten by the pattern matching one myself recently, and apparently there’s a feature in development to make it suck less, but it’s been in development hell for years. You can pattern match “through” references just fine, but Rust is replete with smart pointer types that can look like references but aren’t, and pattern matching through them Just Doesn’t Work.
    • Related to that is “too many ways to do things”. It’s something you get used to as you learn the languages, but it still causes occasional Feels Bad moments when you remember that to write an iterator you need to implement iter(), iter_mut(), and into_iter() which are all exactly the same thing except for returning &T, &mut T and T. Threading vs. non-threading variants (Rc vs Arc) are less common but similarly Feel Bad. In my experience trying to fix this rapidly leads into a grim hellscape of overly-generic generics and undecidable type theory. Maybe someday we’ll figure it out, but it will probably be in a different language than Rust.
    • Over-use of macros is definitely a code smell, one I suspect comes from the author wanting to write OCaml. Rust very much embraces “make it explicit and clear” over “make it concise and clever”, which IMO is a good thing but dang do you do a lot of typing sometimes.
    1. 7

      Looking at the “things to like about Rust” it’s community, libraries, tooling, more tooling, aesthetics… oh yeah, and macros. Only one actual language feature.

      You kind of undersold the “other” two language features: zero-cost abstraction and “fearless concurrency” (which has taken OCaml… some time to get to). You mentioned “control of memory”, but it’s only a little bit about “control” and often more about the zero-cost aspect.

      I agree with the rest of your point, though. I feel like OCaml is a really great language and arguably more productive and expressive than Rust for domains where the (pretty small) raw performance difference and concurrency issues don’t matter much.

      1. 2

        Zero-cost abstraction is nice but IIRC OCaml’s abstractions are generally pretty cheap. I mainly do indie gamedev stuff, so avoiding GC pauses is way more important than having absolute performance. Others’ priorities may vary.

        Fearless concurrency is absolutely awesome though. I don’t often need to use it, but when I do… right now the only languages that do concurrency Right are Erlang and Rust.

        1. 3

          Yes, OCaml is very performant for sure. And Rust isn’t immune from “GC pauses” in a way: https://abramov.io/rust-dropping-things-in-another-thread

          Fearless concurrency is absolutely awesome though. I don’t often need to use it, but when I do… right now the only languages that do concurrency Right are Erlang and Rust.

          Agreed. Any opinion on Clojure with respect to concurrency?

          1. 5

            And Rust isn’t immune from “GC pauses” in a way…

            Memory management always costs something, somewhere. The thing is just that real-time programs like games or music/video players must have control over where the cost happens, or sooner or later it will catch up with you at an unexpected time and you will drop frames. How bad this is depends on the program and how picky you/your users are.

            Any opinion on Clojure with respect to concurrency?

            Unfortunately no, I haven’t used Clojure enough. Clojure is one of the coolest languages I will probably never use; I tend to write either command line tools or video games, and either way having long start-up times are painful at best. Though now that I check again it appears a “hello world” program starts and runs in only two seconds on my desktop now, so maybe it’s worth checking up on again.

            1. 2

              Clojure is one of the coolest languages I will probably never use

              Yeah, same here. I used it once for a small app. It’s a really nicely designed Lispy language. I like that it enforces immutability and feels more FP than your typical LISP or scheme. But, the startup time was rough, memory consumption was high, and I still just can’t see myself choosing an untyped language when I have a say. Definitely just my bias. But I still admire it and really like how clean the code looks.

              1. 4

                But, the startup time was rough, memory consumption was high, and I still just can’t see myself choosing an untyped language when I have a say.

                Nitpicky, but: it’s dynamically typed. It’s not untyped, which is another beast entirely.

                1. 1

                  Yes, fair enough.

              2. 2

                GraalVM is supposed to help with clojure startup times. Might be worth considering.

                This claims 100x improvements:

                https://github.com/io-tupelo-demo/graalvm

                1. 1

                  Two seconds!? I can’t even…

            2. 1

              I’d be curious on your thoughts of how Rust and OCaml are handling concurrency today. I’m somewhat out of the loop on each, though familiar with both languages. If I were picking between the two for a project that had some amount of inherent concurrency, what would the tradeoffs be?

              1. 2

                I’m definitely not an OCaml expert. But I’d say it depends on what kind of concurrency you need. If you want to be able to have some amount of multi-threaded-ness, I’d say you are pretty much forced to use Rust today, unless you’re okay with the almost-there-but-still-evolving multicore branch of OCaml.

                If you need single-threaded async, there are libraries for OCaml to do that.

                Otherwise, it’s just up to whichever language you like more.

                1. 2

                  Makes sense, thanks for the insight!

            3. 4

              But they’re implementing the Dark Language interpreter. Dark is an immutable functional programming language that uses pure functional data structures.

              I like writing mutable code in Rust, but that’s not going to be an option here.

              1. 3

                I like writing mutable code in Rust, but that’s not going to be an option here.

                But the implementation language and the destination language don’t have to match. OCaml itself is written in C and OCaml and C is quite different from OCaml.

                1. 1

                  But the implementation language and the destination language don’t have to match

                  But it sure helps.

              2. 2

                I’ve been spending some more time with Haskell lately, using it to learn how first-order unification and Hindley-Milner type checking works; and I implemented some of the same code in Rust. Based on that experience, I think it’s better to think of Rust as a C++ competitor that borrows concepts from the ML-family of languages. Compared to Haskell, Rust code is extremely verbose and finicky in the details (I.e. owned vs borrowed vs mutably borrowed). The trade-off is that, if you’re fimiliar enough with Rust, you have a pretty good idea what the resulting assembly code will be. In comparison, Haskell compilation is a black box due to lazy evaluation and GC.

                I think there’s definitely a place for a language that is closer to the ML-family but that fully embraces linear types to acheive static memory management. I’m trying to learn enough to build a prototype, though it might take years to get there. I’m planning to use concatenative syntax and semantics to minimize the syntactic overhead of pervasive linear types. And I’m also playing with the concept of implicit parameters (similar to shell environment variables) as a substitute for globals.

                1. 2

                  I love ocaml, and have so far dabbled in but not really done much with rust. however, I have an ocaml library that I’m seriously considering porting to rust, despite the fact that it will undoubtedly be a lot more inconvenient to implement, because of one other major rust feature - rust libraries can be seamlessly consumed as though they were c libraries by any other language with a c ffi. I know very few languages with this property - rust, d if you are willing to use a restricted subset, c++, zig and ats are the main ones that have crossed my radar, though there are probably a few even more niche ones that I have seen and forgotten.

                  1. 4

                    It’s not 100% seamless, you have to mark C-consumable functions as such and there are certain Rust types those functions can’t consume or produce (enums, generics, etc). But it’s probably like 80% seamless.

                2. 19

                  The unsurprising takeaway here seems to be that’s its frustrating to write OCaml in Rust.

                  With more than a couple of weeks in the language and more of a willingness to use Rust-native idioms instead of trying to straight translate OCaml (among other things, I think an arena allocator for those AST nodes would probably simplify that rats nest of pattern matching that strikes me as a bit of a smell pointing at the square-design-into-round-hole pounding going on here) it would probably feel like less of a frustrating series of brick walls.

                  1. 11

                    Right. Even though Rust took a lot of inspiration from OCaml, and in spite of some Rust users saying they write in a “functional style”, Rust is really not a functional language. Rust is an imperative language. But even calling it “imperative” is kind of an injustice because its lifetime mechanism has really brought forth an idiom that is fairly unique to Rust (in my experience).

                  2. 17

                    The complaints listed here for Rust are exactly what I have been struggling with!

                    However, I can’t actually pattern match like this in Rust because I don’t have DLists, I have Arc<Dlist>, and you can’t pattern match through Arcs and Rcs and Boxes.

                    When trying to create thread safe recursive data types, I have struggled a lot with managing Arcs. Instead of normal pattern matching, you have to dereference the Arc within your match statement and then use ref to declare that you don’t actually want to access the data but a reference to it (I think I’m interpreting that correctly?).

                    match *instruction {
                        Instruction::Jump(ref j) => {
                    

                    Want to make this mutable? Yikes! Shoving Mutex into here makes things far more complicated because that’s another dereference you have to do every pattern match. Paul ended up doing this:

                    match args.iter().map(|v| &(**v)).collect::<Vec<_>>().as_slice()
                    

                    which I would say is unreadable! I had a huge number of mutable concurrent data structures and I ended up switching all of them to immutable which simplified things greatly, but this had its own costs. I wrote this up thoroughly on my own blog.

                    I’ve been writing Rust for quite a while now, enough to where I start thinking with the borrow checker and I know what structures/patterns won’t work before I write them, but I still hit walls pretty hard. Refactoring that codebase from mutable to immutable was very challenging in Rust, whereas in Java refactoring can be a lot faster. I feel like taking the wrong step in Rust can end up costing much more time compared to other languages, which ends up making prototyping difficult. (Non-concurrent, non-recursive prototyping is substantially easier)

                    1. 9

                      This is definitely an area that can be challenging! I think learning the AsRef and AsMut traits can be really useful for this case. In this case, Arc has an AsRef implementation that gives you an immutable reference to the contained type.

                      Here’s an example from the Rust Playground on the use of as_ref on an Arc, along with Mutex::lock to access the value inside the Mutex as an owned value by blocking (to attempt locking without blocking use Mutex::try_lock, for mutable reference use Mutex::get_mut instead).

                      1. 3

                        Question: How does the Rust compiler itself solve these problems? Or does it not have to?

                        1. 7

                          The internals of the Rust compiler actually intern a lot of data, tied to the lifecycle of the memory arena containing the data. So for type information (the most widely shared information), you’re working with lifetimes rather than Arc. Here’s a section of the rustc dev guide explaining: https://rustc-dev-guide.rust-lang.org/memory.html

                        2. 3

                          In my experience with Rust, the best way to write recursive data structures like Parse Trees is to simply reference Nodes by their indices in the backing data structure (usually a Vec).

                          struct Node {
                              id: usize,
                              parent: usize,
                              children: Vec<usize>,
                          }
                          
                          struct Tree {
                              nodes: Vec<Node>,
                              root: usize,
                          }
                          

                          I imagine this isn’t quite as efficient as using a tonne of Arc<> and unsafe but it’s plenty fast enough for anything I’ve ever needed to write and it circumvents a lot of extremely ugly code.

                          1. 2

                            Seems like a significant compromise on type safety though.

                            1. 1

                              That can be mitigated with something like:

                              type NodeID = usize;
                              
                              1. 4

                                That’s a type alias. You want a newtype, like this:

                                struct NodeID(usize);
                                
                                1. 1

                                  Sorry, yes, you’re quite right.

                        3. 7

                          I think what this comes down to is that there isn’t a great language for building languages :-/

                          OCaml is supposed to be that language, and I even wrote in ~2015 on my website that I would write all future language projects in OCaml. Yet I didn’t go down that path for Oil, and I don’t regret it.

                          Instead I came up with this somewhat weird Python + ASDL + multiple code generator combo, but it has worked out well, and compiles to nice C++.

                          It’s both low level and high level at the same time. Languages need both because they’re extremely repetitive tree matching on the one hand, and very performance sensitive on the other (which I learned the hard way).


                          A few more threads about metalanguages, with extensive comments on using Rust to implement languages:

                          https://old.reddit.com/r/ProgrammingLanguages/comments/bkohba/what_language_did_you_use_to_implement_your/

                          https://old.reddit.com/r/ProgrammingLanguages/comments/ays7d7/languages_used_to_implement_compilers/

                          https://notamonadtutorial.com/an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler-e94775f60dc7


                          This is the programmer’s version of Guy Steele’s computer science complaint: https://www.youtube.com/watch?v=7HKbjYqqPPQ

                          That is, that the language used for describing languages is horribly imprecise and inconsistent.

                          1. 5

                            I guess it is supposed to be Racket … and yet often it doesn’t seem to play out that way.

                            As an outside observer, I wonder why that is.

                            1. 7

                              Yes exactly, Racket is supposed to be a language for languages. A bunch of reasons that I see:

                              1. Performance. As mentioned, I learned the hard way how performance-sensitive languages are. Racket was a CPython-like interpreter in C until recently: https://blog.racket-lang.org/2020/02/racket-on-chez-status.html

                              I wrote Oil in Python and it was way too slow. Racket would have been also too slow, and even with the new runtime, I doubt it would be fast for parsing shell. JITs tend to speed up numeric workloads more than string workloads. String workloads are dominated by allocations and the JIT may not see through those.

                              1. Algebraic data types. I’m not up to date on what Racket offers here, but all the Lispy mechanisms I’ve seen fall somewhat short of the real thing. Algebraic data types really help when dealing with languages. They affect 50-80% of the lines of code. Compilers and interpreters are full of conditionals, and it’s a huge help to encode those as data rather than code you have to step through.

                              2. Static types help too. Oil started out dynamically typed and is now statically typed with MyPy.

                              3. Syntax. Racket does support syntax unlike other lisps, but I think it’s not culturally there, and the support for parsing is relatively weak. For example, the C ecosystem has re2c, which I used in Oil, etc. The Python ecosystem has a number of options for parsing as well.

                              4. Runtime dependencies (for interpreters). As far as I call, the Shill shell (a research project) was written with Racket. But then they switched to something else because the runtime got in the way.

                              5. Build time dependencies (for compilers). Compilers are often bootstrapped in a unique way – e.g. Go compilers in Go, Rust in Rust, Zig in Zig, Clang in C++, etc. Compiler writers want to use their own language, and not someone else’s.

                              So in all of those areas, OCaml and Rust beat Racket IMO. And on top of that, I agree with the downsides about both OCaml and Rust. (Not that my own solution doesn’t have a lot of downsides. The important thing is that they’re all fixable because the code is small and under my control!)

                              I think Racket is probably very nice for prototyping languages. I’m not sure it’s good for production quality implementations, at least when you’re talking about competitors to CPython, LLVM, rustc, Go, Julia, etc.

                              Julia was bootstrapped in femtolisp though, which is interesting. I hacked on it at the beginning of Oil, but decided I didn’t like that style.

                            2. 3

                              From my perspective, as someone who’s spent the past 5 years doing more pure functional programming (Elm and Haskell) professionally than anything else, and who’s been working on a compiler written in Rust outside work…I would gladly describe Rust as “great for building languages.”

                              The learning curve was substantial, but now that I’m comfortable with Rust, I don’t think anyone could sell me on OCaml or Haskell (or any other language I’ve heard of) as a better choice for building a compiler.

                              Granted, that’s in large part because execution speed is extremely important to me. I have very high standards for how fast I think a compiler should run!

                              1. 6

                                I have very high standards for how fast I think a compiler should run!

                                Kind of ironic, since you’re using Rust. (I kid, I kid!)

                                1. 1

                                  Haha yeah rustc is definitely way below my bar!

                                  1. 1

                                    To be fair it is doing some amazing things :)

                                2. 2

                                  Purely opinion, based on looking at some code like

                                  https://github.com/gleam-lang/gleam/blob/main/src/typ/expr.rs

                                  (linked in the above threads)

                                  It looks more concise than C++, but a lot more wordy than OCaml (or Elm). I’d be interested in seeing other idiomatic Rust code that implements languages (compilers, interpreters, runtimes).

                                  1. 2

                                    I’m the author of this code. :)

                                    I did experiment with using OCaml to start with, and yes, the Rust version is a lot more verbose, especially when using shared mutable references (which are very concise in OCaml). Despite this I prefer the Rust experience, and I think it’s a more generally useful language to know.

                                    1. 2

                                      Yes I think we talked on the original Reddit thread which I quoted here

                                      https://lobste.rs/s/vmkv3r/first_thoughts_on_rust_vs_ocaml#c_v5ch1q (as well as your article)

                                      I think you said you prefer Rust there. That is a useful data point for sure. I’m not experienced with Rust but I can definitely see why it’s appealing for languages.

                                      I actually think that “procedural” / stateful code with algebraic data types is a pretty good combo. That’s basically how my Oil project is written, with statically typed Python + ASDL.


                                      I heard someone say that Rust shows you can “just mutate”. In other words, some languages like Clojure and Erlang rely on immutability for concurrency. But Rust relies on its type system for that, so you are safe with mutation.

                                      And I just read someone say something similar here:

                                      https://news.ycombinator.com/item?id=24295408

                                      Others sometimes don’t like to hear this, but IMO, Rust is not at all functional. … Rust is very much procedural

                                      Although not everyone agrees.

                                      I have come around to this viewpoint. I used to program in more of an immutable style, but now I favor local mutation and “principled” global mutation. It seems to work well for languages, e.g. lexing and parsing are inherently stateful. And that style does seems to be in line with Rust’s design.

                                3. 1

                                  Thanks for these resources, will read them!

                                4. 7

                                  Important insight: in Rust, there’s no functional distinctions between mutable and immutable data. Mutable data structures give you exactly the same guarantees as immutable ones, and have the same API.

                                  The difference between the two is just performance: dense memory layout, O(1) access, O(N) clone vs sparse layout, O(log N) access, O(1) clone.

                                  This is as big a claim as it seems, see http://smallcultfollowing.com/babysteps/blog/2018/02/01/in-rust-ordinary-vectors-are-values/ for why it is indeed the case.

                                  1. 5

                                    It makes sense that Rust has better libraries and IDE support, it has more funding and a larger community.

                                    in OCaml you have opam, esy, dune, and OCaml itself all doing part of the job. They sorta kinda mostly work well together, until they don’t. And as you wire them together, you really need to understand what each tool does, where it starts and stops, and how they integrate.

                                    I think this is only true if you’re trying to use Reason, now ReScript?. If you stay firmly within OCaml-land you only need to know two tools: Opam and Dune. Opam is a package manager and Dune is a build system. It’s nice that Cargo can combine these — and Cargo is excellent — but so is Dune. Dune has been introduced widely in the last two years and IMHO has totally transformed the OCaml build story. It’s true that Reason has introduced a lot of segmentation, but if you stay away from npm things are generally good.

                                    Re macros: I totally agree that PPX’s fall short sometimes and a hygenic macro system for OCaml would be awesome. That said, the blog post supposedly showing trouble in the PPX ecosystem is from four years ago and I believe the proposed solution has been adopted. Overall the PPX infrastructure has improved a ton in the last four years.

                                    I’ll also say OCaml has a great module system with “functors” (function-like things that take modules as arguments and produce new modules) that subsumes much of the use-case for macros.

                                    Re aesthetics:

                                    OCaml is so ugly that the community came up with a whole other syntax for it

                                    Well, the JavaScript community came up with a JavaScript syntax for it. Of course beauty is in the eye of the beholder, but I happen to prefer the OCaml syntax.

                                    1. 8

                                      That’s one point I disagree with. Merlin (in OCaml) is just amazing, and much better than rust-analyzer. It’s fast, it’s very, very robust to bad syntax, and I only have good things to say about it. RA is not too bad but it’s not as mature yet.

                                      The ppx story keeps unfolding with, imho, still no viable solution in sight (soon there’ll be a ppxlib 2.0 or something, that doesn’t improve ppx stability, and we still don’t have a stable AST to write these parsers again.) I would love macros and deriving in OCaml, but I don’t see any way of getting them in a stable, future-proof way.

                                      1. 3

                                        I would love macros and deriving in OCaml, but I don’t see any way of getting them in a stable, future-proof way.

                                        Both Haskell and Rust wisely have deriving so OCamls stubborn insistence to defer it to a combination of ppx_deriving/type_conv and support from the build system is just death by a thousand cuts.

                                        1. 2

                                          I couldn’t agree more. Sadly it’s difficult to contribute this kind of functionality and get it accepted.

                                      2. 4

                                        This is exactly what I was thinking about reading his criticisms of OCaml. Sure, the language has some warts (I think mostly due to adding features over the years) but I find the core syntax very nice. Reason to me is incredibly ugly. Along similar lines, OCaml + Merlin + Emacs is one of the best toolchains for writing code that I’ve ever used.

                                        The authors comments about bad error messages are valid, they could definitely use some work. But I think a lot of the complaints about dealing with the typechecker is something you get comfortable over time, or if you sit down and read up on the type inference/checking algorithm.

                                        1. 1

                                          I think this is only true if you’re trying to use Reason, now ReScript?

                                          No, you can also use Esy as a replacement for opam on pure OCaml projects, without having to use Reason. ReScript (formerly BuckleScript) is a separate toolchain that leverages npm and a different build tool (ninja).

                                          To the wider point, though: I was going to take issue with the way Paul mentioned confusion with so many build tools, but I’m forced to admit that’s partly on the OCaml community. If the community-recommended tools don’t solve real developer needs like cross-project dependency sandboxing and build caching, then eventually alternative tools (like Esy and Nix) will enter the picture and compete for market share.

                                        2. 3

                                          Meanwhile, OCaml has a ton of stuff that they really should prune and have not.

                                          You can compile 20 years old OCaml code with minor (if any) adjustments. Try that with Rust.

                                          Meanwhile, OCaml is so ugly that the community came up with a whole other syntax for it

                                          I still have no idea how ReasonML managed to make itself look more popular than it really is. I’m still to meet anyone, outside of the JS community, who uses it.

                                          1. 7

                                            You can compile 20 years old OCaml code with minor (if any) adjustments. Try that with Rust.

                                            since it’s not 20 years old, it’s indeed a bit hard 😂. But otherwise, rust’s commitment to backward compatibility is as strong as OCaml. You might have to adjust one or two lifetimes with rust2015 code… same as adjusting your OCaml so it’s -safe-string compatible.

                                            1. 4

                                              Reason is specifically FOR the JS community, I’m not sure what this comment means.

                                              Are you expecting people outside of the Ocaml ecosystem, and outside of the JS ecosystem, to be using Reason?

                                              Maybe you could clarify your position.

                                              1. 7

                                                My position is that:

                                                1. There exists a vocal minority of people who claim that OCaml syntax is ugly and everyone prefers Reason syntax.
                                                2. Their claim isn’t true.
                                                1. 1

                                                  Oh, I see.

                                                  Well, in that case, I can agree with you more easily. I think ReasonML is probably more approachable to some types of developers because:

                                                  • There aren’t good resources for “I only need to know the syntax of Ocaml to use a library”
                                                  • It’s pretty easy to pick up in a few hours if you need to
                                                  • It provides a more robust type-system experience than typescript, with decent errors, and for developers who are coming to it with not-quite-as-much FP experience as an Ocaml dev, that goes a long way towards helping them stick with it and complete their tasks.

                                                  I think ReasonML is a well-designed tool, and sticks to a narrow enough playing field as to create that type of loyalty with the users. Kinda like how Rails users behaved 2008-2012ish.

                                                  In a twisted way, Rust fails incredibly hard at exactly this, an insight you already alluded to. I think that in a few years, there will be a big wake up call as those users realize “Wow, working with code that’s hard to work with is MUCH more trouble than it’s worth.” That’s going to compound itself more and more as users leave the ecosystem and leave behind more and more unmaintained libraries and the like, forcing newer users to dig through code they can’t easily wrap their heads around. It’s one of those hydra problems, where you cut a head off and two more grow back, only they’ve cut off too many heads now and they’ve realized they should’ve stopped cutting a while back.

                                                  Anyhow, Ocaml syntax is not difficult at all, and honestly, the whole ReasonML value proposition is just “syntax that’s NOT unfamiliar, OR difficult, and with better errors than Typescript.” at least, imo.

                                                  Thanks for clarifying, sorry if it seemed petulant of me to inquire.

                                                  1. 1
                                                    1. It’s not a vocal minority (a minority of what, btw?). Pretty much everybody outside the ML world thinks ML syntax is ugly/difficult/unapproachable.
                                                    2. It’s a subjective claim (‘ugly’/‘beautiful’), so ‘true’/‘false’ is not a useful way to think about it. Instead, we should ask, is that really how they feel? And if so, what can be done about it? you have two options: argue with them that their personal preference is not correct; good luck with that. Or, offer a syntax which looks better to them. Which as we can see from the success of Reason (and Elixir), actually works.

                                                    The funny thing is that a lot of people who start in the Reason world actually come to prefer OCaml syntax over time. One recent example is https://discuss.ocaml.org/t/ann-sihl-0-1-0/6374

                                                2. 3

                                                  …still to meet anyone outside the JS community who uses it…

                                                  To be fair, that particular community is probably the single largest one in software development. If 5% of JS devs seriously tried Rescript that would easily dwarf most other FP user communities.

                                                  1. 2

                                                    I still have no idea how ReasonML managed to make itself look more popular than it really is

                                                    Maybe you quoted the exact reason why above your reply?

                                                  2. 2

                                                    Your code listings look like this on Firefox 79.0. I can only read them if I select the text.

                                                    1. 2

                                                      A very common thing I’m doing is to create a new “scope” (or symbol table) in Dark, which is the old scope plus a few variables. In mutable languages, this is expensive in terms of performance, so language implementations often create a sort of stack of scopes to manage the performance implications. With immutability, you create a “copy” of the old scope for free, and then add your new values to it. When you’re done, you just keep using the old scope, which hasn’t actually changed.

                                                      That’s a little misleading. The performance implications don’t magically disappear in the immutable language, but they’re hidden away by the library or language implementation. There’s no reason an equally clever immutable data structure can’t be implemented in a language that allows mutation.

                                                      Personally, I prefer mutable languages. It’s always possible to have immutable data structures in a mutable language, and it’s always a hassle not having them when you need them (i.e. to get better performance or memory use).

                                                      Interesting article, though. I’ve also been learning Rust a little bit lately because I want to start contributing to Spotifyd. More out of necessity than desire - I can’t listen to a full album without it crashing, but it’s the only way I’ve found to listen to Spotify on FreeBSD, so I might as well try to help fix it.