Settings

Theme

Show HN: Alumina Programming Language

github.com

107 points by tibordp 3 years ago · 89 comments (88 loaded) · 1 min read

Reader

Alumina is a programming language I have been working on for a while. Alumina may be for you if you like the control that C gives you but miss goodies from higher level programming languages.

It is mostly for fun and exercise in language design, I don't have any grand aspirations for it. It is however, by this time, a usable general-purpose language.

Alumina borrows (zing) heavily from Rust, except for its raison d'être (memory safety). Syntax is a blatant rip-off of Rust, but so is the standard library scope and structure.

Alumina bootstrap compiler currently compiles to ugly C, but a self-hosted compiler is early stages that will target LLVM as backend.

If that sounds interesting, give it a try. I appreciate any feedback!

Standard library documentation: https://docs.alumina-lang.net/

Online compiler playground: https://play.alumina-lang.net/

MontyCarloHall 3 years ago

I get that this is mostly for fun, but this is as good a place as any to bring up an issue I rarely see discussed with any post about a new language.

Well-established languages have tons of widely used, highly vetted libraries implementing functionality that doesn’t exist in the new language and would be totally impractical for an individual to implement themselves. For example, if I’m doing scientific computing, I need a good linear algebra library like Eigen or Armadillo (or Numpy/PyTorch/Tensorflow), all of which would be impossible for me to implement myself.

Therefore, for a new language to catch on, it needs a good foreign function interface. Yet FFIs are almost never brought up whenever new languages are discussed on HN. (Again, I realize that this is just a fun project and widespread adoption is not a goal.)

  • belmarca 3 years ago

    We've been investigating coupling syntactic and low-level FFIs [1]. Our most recent work will be published at the upcoming Scheme Workshop [2], where we integrate Gambit Scheme with CPython. We share the concerns you have and have had quite good success with the Scheme<->Python interface! The syntactic interface makes it really enjoyable.

    [1]: https://zenodo.org/record/4711425

    [2]: The paper should be up in a few days I suppose.

  • tibordpOP 3 years ago

    Totally agreed about FFI. I wanted to make it easy to interop with C code and write expressive bindings.

    Check for example the language bindings to LLVM's C API (fairly low level) and Tree-Sitter which is used internally (a bit higher level bindings)

    https://github.com/tibordp/alumina/tree/master/libraries/llv...

    https://github.com/tibordp/alumina/blob/master/libraries/tre...

    I think UFCS makes it quite nice for bindings, since external C functions can be used as if they were methods if the object is passed as the first parameter. So in many cases there might not even be a need to write wrapper structs for bindings that feel native.

    Of course, it's still a manual process and since Alumina is just a compiler and stdlib for now (no llibrary ecosystem, no compiler driver), it's a bit cumbersome. But I like the approach Rust has with bindgen and cc crates, to automatically create bindings for C and C++ code.

    • girvo 3 years ago

      UFCS making C bindings a hell of a lot nicer is one of the things I love about Nim, so I’m happy to see another language try it!

  • danias 3 years ago

    We are building a new language that is not for fun and we have thought of this important issue. We solve it with a Package Ports and Package Adapters. The Bitloops Language (BL) is a transpiled language with support for only TypeScript at the moment. Nonetheless, if it picks up we will be adding support for Java, C#, and C++ so that people can leverage their investments in their existing packages.

    https://github.com/bitloops/bitloops-language

  • culi 3 years ago

    What's an example of a language with "good" FFI?

    • beagle3 3 years ago

      LuaJIT has a pretty great FFi which was later ported to standard Lua; Python’s ctypes provides a decent FFI.

      Nim, Zig and Rust do too, but they have semantics much closer to C, so it’s almost free (especially when they can all use llvm directly for code generation, and Nim’s preferred way is to compile through C in the first place)

    • WalterBright 3 years ago

      With the D programming language, to interface with C's stdio.h:

          import stdio;
      
          void main() { printf("hello from D!\n"); }
      
      is all that's necessary, as D has a built-in C compiler that reads stdio.h, compiles it, and presents its interface to the D code.
      • cercatrova 3 years ago

        I hear about D often on HN but I never see it being used in the wild so to speak. When I looked at it, it seemed, like C++, a hodgepodge of features built up over time rather than being a more deliberately focused language.

        I hate to compare and contrast but Rust comes to mind as one of the latter, probably because it has a somewhat more intensive and extensive RFC process for adding new features.

        • WalterBright 3 years ago

          D has made its mistakes (there's no way to evolve a language over 20 years and not make a mistake here and there), but we also have a deprecation process to remove them.

          The people who use D tend to like it very much.

      • andrewmcwatters 3 years ago

        This is even more impressive than LuaJIT's FFI in my opinion, which I previously thought was state of the art. You basically pass in a preprocessed header, and LuaJIT does the rest.

        All this to say, I feel that any FFI that requires you to manually write bindings is rubbish.

        • WalterBright 3 years ago

          We lived with manual bindings to interface with C for years. Building in direct support for C itself is a huge leap forward in usability. In several ways it's even better than C++'s support for C.

          • girvo 3 years ago

            How does it deal with the macro-in-macro-in-macro soup that a non trivial amount of headers are? c2nim does a decent job but struggles with some of those types. gcc -E on the header works around it, so I wonder if c2nim could be made to operate similarly to what you’re describing.

    • williamstein 3 years ago

      Calling C functions from zig is very nice, partly because zig uses llvm to parse C header files and uses that information.

    • zyx_tony 3 years ago

      Nim is quite enjoyable to use. I do a decent amount of scientific computing, interfacing with various c/cpp libs

    • davedx 3 years ago

      Rust's seems pretty good. I've been doing some Rust/C interop and it works very smoothly

  • aliqot 3 years ago

    Libraries are a farce. Stdlib or die. I 100% mean this and live this.

    • Asraelite 3 years ago

      That's a strange take. Do you mean that you would rather call external binaries directly, like Bash does, or that you would rather re-implement all functionality you need, however complex?

      • aliqot 3 years ago

        To me, there is value in the process and craft. It started as a one year challenge to use only stdlib in all projects, for work and personal code, and became a way of life. Though it may not work for everyone, or all languages, or all skillsets, it was a revealing experience.

        In retrospect, it made sense given that in my community we make our own furniture, instruments, tools, foods from whole items. Code seemed like the next logical step. During travels, once there was a man who had a word in his language for this. He said it was an aphorism loosely translatable to "the beauty of struggle". As he explained it, this is the positive benefit gained in return for the time and effort to do something as an act of appreciation of the craft, and how the value in the experience surpasses the debt of time and sweat.

        To put it in a more modern and eastern philosphical context, think of it like Kata.

        https://en.wikipedia.org/wiki/Kata

        • Art9681 3 years ago

          I too suffer from obessively overcoming challenges. I will say this, in a snarky and friendly way. I hope you understand.

          If developing with high level abstractions wasn't challenging enough, your vision was too small. Surely you can think of a problem to solve that even Copilot would be of little use.

          Imagine what you could build if you got a little more help from third party libs and a little more ambition?

        • whartung 3 years ago

          I can certainly identify with this.

          Having done enterprise java for so long, I strive to be as reductionist and minimalist as I can be in order to avoid dependencies outside the JDK.

          Vying for "you aren't going to need it", trying to keep things as simple as I can.

          But it also comes down to not overcomplicating stuff we've already written.

          Obviously there's an urge to reuse your own libraries, but you have to strive to not overcomplicate them as they're applied to new use cases as you drive the peg in to a rounder hole.

          It's very easy to FactoryFactoryFactory in Java, but flexibility and configurability leads to complexity and black hole of combinatorial testing.

          Almost better to fork the earlier library and hammer it to fit the new space without regard to its old use in the other system. But that leads to file replication (notably files of the same name doing subtly different things). And there it's a challenge to go "gee which one should I use" when you're working on version 3, when what should be happening is "pick the best one" and keep hammering.

          We used to have our general purpose "catch all" library which, in the end, indeed, "caught all". "Oh look, somehow I have jars from Clojure, Groovy and Scala, when all I wanted was a URL Builder."

        • pengaru 3 years ago

          That's a whole lot of words for describing NIH syndrome [0].

          But sure, yeah, there's value in practicing your craft and making all the things.

          [0] https://en.wikipedia.org/wiki/Not_invented_here

    • mypalmike 3 years ago

      Why even use stdlib? Or an OS? Just write everything every time down to the bare metal.

    • thesuperbigfrog 3 years ago

      Libraries are how software is shared and reused.

      Do you really intend to write your own library for a given task when there is a perfectly good and mature library that does that task and more freely available?

      How long would it take for you to write your own Sqlite or your own Nginx?

    • tyingq 3 years ago

      Would that include things like encryption? No exceptions for your rule?

      • still_grokking 3 years ago

        The parent will never "need" something as "complicated" as encryption as you can't write anyway any serous software with the stated mindset.

        The whole point of modern tech and science is that everybody is standing on the shoulders of giants. Without that all you probably can get at max is low tech form 200 hundred years ago…

mhd 3 years ago

I thought people got along with Rust due to its features and semantics and learned to live with the syntax. Not it being something one would copy. (I'm personally still hoping for a Ratfor/Coffeescript transpiler)

Also, wonder how long it'll take until we see a "Aluminia" fork...

  • jimbob45 3 years ago

    What is it that people hate about Rust syntax beyond the terrible lifetime syntax? Seems pretty reasonable to me.

    • still_grokking 3 years ago

      Rust's syntax is just baroque.

      It's full of unnecessary noise and additionally very irregular. (With complete craziness thrown in between like the semicolon rule to "visually distinguish" procedures and functions, which must be a kind of joke I don't get).

      I really don't understand how such a conceptionally well thought out language got this pretty ugly syntax.

      (And no, you don't need such ugly syntax "because language features". Just have a look at Scala 3 that is much more powerful but maintains a clean, almost pythonic syntax).

      • Syzygies 3 years ago

        Rust is a fly-pollinated flower. Without garbage collection, it needs flies.

        Rust is in part designed to look familiar to C programmers. Rob Pike once famously described C syntax as able to survive a channel that mangled whitespace. That's less of an issue now, but habits die hard. Indentation in place of syntax is nevertheless controversial. That's a toy version of the bigger question: Why should text be required to carry a load that a smart editor can infer? In Clojure, some prefer ;; to ; because the comments stand out better. Um, syntax coloring? I dislike all comment characters, and for many years I preprocessed a practical version of "comments are flush, code is indented".

        Ownership is nevertheless pure genius, and one can define more powerful operations on Rust's restricted notion of data than on general data. I'm imagining a "lisp without parentheses" that transpiles monadic parsers on steroids (aimed exactly at Rust data) to Rust. It will take me a while.

        • kazinator 3 years ago

          > Rust is in part designed to look familiar to C programmers.

          Rust may be accompanied by a design statement like that somewhere, but it actually does no such thing.

          • Syzygies 3 years ago

            I'm sure you're right. Rust is a popular language in Haskell user surveys, as it's not such a stretch coming from Haskell.

            The majority of the lines I've ever written were in C. When I look at Rust, all I see is `{};`

      • brundolf 3 years ago

        I love the semicolon rule, I think that distinction is extremely important and too often gets muddled

        (though in Rust's case I think it's more accurate to say it distinguishes between "statements and expressions" than "procedures and functions")

        • still_grokking 3 years ago

          > I love the semicolon rule, I think that distinction is extremely important and too often gets muddled

          Yes, the distinction is important. That's why it's extremely annoying that this distinction is almost invisible if you don't look very close on the code using magnifying glasses. Like I said: Marking such an important distinction through something almost invisible like a (missing) semicolon is pure craziness.

          Usually nobody reads semicolons! They are usually just line noise coming form a time as parsing code was actually still some kind of science and people made syntax with the explicit intent to be easy readable by archaic computers (and not humans in the first place).

          I think `return`s are superfluous but given the choice between some more line noise in the form of a `return` statement and this semicolon brain-fart I would clearly prefer the `return`…

          > (though in Rust's case I think it's more accurate to say it distinguishes between "statements and expressions" than "procedures and functions")

          Since when? Did I miss something? (This could be, I'm looking only occasionally into Rust).

          AFAIK leaving out the semicolon is only an option on the last expression of a procedure, turning that "procedure" into a function.

          Leaving out (the completely unnecessary!) semicolons elsewhere is a syntax error to my best knowledge.

            fn main() {
                let baz = if false {"bar"} else {"foo"}
                println!("Hello, {baz}!", baz = baz);
            }
          
          The above code would not compile, afaik, because the semicolon is missing on the first line of the procedure.

          The completely unnecessary semicolons are just one of the examples that make the Rust syntax heavyweight and needless noisy for no good reason. I don't get how a modern language can fall back to such antique syntax.

          The very rare use-case where you really want to write some comprehensive one-liner could have been easy supported by optional semicolons. But in the general case one just doesn't need that line noise.

          Rust is a great language, really! But they obviously didn't put any effort into the syntax. The result is that the language reads partly like C++, and I guess almost everybody could agree that C++ has one of the most terrible syntax out there.

          Rust is "modern" language with a stone age look & feel. That's a big missed opportunity, imho.

          • brundolf 3 years ago

            > they obviously didn't put any effort into the syntax

            This is an incredibly arrogant and ignorant statement to make, especially for someone who self-describes as "looking only occasionally into Rust". A whole lot of thought has been put into Rust's syntax.

            > The result is that the language reads partly like C++

            My impression is that a certain amount of this was intentional; if their goal is to attract C++ developers, they can't scare them off with syntax that's wildly alien. Rust took the parts of C++ syntax that made sense to keep and that fit into Rust's semantics, refined/modernized/distilled them, sanded off the rough edges and ambiguities, and presented something cohesive that's still familiar.

            The syntax isn't without warts - turbofish comes to mind - but overall I find it pleasant and comfy (and I'm not even a C++ developer). I appreciate that it makes a lot of things explicit that should be explicit. Fewer characters doesn't automatically mean better readability; in many cases it can mean the opposite.

            • still_grokking 3 years ago

              >> they obviously didn't put any effort into the syntax

              > This is an incredibly arrogant and ignorant statement to make, especially for someone who self-describes as "looking only occasionally into Rust".

              There is nothing arrogant or especially ignorant about my statement.

              I'm primary using a language that has a shitload more features than Rust but gets along with a fraction of syntax.

              So from my standpoint this is clearly something to criticize Rust for.

              And this is very sad imho as I think Rust is a great language as such. A great language with a miserable syntax!

              That's especially unfortunate as there are today no technical reasons to make ugly languages given how fast our computers are.

              > A whole lot of thought has been put into Rust's syntax.

              Who knows, maybe you're even right, idk.

              But at least the result does not show, and that's the only relevant part.

              > My impression is that a certain amount of this was intentional; if their goal is to attract C++ developers, they can't scare them off with syntax that's wildly alien.

              That's imho nonsense. You can't "scare" C++ developers with syntax. They already endure one of the most broken syntaxes out there.

              One does not use C++ because of its syntax, but in spite of that monstrosity!

              One endures it as the language has other until lately unmatched properties. But C++'s look & feel is just a horrible historical accident all in all.

              Rust would be attractive for its features no mater the syntax.

              As we see it gets hyped and does very well for a newcomer even it's overly and needlessly ugly.

              > Fewer characters doesn't automatically mean better readability; in many cases it can mean the opposite.

              Sure.

              But it's Rust that uses almost every ASCII char for some special purposes; imitating by doing so one or two of the worst examples history ever created.

              The other thing is: Putting outright line noise everywhere only because that makes reading the code simpler for the machine is just the completely wrong priority. Less line noise makes reading code definitely simpler for humans. It has reasons why math notation looks like it looks after hundreds of years of optimization…

              The whole point of good syntax is that you can mostly ignore the syntax and concentrate on the message. But Rust is like C++, you can often hardly see the actual content as it's burrowed under a pile of ugly needless syntax noise.

              Copying a bad example is definitely nothing to be proud of. Rust failed in that regard miserably, imho. For completely incomprehensible reasons—which make it especially bad.

              It's a real pity such a great language looks like a archaic accident!

          • Quekid5 3 years ago

            > But they obviously didn't put any effort into the syntax.

            Ackshually moment here, but they did put a lot of effort into chosing syntax which would require very little look-ahead on the part of the parser (given current or even decade+ old parser tech). I don't understand their reasons for doing so at all, but that's what they did.

            The result is... not very human-friendly IMO.

            • still_grokking 3 years ago

              Exactly my point. This syntax was made for machines, not for humans. That's just not reasonable given how fast our computers are, and where the actual work for a modern compiler lies.

              But I don't get that either: Parsing is today the least problem. The time you spend parsing is negligible (if you didn't mess up the language completely, of course) compared to the time for type-checking and optimizations.

              Avoiding look-ahead (or especially the need to re-parse parts recursively) is a very good rule of thumb, sure. But when you need to decide whether you make the language simpler to read for the machine or more heavyweight for the human the answer should be absolute clear.

              A modern compiler spends anyway most of its time in the semantic analysis (and depending on language, later optimizing the output). Optimizing the lexical part for the win of a few milliseconds on tens of thousands of lines just makes no sense. Today's computers are even fast enough to parse spoken human language fast enough. Again it's the analysis that takes time there.

              The thing with Rust's syntax is especially annoying as almost everything else in that language makes a lot of sense. The concepts are neatly put together. It's explicit about the right things. It's considerably small and simple. It's almost a kind of sweet spot in language design, imho. And than it was hit hard with the ugly stick. That's a really sad point. And so needless.

              I still hope they will come to their mind some day, and will start to offer a kind of "light" syntax at some point.

              I really wish Rust could be more like Scala 3 on the outside, with a clean, minimal pythonic look & feel, and not like how someone put it before in a comment in this thread "When I look at Rust, all I see is `{};`". The later is also exactly my impression, sadly.

              • brundolf 3 years ago

                It’s not just about parser throughput, it also helps with giving better error messages (because the compiler can make better sense of partially-broken syntax), which is something the Rust team cares a whole lot about.

                • still_grokking 3 years ago

                  I don't buy that.

                  Good error messages and robust error recovery for syntax errors are possible for almost any kind of language, even very weird ones, with today's modern parser technology. Just have a look at what for example Tree-Sitter does.

                  But the meat of good programming language error messages lies not in the syntax errors. It's in meaningful and informative semantic error messages. And these are almost completely independent of the language's syntax.

                  • c-cube 3 years ago

                    Tree-sitter became somewhat popular after rust reached 1.0, as far as I can tell.

                    I personally find rust syntax pretty neat. It's designed to be unambiguous to machines, but that also means it's unambiguous to humans. It has no () around tests, but it mandates {} because that prevents goto fail. It has the classic ML `;` as a separator, not terminator. It's a pragmatic blend of C++ (with generics, namespacing, and the C influence), and ML (expression based, easy to parse, let-binding and type inference).

    • markusde 3 years ago

      Is lifetime syntax so terrible? Personally I like that all the subtyping relations are in the same place (lifetime outlives, polymorphism etc) and that they can be written inline until complicated enough to justify a ``where`` block.

    • xigoi 3 years ago

      Semicolons, braces, double colons

      Using "<" and ">" as both operators and delimiters

      Turbofish

      Symbols instead of words (ref -> &, and -> &&, not -> !, …)

      Inconsistency (Why [i64; 5] and not something like array<i64, 5>?)

    • aaaaaaaaaaab 3 years ago

      The community.

      • dhosek 3 years ago

        What I’ve found is that Rust people on stackoverflow not so great, Rust people on Reddit pretty pretty good.

  • IshKebab 3 years ago

    I assume he means the basic syntax like the fact that everything is an expression, `name: type` not requiring brackets for `if` and `for` etc. Most of the ugly Rust syntax is for advanced features like lifetimes and generics.

Surfactant7 3 years ago

> Unlike Rust, however, Alumina is not memory-safe and it requires manual memory management.

From what I gather, it might be more accurate to say that Alumina has no ownership model. Rust requires manual memory management, but offers the ownership model as a compile-time tool for doing so.

It would actually be pretty interesting to see some experimentation around alternative ownership models.

noncoml 3 years ago

I really don’t like the cognitive load of having to remember to use defer. We already have the scope defined, why add something extra?

IMHO the way it’s used in Go is a workaround, of luck of destructors, not a feature.

Edit: not a criticism on your language OP, which is better than what I could have ever built. Just a comment in the “defer” trend.

  • tibordpOP 3 years ago

    Scoped destruction is awesome in general, and I agree that it is superior to defer.

    I think one case where defer might be nicer is for things that are not strictly memory, e.g. inserting some element into a container and removing it after the function finishes (or setting a flag and restoring it).

    This can be done with a guard object in RAII languages, but it's a bit unintuitive. Defer makes it very clear what is going on.

    • noncoml 3 years ago

      > This can be done with a guard object in RAII languages, but it's a bit unintuitive

      Some syntactic sugar, like Python’s “with” should help with that, shouldn’t it?

      • tibordpOP 3 years ago

        Python context managers are actually very similar to guard objects in C++ and Rust.

        What I meant was something like this (could also be done with `contextlib`, but it's also verbose)

            seen_names = {}
        
            class EnsureUnique:
                def __init__(self, name: str):
                    self.name = name
                
                def __enter__(self):
                    if self.name in seen_names:
                        raise ValueError(f"Duplicate name: {self.name}")
                    seen_names.add(self.name)
        
                def __exit__(self, exc_type, exc_value, traceback):
                    seen_names.remove(self.name)
        
        
            def bar():
                with EnsureUnique("foo"):
                    do_something()
                    ...
        
        With defer this could be simplified to

            static seen_names: HashSet<&[u8]> = HashSet::new();
        
            fn bar() {
                if !seen_names.insert("foo") {
                    panic!("Duplicate name: foo")
                }
                defer seen_names.remove("foo");
        
                do_something();
            }
        • UncleEntity 3 years ago

          Honestly, the with example seems simpler if you ignore what it takes to build a context manager (which isn’t all that hard).

          Maybe it’s just I’ve never used defer before but I do use python with whenever I get a chance. Not like that, I don’t really understand what the code is trying to achieve by removing the name at the end, but to close resources at the end of the block. And even then only if it makes sense for what I’m doing.

          Using a context manager like your example is just busywork IMHO, easier to just write the code out linearly like the defer example.

          • tibordpOP 3 years ago

            It's not that it's hard, it's just that it is not inline, so it requires a context switch because the CM is defined outside, even when it's doing something specific.

            The most common problem that defer is trying to solve is cleanup when the function returns early (ususally because of an error). Writing the cleanup code inline before the early return results in code duplication.

            C#/Java/Javascript have try/finally for this, C has the "goto cleanup" idiom, and C++ and Rust have the guard objects. Go and Alumina have defer.

            • tzot 3 years ago

              There's `contextlib.closing` for objects that do not support the context manager protocol and they should be closed.

              And then one can simulate defer in the spirit of the `atexit` module with a single context manager (say `finalizer`), defined only once, which could be used as:

                  with finalizer() as defer:
                      ...
                      req = requests.get('https://w3.org/')
                      defer(req.close)  # just like contextlib.closing
                      ...
                      a_dict['key'] = value
                      defer(a_dict.__delitem__, 'key')
                      ...
                      defer(print, "all defers ran", file=sys.stderr)
                      ...
              
              The `__call__` of finalizer adds callables with their *args and **kwargs to a fifo or a stack, and its `__exit__` will call them in sequence.
  • leni536 3 years ago

    Except go's defer is scoped to the function, instead of the innermost enclosing scope.

    • tibordpOP 3 years ago

      That's a good point and also one of the things I kinda like about Alumina. You can do thing like this and the file will only be closed at the end of the function rather than the end of the if block.

          let stream: &dyn Writable<Self> = if output_filename.is_some() {
              let file = File::create(output_filename.unwrap())?
              defer file.close();
      
              file
          } else {
              &StdioStream::stdout()
          };
    • noncoml 3 years ago

      So less granular and can be assymetric. Don’t think that’s a good thing

  • girvo 3 years ago

    Despite Nim having RAII of a sort, one thing I love is “defer”, because it lets me get the same semantic behaviour from bound C functions. Handy!

Eliah_Lakhin 3 years ago

I'm currently working on a project similar to Tree-Sitter.

Basically, it is going to be a full-featured Compiler front-end foundation library with incremental parsing capabilities, error recovering, AST manipulations, etc, but written entirely in Rust, and hopefully with more user-friendly API for Rust devs.

May I ask you to give me some feedback on your experience with Tree Sitter, and the challenges you faced during the development of your compiler's front-end?

Thanks in advance!

  • tibordpOP 3 years ago

    Honestly, Tree Sitter is fantastic, I can highly recommend it. By far the most user friendly and powerful parser generator I've worked with. The C API is very nice.

    The only two pain point I had is that the `node-types.json` that's generated only contains the names of the nodes, not the numerical IDs. This means that if you have some codegen generating Rust enums is difficult if you want to avoid matching nodes by string.

    I wrote https://github.com/tibordp/tree-sitter-visitor for generating visitor traits in Rust for a given grammar. I actually did it a bit differently in the end for Alumina, but it might come useful.

ducktective 3 years ago

Awesome!

How difficult was it for you to design a whole programming language?

Do you have a theoretical CS background?

If I want to design my own, would learning Racket and other LISPs help?

I'm interested in formal methods and embedded systems.

  • tibordpOP 3 years ago

    I wouldn't say it was very difficult, but it did take quite a bit of time. Apart from some basic principles (no GC, no RAII, "everything is an expression"), I basically kept adding features whenever I hit some pain point trying to write actual programs in Alumina. If I were to do it again, I'd probably be more methodical, but anyway, here we are :)

    Protocols were probably the trickiest feature of the language to figure out. As for the compiler itself, surprisingly, the biggest hurdle to get over was the name resolution. It's a tiny part of the compiler today, but everything else was much more straightforward.

    I don't have formal CS background, but I have been coding for a long time. I read the Dragon Book and would recommend it to anyone writing a compiler, even though it's a bit dated.

    I don't know Racket or LISP myself so I cannot comment on that part.

chaosprint 3 years ago

Online playground! So it compiles to WASM? If you are gonna look like Rust. Please, no unwrap() everywhere.

  • tibordpOP 3 years ago

    No native compilation to WASM yet, but since the compiler outputs self-contained C, it should be fairly easy to do it with Emscripten.

    The sandbox is running the code server-side in a nsjail container.

    As for unwrap, I feel you! the try expression (expr?) is supported, which makes it look a bit nicer, but I'm still trying to figure out a good idiom for when you actually want to do specific things based on whether the result is ok or err.

    Alumina does not have Rust-style enums (tagged unions) or the match construct, which makes it a bit tricky.

revskill 3 years ago

Love this.

What if Rust provide a separate analyzer to analyze potential memory leak from this language.

  • tibordpOP 3 years ago

    Valgrind and Sanitizers should work on Alumina. I have not actually tried them myself yet, but I don't see any reason why they couldn't work.

    The only potential problem I see that with the current C backend, the debugging information is very hard to trace back to the original Alumina source code, so it might be hard to see where the leaks are coming from. This is something I plan to address in the self-hosted compiler, once it is functional.

chrismsimpson 3 years ago

Interesting no one here is discussing “Jakt”, which looks very similar in style and approach. Jakt is the language attempted by the SerenityOS team, which itself dispels the notion you can’t building something of substance from scratch without outside libraries. Jakt also implements fairly lightweight reference counting, making it memory safe. I think the potential of SerenityOS/Jakt can’t be overstated and strikes me as comparable to the excitement surrounding Linux in the early ‘90s.

  • lolinder 3 years ago

    Jakt's #1 design goal is memory safety. The very first paragraph of Alumina's docs says that it intentionally keeps C-style memory-unsafety. For systems programming languages, that makes them philosophically quite at odds with each other.

    Were there similarities besides "syntax inspired by Rust"?

renox 3 years ago

So, as far as I understand its main feature is that it has a Rust-like syntax?

  • tibordpOP 3 years ago

    As far as I know it doesn't have a single feature that is really unique. It's more like a combination of things I like from other languages, like syntax and expressions from Rust, defer expressions from Go, UFCS from D.

    The overarching theme is to see how far you can go making a language that feels high level without having a garbage collector or RAII. I used to use Deplhi/Pascal a lot when I was younger and it was this kind of language.

nnoitra 3 years ago

New language posts have to stop. There are tons of other CS topics to talk about but instead LIPSs ()()()()((((())))) and random langs taka the spotlight on HN.

  • nicoburns 3 years ago

    Well we'll always need language designers and compiler developers, and new ones have got to learn somehow. Creating a toy language seems like a pretty decent way to go about it.

  • lolinder 3 years ago

    I upvote any new language post I see because I find them very interesting and want more of them. The nice thing about HN is you can just scroll past posts you don't find interesting. The "tons of other CS topics" are also discussed on HN.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection