1. 44
  1.  

  2. 16

    I would not give up Result. To me there’s nothing “systems” about it. It bridges the two worlds of exceptions and return values.

    Typically exceptions are tied to the call graph, and can be handled only immediately, in their own scope. OTOH values are independent of the scope in which they were created, and can be handled anywhere at any time, moved, aggregated, copied, stored. Result gives that flexibility to error handling.

    It does make the language smaller, because there only needs to be one way to return from a function, not two.

    1. 5

      In languages with exceptions I always have trouble deciding when to use exceptions or return values, I really like rust’s way of doing things, it is really clear and the ? operator works well imo.

      1. 4

        Zig’s error strategy seems nice, there’s some details in here https://andrewkelley.me/post/intro-to-zig.html but the best description I’ve seen of it is in here https://www.youtube.com/watch?v=Gv2I7qTux7g

        1. 1

          I agree. In Swift (which has been in some ways inspired pretty heavily by Rust), some APIs use its exception system, some use Swift’s equivalent of Option, and now I believe a Result type has been introduced - not to mention having to deal with legacy Objective-C APIs with their own ways of signalling results.

          This is partly down to the fact that the APIs are inconsistent, which is fixable, but in comparison to Rust’s Result, I just find this situation so annoying. It bothers me every time I have to call a method that uses exceptions. I wish Swift had a consistent usage of a result type in the same way, and I don’t think it would feel particularly more low-level or “systems” in any way.

        2. 9

          I think much of this could be implemented in a “batteries included” library that has pervasive use of Arc<RefCell<Box<Any>>> or some such, spit balling here and/or embedded as a language within a macro.

          I think a model like

          where a high level dynamic language is interwoven with a low level counterpart. This could well serve Rust, so that complexity and control are opt-in in a gradual way. Or maybe more tooling around starting projects in Dyon/Gluon with smooth affordances to dropping down into Rust. Where Rust is seen as the low level, correct, high performance base layer and application code can be written in a higher level language.

          1. 6

            I don’t know if I would call what the author describes a “smaller Rust”, as much as “how would Rust look like if it wasn’t targeted at low level programming”.

            I would say Pony shares a lot of the characteristics outlined here (sans, maybe, production-ready, although probably the people at Wallaroo would disagree):

            • Both structural and nominal polymorphism.
            • Targets LLVM
            • Being garbage collected, sidesteps all gotchas with data location and storage.
            • Immutable data without overhead, by using capabilities (~ownership semantics) on pointers. Data might only be aliasable or mutable, but not both.
            • Error handling with error, which is the only exception allowed. ADTs can also be used to build Result and Option types.
            1. 5

              See, everyone has a different thing they find important about Rust. He suggest abandoning zero cost abstractions (letting stack/inline allocation be decided by the compiler instead) which I think would remove most of the power of the language. Default thread safe primitives sounds really wasteful too.

              I think languages similar to Rust but with less complexity will be a very cool space to watch going forward. All sorts of interesting language designs possible.

              I’m working on a language that does “Rust-like” things, but unlike the article, what I am going for is the efficient memory management, in this case the inline structs (zero cost abstraction) and compile time memory management (automatic lifetime analysis). The biggest difference with Rust is that it is fully automatic: when ownership can’t be determined at compile time, by defaults it falls back to a reference count increase at runtime (in Rust this would just be an error). The advantage is zero annotations, and a language that can be used mostly by people that don’t even understand ownership. There may be ways to explicitly (optionally) enforce ownership in the future, for those who want more control.

              Language: http://strlen.com/lobster/ Details on memory management: http://aardappel.github.io/lobster/memory_management.html

              1. 4

                Nice article, but if you have real threads already (and so can escape the horrors of async/callback-style programming), I think the benefits of an additional green thread system are dwarfed by the complexity introduced.

                1. 5

                  Interesting article, because I also tend to think that there is a smaller, better language inside Rust that’s struggling to emerge that can be reached without messing with the things that make Rust Rust.

                  Having both “product types” (in Rust structs) and “sum types” (in Rust enums) is crucial.

                  True, but having two different syntactic variations for enums isn’t.

                  Also:

                  • Get rid of all special syntax involving []: Drop special syntax for arrays and slices.
                  • Get rid of all special syntax for ranges.
                  • Get rid of mandatory semicola to end lines.
                  • Fix the inconsistent casing of type names.
                  • Get rid of casts that are not casts but conversions. E. g. int ⟷ float casts.
                  • Make everything that takes arguments consistent: structs, enums, functions. Get rid of all the special cases.
                  • Replace <> in generics with [].
                  • Clean up the naming in the standard library.
                  • Deal with the library stutter, e. g. foo::bar::Bar
                  • Fix the broken Eq/PartialEq and Ord/PartialOrd hierarchies.
                  • Replace macro invocations that emulate varargs with first-class varargs.
                  1. 1

                    Generics also take arguments. Shouldn’t they be consistent with structs, enums, functions?

                    1. 1

                      Let me change “arguments” to “term arguments” in the text above. :-)

                      There is a large difference between type parameters/arguments and term parameters/arguments (semantically and from a usage POV)¹, but little to no distinction between term parameters/arguments for structs, enums and functions.

                      So one syntax for type parameters, one syntax for term parameters makes a lot of sense to me. (If you go into the direction of dependently typed languages, this equation changes substantially of course.)

                      ¹ positional/named, defaulted, variadic etc.

                  2. 3

                    This looks like they are describing Nim.

                    1. 3

                      I see the ask as Linear ML, which is largely what I think of Rust being to begin with… :)

                      1. 1

                        Araq’s write-up makes me think they’re going in a different direction than Rust’s foundation. I don’t track it closely, though.

                      2. 1

                        I would be careful to design and implement the compiler so that it could be embedded in different runtimes, and I would have two primary targets: an LLVM based one creating a standalone binary on the mainstream UNIX and windows OSes, and a WASM target that would be intended to use the host VM’s runtime for threads, garbage collection, and so on.

                        Instead of having this language target LLVM and WASM, why don’t we have the language target something that compiles to both of these: Rust!

                        I love the ideas that this article brings about what can stay in and what can go, but (almost, see below) all of the features they propose can be implemented as a subset or syntactic sugar upon Rust. So why not create a simplified DSL that compiles to Rust. We can get rid of some complexity, leverage all the work that Mozilla has put into a more friendly compiler frontend, and get both of our compiler targets for free.

                        The one thing that we can’t get from this is garbage collection, but I don’t like garbage collection, and this is my rant, so I would say we keep the lack of GC ;)

                        1. 1

                          The one thing that we can’t get from this is garbage collection, but I don’t like garbage collection, and this is my rant, so I would say we keep the lack of GC ;)

                          It’s absolutely possible to write a garbage-collecting runtime in Rust, so no reason to give up on that requirement (aside from you not liking it :) ).

                          1. 1

                            I feel like it would add a significant amount of complexity to the language, especially since if we’re generating Rust we by default shouldn’t need a GC. Plus, I like the idea of the language not having a runtime, but that’s more from my personal struggles of trying to write OS code in Go and being stung by a complex runtime I had to implement first.

                          2. 1

                            Instead of having this language target LLVM and WASM, why don’t we have the language target something that compiles to both of these: Rust!

                            Wouldn’t the compilation overhead of Rust be a bit of a burden? (Time-wise)

                            1. 2

                              You could compile straight to MIR to shave a bit of compilation time off.

                              1. 3

                                Raw MIR doesn’t have things like privacy checking, type inference, or a stable source representation. I’m not even sure that’s it’s really memory-safe without all the up-front checking that rustc performs on the HIR. You’d be better off compiling to C.

                          3. 1

                            I’ve personally been thinking about this in terms of how a language could serve as the interface for a Rust based operating - a sort of shell rust.

                            1. 0

                              …. so, safe D then?

                              1. 1

                                Does safe D have lifetimes?

                                1. 0

                                  Partially, with scope vars and RAII but it seems a more solid own/borrow semantics will be available soon https://dlang.org/blog/2019/07/15/ownership-and-borrowing-in-d/

                              2. -3

                                basically go

                                1. 26

                                  Uh…except that Go has zero of the three “necessary components” called for.

                                2. [Comment removed by author]

                                  1. 6

                                    So let me get this straight. You’re saying Cargo isn’t great purely because you have to edit a file to add your dependency? Seems like one of the most minor issues you could possibly point out.

                                    1. 3

                                      Sorry, I don’t understand what you mean, though I confess I haven’t done more than play with all the languages listed. But if you want to update packages in a project, cargo update will get the latest compatible ones, following semver. And if you don’t want to follow semver you specify * for the target version.

                                      If this isn’t what you’re talking about and you just want to manipulate deps without opening a text editor, the cargo-edit plugin discussed in the issue you linked seems to just do this. …actually that looks pretty nice. I should try it out.