C3 is pretty much aimed at those who would use C for a task but prefer something a bit more modern. I find it more fun to program in compared to plain C, and it's definitely more simple than reaching for C++.
I don't think it is available no, and it's the first time I heard about such an idea. Thinking on it, this would allow such cursed code (love that :D). I'll put it up for discussion in the Discord as I'm interested in hearing whether `.defaultof` is a good idea or not.
One application of such a feature would be something like a "cligen.c3" (like the Nim https://github.com/c-blake/cligen or its /python/cg.py port or etc.). Mostly it just seems a more complete signature extraction, though. Any other kind of documentation system might benefit.
This actually started of by Christoffer (C3 author) contributing to C2 but not being satisfied with the development speed there, wanting to try his own things and moving forward more quickly.
Apparently together with LLVM it was doable to write a new compiler for what is a successor to C2.
The way I reason about it is that the contracts are more soft conditions that you expect to not really reach. If something always has to be true, even on not-safe mode, you use "actual" code inside the function/macro to check that condition and fail in the desired way.
The difference from an assert is that for "require" they are compiled into the caller frame, so things like stack traces (which is available in safe mode) will point exactly to where the violation happened.
Because of inlining them at the call site happens, static analysis will already pick up some obvious violations.
Finally, these contracts may be used to compile time check otherwise untyped arguments to macros.
“However, violating either pre- or post-conditions is unspecified behaviour, and a compiler may optimize code as if they are always true – even if a potential bug may cause them to be violated”
This implies that a compiler would be permitted to remove precisely that actual code that checks the condition in non-safe mode.
My understanding of this was that the UB starts only after the value is passed/returned. So if foo() has a contract to only return positive integers, the code within foo can check and ensure this, but if the calling code does it, the compiler might optimize it away.
Assuming that is correct, it's still exactly the same footgun. Checks like that are introduced to guard against bugs: you are strictly safer to not declare such a constraint.
You can actually see the whole implementation of `@pool` inside the standard library (link: https://github.com/c3lang/c3c/blob/f082cac762939d9b43f7f7301...) if you're interested. You'll have to follow a few function calls, but the whole implementation is defined within the standard library and thus easily modified for your needs.
I believe that the memory inside the pool is indeed contiguous, and you can ask for a custom initial capacity. The default capacity depends on `env::MEMORY_ENV` at compile-time, but for normal use it's 256kB (256 * 1024, in bytes).
About the explicit allocator passing, that's also a theme throughout the C3 standard library. Functions that need to allocate some memory will take in an `Allocator` as first argument. For those kind of functions there is always a `t<function>` variant which does not take in an allocator but calls the regular function with the temporary allocator. It's a nice naming convention used which really helps together with `@pool`. Examples are `String format(Allocator allocator, String fmt, args...)` and `String tformat(String fmt, args...)`.
I hope that clears up some "concerns", and maybe you'll also find some joy in programming in C3 =)
If I could take a guess, then it is for embedded applications.
You could argue though that people should then really do there own memory management, but in the end you might end up just recreating the temp allocator with `@pool` anyway. It's a neat feature.
(btw, `@pool` is just a macro from the standard library, no fancy compiler builtin)
In that case I advice using actual C3 vectors. They are a built in type that will use simd (or similar) under the hood if the compilation target supports it.