Araq
Having said that, "embedded" is a wide field and sometimes one cannot even afford a heap, no matter if garbage collected or managed manually. But even then Nim can be used, you still get array bounds checking, Ada-inspired strong type checking plus the meta programming goodies.
There's a patch of the collector to make the M&S incremental, to avoid pauses for this step too. Of course, whether a deferred RC'ing GC with incremental cycle collector works better in practice than a more conventional generational incremental GC (or just an incremental GC) is an open question. :-)
Nim has garbage collected pointers (ref) and raw pointers (ptr). You can use 'ptr' to break up cycles manually and disable the M&S. I suppose it's very much comparable to Swift except that Nim's RC overhead is much lower since it's deferred RC.
Sure and you only need to call libclang for each different platform. Or is it on every platform? ;-)
Since version 0.14 (iirc) however, Nim uses a traditional mark&sweep backup GC to collect cycles. Reasons: Trial deletion in practice is much slower.
For all versions of the GC is stack is scanned conservatively as precise stack scanning is simply too expensive when C is your main target.
The manual tries very hard to mention corner cases since it's evolving into a proper spec. Calling printf is safe, it's C functions that take ownership of the char* pointer that are inherently unsafe.
> Maybe Nim should have an unsafe directive to make sure any unsafe user code is clearly marked?
That's a common misunderstanding, Nim doesn't need this. Instead of an ``unsafe`` keyword, Nim has ``addr`` and ``cast`` as keywords, these are the unsafe building blocks of the language. There are other corner cases that introduce unsafety, but they are all known and can be solved in time.
> I also coulda sworn there was some part of the manual or site that was discussing a feature with a limitation due to the difficulty of expressing it in C.
Well these things certainly are everywhere, but the issue here is not the difficulty of expressing it in C, but a desire to have very good C interop. Rust actually has all the same design constraints even though Rust builds on top of LLVM because the constraints come from the "systems programming" problem domain: Control over memory layouts, the stressed difference between heap and stack, etc. LLVM's IR is very close to C, so what is difficult to map to C is difficult to map to LLVM too.
But C is Turing-complete, so there is no restriction here. It's also not a "bunch of ideas thrown together" anymore than Haskell or Scala or Rust is. Nim focuses on 3 things:
* Metaprogramming via a hygienic AST-based macro system.
* An effect system to make the type system simpler to use. (The compiler infers an awful lot of useful information for you, the docgen shows the results for everybody to look at.)
* GC'ed thread local heaps where each GC can comply with soft-realtime requirements. Hard realtime is being worked on.
Any modern statically typed language also needs to have generics, closures, inheritance, exceptions or workarounds of the same complexity, so yeah Nim also has these making Nim instantly a big language. That doesn't mean it's a "bunch of ideas thrown together".
> It doesn't have memory safety as a core goal.
It does and it is reasonably safe (yeah yeah yeah we don't check for 'nil' properly yet, give me a break) with quite some improvements in the pipeline.
- Conservative GC marking of the stack.
- No stack overflow check in release mode.
Compiling to C is not tricky, it is horrible and we don't do it for the fun of it! That said, clang has lots of options to tame C's undefined behaviour. Guess what, you can enable these too for C code generated by Nim.
pcwalton's remark is excellent but "automated proof technology" is not a well defined term. What I mean by this is that it goes beyond what a traditional type checker can do. I don't think Rust can do exactly the same things via its borrow checking and its iterators, but I might be wrong. Note that the very same analysis also proves your index bounds are correct.
Nim's disjoint checker is so experimental that its docs are indeed very terse and we only have a couple of test cases for now. That said, the disjoint checking is restricted to the 'parallel' statement, so its complexity only affects this language construct and not the whole language. You can think of it as a macro that does additional checking.
I can't say I agree with anything you say though... So only memory safety is C's problem? Not its type system that's very weak in every aspect (not just memory safety)? Not its missing module system? Not its ambiguous syntax?
You also confuse "simple" with "primitive" and perhaps "familiar". C surely is primitive, but how is it simple? Simple to use? No. Simple to implement? Not really. Has a simple mapping to the underlying hardware? That stopped being true three decades ago.
What you say is entirely correct; however Nimrod's effect system is not tied to any runtime mechanisms like a GC and provides lots of other aspects of safety. For instance you can ensure at compile time that a particular piece of code performs no database operations.
Also the effect system will improve the safety for concurrent programming quite a lot; coming soon in some of the next versions. (Sorry, no papers about it yet.)
UTF-32 strings roughly take up 4x more memory than UTF-8 strings and yet hardly solve anything: The proper toUpper("ß") used to be "SS" in German (nowadays there is an upper cased 'ß'). Other languages have other rules; i18n is hard, get used to it.
IMO Nimrod's UTF-8 strings at least make the programming errors easier to spot instead of the "mostly working but fails for edge cases" style that UTF-16 or UTF-32 encourage.