V is very similar to Go, and these are the things it improves upon:
- No global state
- No null
- No undefined values
- No err != nil checks (replaced by option types)
- Immutability by default
- Only one declaration style (a := 0)
- Much smaller runtime
- Much smaller binaries (a simple web server written in V is 65 KB vs 7 MB in Go)
- Zero cost C interop
- No GC
- Much faster serialization using codegen and no reflection
- Precompiled HTML templates unlike html/templates that have to be parsed on every request
- Fearless concurrency (no data race guarantee at compilation)
- Enums
- Generics (in July)
- String interpolation: println('$foo: $bar.baz')
- Stricter vfmt to ensure one coding style
- Centralised package manager
In C the only memory available to a function is its arguments and data with static duration. That static storage is synonymous with global state, if it isn't known at compile time.
A C-compatible closure basically requires an executable chunk of memory that captures the state along with the istructions to push it to the parameters area (based on the architecture's calling convention) and then jumping to the actual function.
This is not global just because it's scoping the state with the function. On the other hand it becomes global the moment it gets installed to a global handler table (because there can only be one such handler).
However a language that limits globals (and forces people through this kind of hoops in order to deal with cases where singletons are really needed) encourages a coding style that makes it easier to test your code in isolation.
Just move "global" (aka: main() ) up 1 function. And then, run everything in that function. Hell, it could be a try-catch loop equivalent.
COM APIs expose a global class factory as the main interface to a shared libraries.
Embedded systems and drivers require globals in one form or another.
"Globals are evil" comes from the fact that globals have side effects, and side effects make things hard, especially in modern software that utilizes asynchronous/concurrent logic. That just makes them unwieldy, not unnecessary. Especially when interacting with legacy systems that require globals.
Yeah, state sucks. But sometimes, you need a starting point, and diff from that. And, that's state.
One of the safe ways of handling global vars, is by having only a single non-interruptible function that can mutate global. And you have best make sure your global-mutating function is fast. You don't want to miss IRQs that might fire off but are blocked.
https://www.ericsson.com/en/mobility-report/internet-of-thin...
A kernel doesn't really need a garbage collector, but keep in mind that some modern GCs can literally be tuned to have ms pause times on absolutely enormous heaps which given that reference counting can have unbounded pause times too can make them an enticing option.
The real reason to avoid garbage collection is typically memory usage in my experience
There are reasons not to use a Garbage Collector but 99% of the time they are absolutely fine if you understand what your particular GC does and does not do
Clang/GCC both have suites of sanitizers which are usually excellent and easy to grok, these are also available in many language frontends based on LLVM (and maybe GCC?)
You can just throw every tool you can find at your CI if you're paranoid, too.