[HN Gopher] Show HN: Alumina Programming Language
       ___________________________________________________________________
        
       Show HN: Alumina Programming Language
        
       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'etre (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/
        
       Author : tibordp
       Score  : 73 points
       Date   : 2022-09-03 15:32 UTC (7 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | mhd wrote:
       | 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 wrote:
         | What is it that people hate about Rust syntax beyond the
         | terrible lifetime syntax? Seems pretty reasonable to me.
        
           | xigoi wrote:
           | 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>?)
        
           | still_grokking wrote:
           | 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).
        
           | aaaaaaaaaaab wrote:
           | The community.
        
             | dhosek wrote:
             | What I've found is that Rust people on stackoverflow not so
             | great, Rust people on Reddit pretty pretty good.
        
           | markusde wrote:
           | 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.
        
       | Eliah_Lakhin wrote:
       | 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!
        
         | tibordp wrote:
         | 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.
        
       | Surfactant7 wrote:
       | > 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.
        
       | chaosprint wrote:
       | Online playground! So it compiles to WASM? If you are gonna look
       | like Rust. Please, no unwrap() everywhere.
        
         | tibordp wrote:
         | 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.
        
       | pipeline_peak wrote:
        
         | wtetzner wrote:
         | What an odd comment when the post contains this:
         | 
         | > It is mostly for fun and exercise in language design, I don't
         | have any grand aspirations for it.
        
           | xpe wrote:
           | > What an odd comment when the post contains this "It is
           | mostly for fun and exercise in language design, I don't have
           | any grand aspirations for it."
           | 
           | You are being quite generous in calling the comment "odd".
           | 
           | Here are five words to summarize that comment: disparaging,
           | out of context, cruel, speculative, and pessimistic.
           | pipeline_peak can do better. The HN guidelines are a good
           | start.
           | 
           | >> pipeline_peak : Another Rust lookalike to reinvent the
           | wheel, I wonder what's gonna happen to it in 10 years.
        
             | pipeline_peak wrote:
             | Aaaaaand no response from wtetzner
             | 
             | I gotta say getting this much coverage from one individual
             | over my little comment is pretty odd, or is that "quite
             | generous"?
        
         | xpe wrote:
         | Please try to offer some kindness. Or at least accept that
         | people have various motivations and goals. Languages are
         | regularly remixed. Also, "language designer" is not an elite
         | term -- it can be a hobby, a way to learn, and even a way to
         | inspire others.
         | 
         | Perhaps I could invent a spoken language where disparaging
         | remarks are possible but extremely lengthy, thereby
         | discouraging negativity from people in bad moods.
        
           | pipeline_peak wrote:
           | > thereby discouraging negativity from people in bad moods
           | 
           | A little tough praising kindness with a whiff of passive
           | aggression, not very "HN guideline like".
        
       | nnoitra wrote:
       | 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 wrote:
         | 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.
        
       | ducktective wrote:
       | 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.
        
         | tibordp wrote:
         | 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.
        
       | renox wrote:
       | So, as far as I understand its main feature is that it has a
       | Rust-like syntax?
        
         | tibordp wrote:
         | 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.
        
       | MontyCarloHall wrote:
       | 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.)
        
         | danias wrote:
         | 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 wrote:
         | What's an example of a language with "good" FFI?
        
           | WalterBright wrote:
           | 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 wrote:
             | 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.
        
           | davedx wrote:
           | Rust's seems pretty good. I've been doing some Rust/C interop
           | and it works very smoothly
        
           | zyx_tony wrote:
           | Nim is quite enjoyable to use. I do a decent amount of
           | scientific computing, interfacing with various c/cpp libs
        
           | williamstein wrote:
           | Calling C functions from zig is very nice, partly because zig
           | uses llvm to parse C header files and uses that information.
        
           | beagle3 wrote:
           | 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)
        
         | belmarca wrote:
         | 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.
        
         | aliqot wrote:
         | Libraries are a farce. Stdlib or die. I 100% mean this and live
         | this.
        
           | thesuperbigfrog wrote:
           | 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 wrote:
           | Would that include things like encryption? No exceptions for
           | your rule?
        
             | still_grokking wrote:
             | 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...
        
           | Asraelite wrote:
           | 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 wrote:
             | 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 wrote:
               | 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?
        
               | aliqot wrote:
               | I appreciate you for relating your experience. It's not
               | ambition or challenge that is lacking, we are what's
               | commonly called 'Amish'. This is just how we do things.
               | 
               | https://en.wikipedia.org/wiki/Simple_living
               | 
               | https://en.wikipedia.org/wiki/Nonconformity_to_the_world
               | 
               | I'm sure this creates more questions than it answers,
               | however, I hope it lends some context as to how we've
               | both arrived at our own respective happy milieus.
        
               | whartung wrote:
               | 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."
        
           | mypalmike wrote:
           | Why even use stdlib? Or an OS? Just write everything every
           | time down to the bare metal.
        
             | whartung wrote:
             | Chuck Moore, is that you?
        
         | tibordp wrote:
         | 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.
        
       | revskill wrote:
       | Love this.
       | 
       | What if Rust provide a separate analyzer to analyze potential
       | memory leak from this language.
        
         | tibordp wrote:
         | 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.
        
       | noncoml wrote:
       | 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.
        
         | leni536 wrote:
         | Except go's defer is scoped to the function, instead of the
         | innermost enclosing scope.
        
           | tibordp wrote:
           | 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()         };
        
         | tibordp wrote:
         | 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 wrote:
           | > 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?
        
             | tibordp wrote:
             | 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 wrote:
               | 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.
        
               | tibordp wrote:
               | 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.
        
       ___________________________________________________________________
       (page generated 2022-09-03 23:00 UTC)