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