Show HN: Micron – Oberon with the Power of C

(github.com)

62 points | by Rochus 4 days ago

10 comments

  • andsoitis 4 days ago
    Love the examples you've implemented in Micron:

    The examples subdirectory (https://github.com/rochus-keller/Micron/tree/master/examples) contains:

      - a Smalltalk-80 implementation,
      - the original 1976 P4 Pascal compiler,
      - the Scheme 9 virtual machine,
      - the Project Oberon System running on the host,
      - and the Micron System described in the textbook, the migrated Project Oberon System natively running on RISC-V.*
    • Rochus 3 days ago
      The idea was to migrate representative C, C++, Pascal and Oberon implementations to Micron to see whether the language is descriptive and practical enough, and indeed I made a lot of language changes because of this experience.
  • berkeleynerd 3 days ago
    Would be great to see Micron up on Rosetta with a good selection of examples ported there. Great work...will definitely be having a look!
  • andsoitis 4 days ago
    Congratulations!

    I've always been super interested in Oberon (due to my Pascal / Object Pascal / Delphi heritage) and even tried things like A2 (https://en.wikipedia.org/wiki/A2_(operating_system)) but never fully got into the boat.

    Micron makes me excited to try your latest incarnation.

  • HexDecOctBin 19 hours ago
    It seems like the language requires Pascal/C89 style declarations on top of the scope. I've never been sure why Pascal developers have stuck to this convention for so long. Is it the zeal to preserve single-pass compilation?
    • Rochus 19 hours ago
      Yes, that's from the Pascal/Modula/Oberon heritage. It's both a design style and a feature to support single-pass compilation (know the stack size and offsets of all parameters and locals before parsing/generating the body). Even that C/C++ are my main languages, I have no problem with declaring variables and nested procedures on top. It's just a matter of taste and getting used to it.
      • fuzztester 15 hours ago
        i don't have any problem with that, either. if you are skilled with your text editor, which any developer should be, the slight extra overhead to jump around between definitions and uses is trivial. e.g. use marks and go to mark in vim. or equivalent in emacs. or ...
    • srean 17 hours ago
      Because some prefer their programs to compile in a snap without throwing a few clouds at it.

      When compilation is that fast, it leads to a different kind of a conversation with the computer. Not necessarily always a better conversation but definitely different.

      • wahern 10 hours ago
        I'm accustomed to it and even prefer it, but the performance benefits are only meaningful for the most simplistic of compilers supporting the barest of optimizations, like trivial constant folding. Once a compiler builds a whole-function AST, inline declarations have approximately zero cost, and when it starts to perform non-trivial transformations then juggling stack slots comes with the territory.

        Such sophistication is also necessary for variable-length arrays, anyhow, especially in loops, so it's presumably no coincidence C99 got inline declarations, compound literals, and VLAs all at the same time.

        C hasn't yet fully embraced and leveraged VLAs or the dependent typing features they brought along. That gave them a bad reputation (in crippled form they're all cost for little benefit), unfortunately causing languages like Rust to avoid them. If Rust (and LLVM) had fully embraced them from the beginning, alot of sharp edges wouldn't need to exist in Rust, especially around initialization and statically vs non-statically sized types. Premature optimization (in this case regarding baseline object semantics) is the root of all evil.

        • srean 10 hours ago
          An effective workflow to have when you have a fast compiler and a slower, optimizing compiler is to use the former for (interactive) development. Sometimes that would be two different compilers, sometimes the same compiler at different optimization settings.

          Once you are happy with the code one can use the optimizing compiler set at a preferred level of optimization.

          As an aside, some simple Pascal compilers would not wait for building the full AST before emitting object code.

          • wahern 6 hours ago
            Sure, but by limiting semantics to preserve the ability to do single-pass compilation or similar implementation optimizations, you're forever shutting the door to some very powerful language features that might only require a moderately more complex compiler, certainly far less complex than what most optimizing compilers end up becoming.

            This is why C++ evolves the way it does, and Rust as well. A little more semantic complexity deeper in the language and compiler architecture would unlock tremendously more potential. But because of how the history of C, Pascal, etc has shaped assumptions about primitive typing and object semantics, compilers are invariably architected in a way that higher-order language semantics have to be built in layers above the core compiler and by extension through a meta layer in these more modern languages. Variable length arrays are the prime example; they can only be modeled in C++ and Rust as library interfaces. To implement them as more fundamental primitive types you need a kind of dependent typing ability in the core semantics and compiler implementation. That then necessarily unlocks alot more possibilities for richer language semantics that would be impossible or handicapped otherwise. Alot of the nominally more sophisticated features of C++ and Rust are stilted for just this reason. Rust especially because while far more ambitious than C++, LLVM in many ways is fundamentally built to model what a 1990s C compiler would require, and a few but crucial choices in Rust were motivated by limitations in LLVM.

            There are similar problems with how control flow is modeled and reified, but properly resolving them is hindered not only by compiler architecture, but also by OS and hardware abstractions, which like compilers largely coevolved to satisfy the needs of C. Imagine a world where both hardware and OS ubiquitously presumed stack management necessarily required a special register to delimit stack boundaries, independent of VM page size. In such a world we could have space optimal stackful coroutines, and they wouldn't need to be as stilted as in C++ or Rust. That alone would be amazing, but it would trivially open the door to every "bare metal" language having something akin to Goroutines for free, and with maybe some additional work possibly in a language independent manner.

            • srean 4 hours ago
              > This is why C++ evolves the way it does

              Exactly why I prefer simplicity. Exactly what I don't want my language to become. Single pass compilable does not precluded multiple passes for optimization.

              D compiles very fast and has a cleaner design than C++. The latter has been trying hard to be a D wannabe for years. D's is not single pass compiled though.

              BTW Modula-2 had coroutines. If I remember correctly they were stackless ones.

      • inkyoto 9 hours ago
        It is not clear whether you are comparing it specifically to C, but single pass C compilers have certainly existed, including the ones that fuse the C preprocessor with the compiler itself.

        Disabling optimisation, can also boost the compilation speed although it won't be as fast.

        If, however, the comparison is against more modern languages, such as Rust, Swift, Haskell, ML etc, the actual compute effort goes into type inference, not the multi-stage compilation process, as proving type correctness is a computationally hard problem.

  • jsrcout 18 hours ago
    This seems like an extremely comprehensive work. Look forward to checking out the textbook and examples particularly.
  • neverartful 15 hours ago
    Very impressive work! I'd love to give it a try but my browser blocks download of the precompiled binaries due to it being served over http. I may build from source as it's intriguing. It would be nice to have the command-line compiler have fewer steps to build from source.
  • nigel_bree 11 hours ago
    Great work, Rochus; I loved what you had done with Oberon+ but I am impressed with how far this goes while being so in the spirit of Wirth's classic approach. And as others have said, the examples are impressive in their selection, they do a great job of demonstrating that it does what you set out, I'll be chewing on the thoughts in your book for a while I suspect.

    I'm so grateful that we have people like you and Nils M. Holm keeping lots of these old ideas about design fresh, you both inspire me to keep pushing myself in my own projects.

    • Rochus 3 hours ago
      Thanks for the motivating words, I appreciate. Micron was indeed a lot more work than Oberon+ and it will keep me busy. I hope the book is clear enough.
  • Panzerschrek 9 hours ago
    Is it memory-safe? Or just as safe as C?
  • chasil 17 hours ago
    "Early examples like UNIVAC and the IBM 7030 were used by scientists working on atomic research. The Cray-1 came along in the mid-70s and accelerated such work to new levels."

    Seymour Cray also designed the CDC 6600, which had a much more immediate impact on IBM et al.

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