1. 69
    1. 24

      What if we were making a language like Rust, but one that was meant to feel more like Java or JavaScript, and less like C++?

      Please ping me when anyone makes Merz, a language like Rust that feels like Lisp.

      1. 61

        I want a language with the memory management of C, the standard library of C++, the syntax of Rust, the performance of Python, the ecosystem of Haskell, the portability of .NET, the multithreading of JavaScript, the object oriented programming of Java, the naming conventions of PowerShell, the enums of Go and the error handling of bash ;-)

        1. 9

          I had a nice chuckle, but it’s worth noting that .NET’s portability story is pretty solid these days, Java’s OO has gotten far less verbose (you can even now have main right in the root of the file), PowerShell’s naming convention is absolutely verbose but honestly highly consistent, C++‘s stdlib has gotten fairly robust in recent releases, and JavaScript has had shared memory and Web Workers if you’re in the mood for some solid preemptively multithreaded foot-guns. Python’s speed and Haskell’s ecosystem, I can’t help you with, but the rest…you might not have made quite the Malbolge competitor you were aiming for.

          1. 3

            I have to use Java at work, and I agree that Java is decent these days. Lambdas, pattern matching, record types (less verbose than Python data classes), etc.

            But all the popular libraries and frameworks are still the same, more or less. Maybe I could say: the language has improved, the culture is the same.

            At my previous job, they used .NET, and while it’s supposed to be cross-platform these days, in practice it wasn’t really. The open source compiler/toolchain seemed to be a different one than what coworkers used on Windows, and they didn’t have feature-parity. I think some kind of “resource files” didn’t work. Maybe they fixed that in the last 3 years.

          2. 1

            aww, you forgot erlang in the list there. that makes me sad.

            1. 6

              They’re naming bad things about each language, so Erlang can’t be in the list.

            1. 1

              Hm interesting, why didn’t this become a thing? It’s from 1992

              It has 116 citations according to Google - https://scholar.google.com/scholar?cites=16067430993533829385&as_sdt=5,39&sciodt=0,39&hl=en

              A few Hacker News discussions: https://news.ycombinator.com/item?id=32384320

              Lobsters: https://lobste.rs/s/mysxrz/lively_linear_lisp_look_ma_no_garbage_1992

              I don’t really see any good comments about how it works.

              I guess there is no code to go with the paper, so we can’t really know

              1. 1

                The appendix has a meta circular interpreter in common lisp, but yeah, no example programs.

                It’s hard to evaluate its practicality, from the paper alone, but I’ve considered writing a small Linear Lisp interpreter with Erlang like semantics. So, single assignment, destructuring, no strings, just lists of bytes… etc. The thing is, the only thing to gain from this is no GC, since Erlang semantics are already great for parallelism. But, Erlang’s basic GC from the 90s was stupidly simple and quite good… so, does this even matter? Not clear.

              2. 1

                Introduction

                Neither a borrower nor a lender be;

                For loan oft loses both itself and friend …

                [Shakespeare, Hamlet, I. iii 75]

                Polonius, you? :)

              3. 9

                Carp? https://github.com/carp-lang/Carp

                I haven’t used it

                But I actually am feeling the need for a “Lispy IR for C++”

                I had sort of a “revelation” that Lisp has the “best” language for metaprogramming (or at least most flexible), but it doesn’t have the best target runtime for metaprogramming.

                For example, there is no Lisp runtime that lets you express value types like C++ or Rust. You have JITs that maybe do that (?), but JITs often fall off cliffs.

                You can’t really lay out memory yourself and make it simple and AOT.


                The best target runtime for metaprogramming should be capable of expressing fast code.

                So then I was wondering if that was what Carp is – probably a little bit.

                Or actually I think Clasp is much closer, it is metaprogramming LLVM with Common Lisp

                https://www.youtube.com/watch?v=8X69_42Mj-g

                Although there is a lot of intermingling of the two languages and of the GC, which may not be exactly what I want

                1. 6

                  Please ping me when anyone makes Merz, a language like Rust that feels like Lisp.

                  Sign me up as well. There’s https://jank-lang.org/ that uses LLVM-based JITting C++ interpreter as a “host” language analogously to how Clojure uses Java.

                  1. [Comment removed by author]

                  2. 2

                    I miss experimenting in Carp, the speed, expressiveness, and interoperability made me comfortable and productive in a way that wasn’t apparent just by reading the landing page, arch decisions, etc.

                    1. 1

                      Does it compare well against Chicken? If I’m going to learn just one lisp targeting lower level stuff than clojure… Or fennel…

                      1. 1

                        Haven’t tried chicken! Used fennel for a bit, but not enough to make a good comparison.

                2. 12

                  object-oriented

                  Possibly the only thing that could get me to root against it; Rust being a procedural language and getting widespread adoption is very slowly starting to break the ‘multi-paradigm language supporting both object-oriented and functional programming styles’ enterprise monoculture, for the better. There are many aspects of Rust that should disappear in a higher-level language, but the roadblocks against object-orientation are not one of them IMO.

                  1. 4

                    I’m confused what you mean by this.

                    Rust is a multi paradigm language as well, so I don’t see how it breaks anything. It contains object oriented and functional paradigms.

                    I think there tends to be a conflation with object orientation and inheritance. They are not synonymous. Rust still has object oriented behavior and shares functionally through its trait system. Dada likely is doing the same thing. They don’t mean they’re going all in on inheritance.

                    1. 6

                      Rust is not object oriented; object orientation and polymorphism are not synonymous either. A hundred little things, from universal function call syntax all the way down to impl being a separate block from struct, communicate the sharp distinction between state and behavior in idiomatic code. Nor is it functional, nor are any of the so-called multi-paradigm languages; ‘having good iterators’ is confused for ‘functional programming’ within the monoculture, and object oriented programmers use those languages but functional programmers do not. If these ideas sound unfamiliar I recommend this article.

                      1. 6

                        Rust is not object oriented; object orientation and polymorphism are not synonymous either. A hundred little things, from universal function call syntax all the way down to impl being a separate block from struct, communicate the sharp distinction between state and behavior in idiomatic code.

                        Common Lisp’s CLOS is very OO-y, and its “generic functions” are completely separated from classes. All you really need for OOP is bundles of data and late binding for things that operate on such bundles. In something like C, you’d need to implement this yourself, so obviously C is not an “OOP language”. Rust however, with the dyn keyword, has late binding built into the language. So while most Rust code is very OO at all, Rust does make it very easy to write non-inheritance style OO code.

                        1. 1

                          For a given value of ‘easy’. Trait objects are indeed objects, but subject you to a rather large number of restrictions - no generic methods, no non-methods, no unknown associated types, no Self, and an ever-present hidden lifetime parameter. (The other common neutral use case for objects is I/O.)

                          1. 1

                            no generic methods, no non-methods, no unknown associated types, no Self

                            Could you elaborate on these?

                            1. 1

                              I’m not sure what there is to elaborate on. You can’t do them with trait objects.

                              1. 1

                                If a trait has any of these, it becomes not-object-safe, meaning you can’t create a trait object from it. The fundamental reason for this is that you must be able to put the trait’s methods into a vtable to turn it into an object.

                          2. 2

                            Rust certainly supports an OO style. You can still write dog.bark(). The only thing it discourages is inheritance.

                            1. 4

                              If object-oriented style means, to you, choosing the syntax foo.bar() instead of foo |> bar(), then you could describe Rust as supporting object-oriented style if you wanted to. This has nothing to do with whether Rust supports object-orientation, a design paradigm around abstract entities which conceptually have agency, which among other things presumes shared mutability, which Rust does not support and requires lots of boilerplate to work around.

                              1. 1

                                which among other things presumes shared mutability, which Rust does not support and requires lots of boilerplate to work around.

                                Does Rust it not support it, or does it only support it with lots of boilerplate (and to what extent can that boilerplate be macro’d away if you design things to share a lifetime)?

                          3. 3

                            I think there tends to be a conflation with object orientation and data abstraction. IMO not every programming language with data abstraction and dynamic dispatch is object oriented.

                            Object oriented programming became popular in the 1980’s because of Smalltalk, and the GUI. Suddenly everyone wanted to write GUIs, and Smalltalk provided the initial idioms (MVC or model view controller) for a GUI framework, and these idioms required an object oriented language. Rust has a big problem with GUIs because convention OO GUI idioms don’t work in Rust. Inheritance isn’t the most fundamental concept in an OOP language: that would be objects. An OOP program consists of a network of objects that send messages to each other, and mutate themselves in response to messages. Each object contains references to the other objects that it is related to. These networks of mutable objects typically form a cyclic graph. You can’t program that way in safe Rust, so Rust GUIs can’t be written in an OO style.

                            1. 1

                              These networks of mutable objects typically form a cyclic graph. You can’t program that way in safe Rust, so Rust GUIs can’t be written in an OO style.

                              Just wrap everything in Rc<Mutex<>> !

                                1. 2

                                  It does give you cycles, it just doesn’t prevent memory leaks if you accidentally drop every reference into a cycle. Though, my suggestion was tongue in cheek. Probably for Rust-y OOP you’d want to avoid cycles.

                              1. [Comment removed by author]

                            2. 1

                              I totally agree. I don’t miss OOP at all in Rust, Go, or Zig.

                            3. 5

                              Is this made by Graydon Hoare then?

                                1. 9

                                  On the Github page the top contributors are listed as nikomatsakis and brson. So, no, but arguably at least as influential.

                                  1. 6

                                    I note that I don’t see the words “creators of Rust” on the linked page. Niko Matsakis and, before him, Brian Anderson have been central figures in the Rust leadership after Hoare stepped away, and I guess I can imagine an argument for their having created Rust as it is now, but I think it’s confusing to call either of them a creator of Rust.

                                  2. 4

                                    I’m reading through the tutorial and it’s quite interesting — the ownership model is unlike anything I’ve seen before. (Very relieved to see first class support for shared ownership!)

                                    1. 3

                                      Dada doesn’t really exist

                                      Awww. I think a humane but powerful language that targets web assembly directly would be really nice to have.

                                      1. 2

                                        Slightly confused about this statement, from their “about” page:

                                        That means you can start out using Dada in the interpreter, with no type annotations, to get a feel for how it works.

                                        What does interpretation have to do with it? Did they neglect to implement the full semantics of the language in their compiler?

                                        1. 4

                                          They follow it up with “Once you’ve gotten comfortable with it, you can add type annotations and use the compiler for performance comparable to Rust.”, so I hope it’s just “We have a REPL”.

                                          After all, syntax hostile to gradual typing aside, writing an interpreted C has been a programming exercise that has shown up in various books over the years.

                                          1. 4

                                            I hope it will have a strict mode where you cannot compile without types.

                                            A project I’m working on is doing a massive Python 2 to Python 3 migration, and the lack of compile-time type checking is really hurting reliability. Seemingly correct changes end up breaking the code all the time, and although we’ve been adding all the gradual typing that python has (mypy, pytest) it still fails to detect all type mismatches in the CI (e.g. code that worked correctly with Python ctypes in Python2 now breaks in python3 and none of the tools warn about it, etc.) We’ve spent so much time trying to convince ourselves that the changes are correct (after master got broken several times due to insufficient testing) that we might as well have rewritten in another language that can be compiled and has a strict type system.

                                            Gradual typing is definitely better than no typing information at all, but is strictly inferior to having a compiled language. Especially that Dada advertised itself ‘like Java’, I think it needs to have a proper strict type checking mode. (It is fine if in addition it has a mode where you can use a repl and do runtime type checking instead, as long as it is not the only mode)

                                            1. 2

                                              see if running pytype in addition to mypy is any help (disclaimer - i work on it). we have a different analysis model and sometimes do catch things mypy does not (and vice versa; not claiming pytype is strictly better, just that it might catch some additional things)

                                              in particular, pytype focuses on type inference for unannotated code, so if your python2 code lacks annotations it will likely be helpful. a massive python2 to 3 migration was one of the motivations behind google’s developing it in the first place.

                                              1. 2

                                                Thanks, I meant to write pytype instead of pytest (we do use pytest, mypy and pytype). It did find some extra bugs compared to mypy: https://github.com/xapi-project/xen-api/pull/5365 https://github.com/xapi-project/xen-api/pull/5384/commits/dae3d61ae9c287be7ae48043527ee8c3608b2c86

                                              2. 1

                                                *chuckle* No need to convince me. I came to Rust from Python and the lack of a Django Ecosystem, a Django ORM/SQLAlchemy+Alembic-level database abstraction, and safe QWidget bindings has me still using Python for various niches with all the MyPy strictness and static analysis I can find.

                                          2. 2

                                            I look forward to seeing this evolve. Hard to say if it’ll be good or not, but it’ll certainly be intriguing.

                                            1. 1

                                              OO is very readable and easy for non-fulltime engineers, like scientists, to abstract their problems they want to solve. So dada going OO and potentially solving the thread safety and other issues, without garbage collector (performance hit) or without full-blown, complex borrow checking semantics and (cognitive overload), is compelling.

                                              That said, CHERIot, stands to make it not absolutely critical to use a memory safe language when reaching for performance.

                                              1. 2

                                                That said, CHERIot, stands to make it not absolutely critical to use a memory safe language when reaching for performance.

                                                Similarly, targetting WASM (which seems to be a thing for dada) is another way to make using a memory-unsafe language more feasible. (Depending on how much performancy you need - WASM is fast like Go compared to Python, but slightly slower than optimized & native compiled C/C++/Rust/Julia/etc)

                                                1. 2

                                                  Similarly, targetting WASM (which seems to be a thing for dada) is another way to make using a memory-unsafe language more feasible.

                                                  Disagree. WASM prevents memory violations from affecting anything outside the sandbox, but different parts of a program running in the same sandbox can affect each other.

                                                  1. 1

                                                    Overlooked that. Good to know.

                                                2. 1

                                                  Kinda reminds me of https://www.ponylang.io/ with using capabilities for variables instead of lifetimes.

                                                  Though AFAIR Pony has garbage collection and its capability system isn’t aimed at memory safety, but is aimed only at preventing data races.

                                                  I wonder if Dada type system is more powerful than Rust and Pony’s in terms of expressiveness.