HackerTrans
TopNewTrendsCommentsPastAskShowJobs

tibordp

128 karmajoined 4년 전

Submissions

Show HN: Kurvengefahr – browser CAD/CAM for pen plotters

kurvengefahr.org
18 points·by tibordp·12시간 전·5 comments

Show HN: Alumina Programming Language

github.com
107 points·by tibordp·4년 전·87 comments

comments

tibordp
·7시간 전·discuss
Yes! We played Achtung a lot on library computers in high school during breaks and I remembered it when I needed to pick a name for the app.
tibordp
·6개월 전·discuss
Given that we are talking about A4 papers and grams, I'd bet this wasn't in the US.

In Europe, the typical flat rate is up to 100g for standard letters. And that's 20 sheets, which is not a particularly unusual letter to send.
tibordp
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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();
    }
tibordp
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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.
tibordp
·4년 전·discuss
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.