https://www.ptc.com/en/products/developer-tools/perc
https://www.aicas.com/wp/products-services/jamaicavm/
Also I should note that many embedded computers in 2022 are supercomputers when compared to the 1961 IBM mainframes running Lisp.
- the GC is a sliding compacting GC. As such there is no fragmentation for heap-allocated memory.
- the memory on these devices is tiny. The GC thus doesn't take long time.
- the ESP32 has really good peripherals, making timing sensitive operations very rare. In most cases there is a hardware module that does the job for you. The timing requirements then usually become significant less important.
I think you can easily do 90% of iot projects with this. Which means you have more time for the 10% of projects that are actually hard.
From an embedded system PoV, your sensor might be a 1-Wire protocol device with a super strict signal timing. How do you mix both timing requirements? How do you differentiate embedded projects requiring "precise timing" from those others requiring "every 60 seconds"?
Unless Toit provides drivers for all kind of buses, sensors and peripherals AND it orchestrates the GC with the strict timing requirements. Otherwise it's probably a good fit only if it just runs on a known controlled development board/architecture/platform.
For example the 1-wire protocol is implemented using the RMT (remote control) peripheral. The pixel strips driver uses the UART or i2s.
If really necessary, we could drop down to C, but the hardware is usually better (more precise and leaves us to do other things in the meantime).
Maybe the title should be "Toit is a modern high-level language designed specifically for ESP32".
How often are you bitbanging non standard protocols? And if so, which field are you in?
Not true at all.
> How often are you bitbanging non standard protocols?
Regarding protocols: bitbanging 1-Wire. Not all microcontrollers have this peripheral. You might be lucky if you can adapt some other peripheral like an UART (with due effort). Or you can use for example an external ds2482 and drive it through I2C.
WS2812B: sometimes you can emulate it with some other peripheral, sometimes you have to do it by bitbanging some GPIO.
I don't bitbang so often in general. But it's not just about available "hardware blocks": introducing undesidered delays in embedded applications is a terrible, terrible idea.
You can have a perfectly working sensor through I2C with DMA, super optimized with 0 CPU intervention. This sensor has an ODR of 1kHz. A GC stopping the microcontroller for 400ms makes you stand behind 400 samples you might be processing in real time (FIFO aside, and because you know you shouldn't be doing any processing in an interrupt handler, right?). You don't lose the buffered samples of course, but your processing is now delayed.
Or perhaps you are doing some 44100, 16-bit stereo audio processing (in or out). You have implemented the perfect I2S/DMA mechanism and all that, combined with perfect SDIO reading. What would happen in a real-time processing audio application if the GC introduces even 20ms delays now and then? Horrible latency and/or artifacts... And because your MCU has 32KB of RAM you don't have the luxury of big buffers, so you have to be quick reading, processing and outputting. Stopping the processing = stopping the output.
Or you might be dealing with some external peripheral that needs an answer within a time limit...
You can see it's not just about "hardware blocks".
Following what I said before, even if "60 seconds" is the application required timing, there are other things that might be happening in the background that require precise timing.
Is Toit a bad language? I don't know. But as I said before, it only makes senses if ran under a known platform like ESP32 where the language developers have tuned everything, and the programer doesn't pretend real-time applications. A generic language for every microcontroller? I am not so sure...
Maybe they don't do[1] dynamic memory allocation in code segments that have real time constraints, or after initialization, etc. (Most embedded projects actually don't have hard real-time constraints, or have them in extremely localized places like bit banging loops...) This is sounds like a good idea and is orthogonal to whether the language's dynamic allocation support is via malloc/free or gc.
1) A compiler flag or similar optional static check that throws a warning if you have dynamic memory allocation. In scripting languages it can be easy to do accidentally
2) A way to block the gc from happening in a time critical section of code, like how you can disable interrupts
3) Some guarantee on the maximum time gc will take
On microcontrollers, which often have very limited RAM, I'd prefer avoiding doing any heap allocation at all. If there is any need for any dynamic allocations, they are within fixed-size memory pools — each with only fixed-size objects or with objects on a stack.