47 comments

[ 3.6 ms ] story [ 105 ms ] thread
From the docs: Blech is a German word and roughly translates as bare metal. As its name suggests, a Blech program can run on pretty much anything:

* directly on “the Blech” in an embedded device,

* on top of a realtime OS,

* as a safety-critical component integrated via some middleware,

* in combination with a simulation model.

Blech also means sheet metal. So a metal (beverage) can is a Blechdose (a Dose is a can). Colloquially one could also say "Red kein Blech" which literally translates to "Say no sheet metal" and means "Stop saying nonsense" or something among those things.

If a sound is blechern we are speaking of a tinny sound. It can also be used as a verb: blechen stands for paying, typically used for when someone has to pay too much or for bad reasons (e.g. when they gave you a ticket for parking in the wrong spot).

> Blech also means sheet metal

I believe the English word “blacksmith” preserves this shared etymology.

Blech has the same etymological roots as English blink, roots whose meaning is “to shine”. Blick (both English and German) is also related, as are blank and bleak, and, indeed, also black (which comes more from a “to burn/blaze” variant of “to shine”).
Also Blikkenslager, someone who works with sheet metal (Norwegian, Bokmål).
This sent me down a rabbit hole, and I'm back to share what I found:

The English word which shares ancestry with Blech is 'blink'. You're welcome.

Edit: Der Blechenmachine ist nicht für gefingerpoken!

Haha thanks, a very interesting connection.
Now it makes sense. “blech” in English is an expression of disgust.

Pronunciation, according to the dictionary, is [blɛç].

I grew up reading Mad magazine, and this is the meaning of the word to me. Along with "poit" indicating a wardrobe malfunction.
I assumed it was in honour of Bletchley Park.
I love the name. What's in a name? In my experience, names that come off like a brag are unlucky. Names that are self-deprecating are lucky.

It's my dream to make something awesome with a particularly off-putting name. People who judge a book by its cover will miss out. People who don't care about names will reap the benefits.

In other words, your customers don't care if you utilize a tool called "Turd" or whatever.

"To build the project you need [Microsoft] .Net installed."
.NET core is cross-platform, open source, and comes with a `dotnet` CLI that allows you to do basically everything.
Except build the program.

$ dotnet build

A fatal error occurred, the folder [/usr/lib64/dotnet/host/fxr] does not contain any version-numbered child folders

I dont know dotnet and dont know how to fix that ^.

On a serious note, talked to a dotnet friend who said "install the sdk you moron". dotnet cli tool requires more than just the tool itself.
And the cli tool didn't report that a dependency (sdk) is missing?
Would be interesting to see how to use this with FreeRTOS. We're using Nim at work for our firmware on top of the ESP32-S3, which has been pretty lovely, but even then there are some challenges with matching how FreeRTOS wants us to work vs how doing it in Nim should be done.

The biggest challenge in embedded programming languages is this tendency for languages to "rebuild the world" rather than work with what we already have, and thats just a non-starter for most of us as the amount of IDFs, HALs, drivers and libraries out there are too numerous to throw away.

But the flip side of that, is they are typically all very C-focused, and so even in a language with really nice binding of C functions (Nim, Blech too from the looks of it), you end up having to contort your Nice Language code into a C simulation most of the time, which really sucks. And don't get me started on C++ libraries/drivers...

I wish I knew what the answer was to this. Nim gets pretty close in my experience, but even it has rough edges for this stuff. Dunno, its a hard problem -- Blech's binding syntax looks decent and the rest of it's features look fantastic, so I'd love to be able to reach for it, but C/C++'s continued dominance and body of work makes my head spin when I think about the task all these languages have ahead of them if they are to get real traction in industry.

Are by chance your nim changes an how you use it with esp32 somewhere publically available? I think I read a thread where you chatted with elritch (the nesper maintainer), to upstream your changes, but I am not so sure
Yep it’s already in develop on his repository :)

Add -d:esp32s3 to your nim.cfg or compile time flags and it’ll swap out the GPIO and IO mux definitions for the S3’s

I have a PlatformIO plugin to make getting up and running with ESP-IDF easier that I’ll be releasing once our new boards arrive and pass assembly and QA next week too, should find it at VenturiTechnology on GitHub

At first glance, the multiple bracket groups in the function signatures look really weird to me.

Does anyone know what the motivation for those is?

Example (function definition):

    function writeTicksToDisplay (ticks: int32) (display: Display) [...] end
Function use:

    writeTicksToDisplay(totalTime)(display)
https://www.blech-lang.org/docs/user-manual/declarations/#su...

> There are two parameter lists. The first lists declares formal parameters that may only be read (like `let` variables), the second list declares formal parameters that may be both read and written (like `var` variables). In particular the two lists are useful for activities which, in every reaction, receive a list of read-only inputs, perform some calculation and set the list of read-write outputs. We will therefore often refer to these two parameter lists as “input list” and “output list”.

I would have personally used explicit `in` or `out` keywords a la C#, but otherwise it seems a reasonable rationale.

Thx for the link!

I actually like how that probably strongly pushes towards const-correct design just to be able to omit the second list...

`in` and `out` would have been the familiar choice, but I think Blech made the better one. They sort of wink at this in the documentation, by naming parameters in and out, but more than just freeing a couple nice names from being keywords, this spare notation is a good fit, read vs. read+write is a crucial distinction in embedded.

In particular, a function with one parameter list can only read the variables, and that is as clear at the call site as it is on declaration. This is a nice property to have!

I also kinda like it , but I believe this implies that function types either can't be first class values or that parsing needs full type information because otherwise you couldn't distinguish between single and chained calls-- or am I missing something?
I wouldn't call C functions first class either, it's a fuzzy term though. Function pointers, yes, and that's another place where it's pretty cool that there are two distinct parameter lists. I just found Blech this morning so I don't know how it deals with function pointers. Competently, I'm guessing.
Completely missed your point in a sibling reply, let me try again.

Returning a function pointer should be ok, chain syntax is a sugaring which is probably not high-payoff in an embedded language.

So would explicitly capture the pointer as a stack variable and then use it, three parentheses would be illegal instead of ambiguous. Seems reasonable to me.

Syntax only distinguished by a relative order doesn't sound robust to me. In contemporary languages keyword arguments are a thing exactly because of that.

Marginally related example: many wiki syntaxes had a link syntax similar to `[[foo|bar]]`, where `foo` and `bar` can be either a label or a target and the order wildly varied across softwares---later lightweight markup languages had their lessons and used a different syntax for a label and a target (e.g. Markdown `[label](target)`).

I don't think that's a problem here. There are three options, function(val), function(valA)(valB), and function()(val).

I read the manual once this morning before coffee and I know which vals are read only and which are writeable. I've never written a line of Blech.

That's pretty good design if you ask me.

Week after week I see posts on HN about a new language and why it suits the niche it targets.

Wouldn't it easier to take a high language lexer like c# and morph it's outcome to the niche iinstead learning a new language that isn't maintained after 5 years? c# was already used for python, maui.net cross compiles to android, ios, windows, linux, web, ...

What's your take on this?

It is a tradeoff. You can buy into the C# ecosystem and get a lot of benefits (like reusing all the libraries already written in other languages). However, if you build software for real-time embedded microcontrollers, like Blech does, that these advantages are not worth it.
Regarding maintenance, syntax is pretty low on my list of "reasons to worry about a language's future". What almost always is at the top is "can I genuinely use this?" which often means being able to interoperate with other languages and reuse existing libraries, and of course, that the language does what it says it does.

In fact, I could only expect more confusion from reusing an existing syntax, no matter how nice it is, if the semantics won't be the exact same. In this case specifically, C# and all its libraries are very much oriented about not managing memory manually, so a lot of language features would either be morphed into something with idiosyncratic semantics, or would not be possible to be used.

Maui most likely could not be hacked to work compliantly in a strict realtime environment anyway, for example. So there's no advantage for it to be available.

1. Learning new languages isn't hard once you've done it a few times. The people most interested in stuff like this don't see that as a meaningful cost, and many even enjoy it.

2. For certain classes of projects the future of the underlying tools aren't relevant. You may be surprised how many projects either don't have a long projected lifetime, or are expected to have a long deployed life with little to no updates or rebuilds.

3. The only way a language can become mature and lasting is for it to survive those first "5 years" (as you put it). Somebody has to be out on the front lines, putting it through its paces, and contributing to the community that makes it last.

4. These new languages often act as unofficial testing grounds for ideas that later fold back into more established languages.

We're in an age of extensive research and innovation in practical languages and tools. It's kind of exhausting sometimes, when you try to keep up on it all (or have a team that tries too), but it's an incredible boon to the industry as a whole.

Has Blech been used in any production real-time critical embedded systems?

Blech looks nice, but I cannot see why it would be chosen versus Ada or MISRA C for real-time critical embedded systems work.

For one thing, having humans write C for critical code is almost always a serious mistake. Almost anything would be better, which is why so much safety critical C is generated nowadays.
No, it's not production ready yet. Look at the GH issues page e.g. No const arrays yet, no C macros for sharing consts,...
I'm not an embedded software guy so I don't have a use case for this. However, I want to give major credit to the people who made the website. The second thing you see is a reasonably sized chunk of real code. This is what every single programming language website/README should do
If "activity" is "async", why rename it? Or, how is activity different from async?
What I love about this:

• A transpiler and language server both written in F#. That's as good as it gets on the .NET platform. I'm starting to use F# myself and I'm sure I can learn a lot from this.

• Top-notch documentation, including a good explanation of the execution model.

• The language specifically targets embedded programming which has to deal with mutable state all the time (hardware registers, interrupts, etc…).

Surely the example shown on the web page would be easier and simpler to write in plain C? By using the loop tick style approach that games use? That’s what I have always done when working on no-OS-to-the-metal code. For low-power usage I pause the loop (if there is hardware/OS support for it) or use an interrupt to trigger a single loop step. And prioritising tasks can be done by only running certain steps every 2/3/4/N ticks. It’s simple. It works.