[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)