Nim 1.2(nim-lang.org) |
How did that work?
I do feel Nim embraces mutation more than other recent languages.
https://github.com/sergiotapia/torrentinim
Nim is a very interesting language, with a lot of upsides. It just needs that killer framework to get the ball rolling and allow devs to solve business needs quickly. Once that's done I think Nim will grow a lot! Tiny binaries, static binaries, fast, low memory usage, macros, compiles to C.
Recent versions also use this fancy thing: http://www.gii.upv.es/tlsf/
In addition there is active work on a swift like reference counting, lifetime based memory management option. This will be suitable for hard real-time use cases.
Java and Python are being pushed by Silicon Valley and universities, Go is being pushed by Google, Kotlin is being pushed by Google, C# is backed by Microsoft and some big companies.
Who can help Nim, or Crystal, or Rust or other new language?
I look at many of them from time to time, see interesting developments, see exciting things but I refuse to learn the languages, their ecosystem and frameworks from the fear I have I will lose lots of valuable time since I might not be able to earn my living using them.
Hoping we can open-source some of this stuff in the near future too to kind of show the world that Rust is ready.
Being a grassroot, community-driven project is a feature, not a bug.
However, I certainly agree with your "you do this because you _care_" sentiment.
Source: implemented dark mode for an application where the "sane css colors using variables" property was true.
So useVersion doesn't simply checkout the old codebase, but they still promise to maintain all prior version's bugs? Seems like a losing battle to me... why not just tell people relying on version 1.0 behaviour to use version 1.0 and create tooling to make sure switching between versions is easy (a. la. nvm)?
The idea is more like the gcc -std flag (gcc -std=gnu++11 for example). to emulate certain versions to ease upgrading.
One bit which I still hate is simply how imports work in Nim. My project pretty much has a header like file containing function and variable signatures which can be called from other files.
For someone used to modern languages, it just feels so archaic.
But overall it is still a fantastic language and I am excited to try the ARC gc
You mean how `import` works or are you using `include`? If the latter then I would strongly discourage you from using it.
As for the former, you can use `from module import nil` everywhere if you really want.
This is my person opinion here: Nim is part of the "new generation of system programming languages" from the last decade or so. Some other examples in this category include Zig, D lang, Go lang, Swift, Rust, etc...
The whole idea is to provide "modern high level" language features and ergonomics while still producing efficient low level code.
For Pythonistas, The familiar syntax is attractive to Python programmers looking for a more performant language (data science is a prime example.)
Nim is also attractive to lispers looking to move to a more traditional Algol or C like language while still keeping much of power and flexibility that they are used to from macros.
Many data scientists are familiar with Python. They can write similar code and will run much faster by default (or with very little tweaking).
Then, if that's not fast enough, The language is positioned such that you can optimize the code to a much higher degree than you can with Python.
I'm not saying that Python code can't be optimized, but there is a limit to the speed of python code even with optimization. At some point you have to drop down to a C extension (what Numpy, Pandas, etc... does) and then you are just writing glue code in Python to drive the C. You could also use one of the Python optimized compilers, but that has limits and edge cases as well. There is "developer friction" there.
In Nim you can just have the whole program in one language. The program can be optimized to the same level as optimized C code with no special tools. This is much less friction.
What's missing is the libraries. But that will come with time.
This is the first release to offer `--gc:arc` so there are still some rough edges, but I would follow @treeform's and @rayman22201's advice from sibling comments: give it a try, it might work for you without any problems, and if not - report it.
The long-term plan is to make it the default.
These comments make a lot more sense now.
But the more the merrier, so I look forward to its bright future.
Also: available to hire if anyone is looking to work with Nim.
I have written UI DSLs in Nim, as well as SQL DSLs. Only LISPy languages come close to the level of DSL you can do.
You could certainly write an expressive web framework in nim, but a django/rails sort of paradigm is not the way.
Nim feels as lightweight as Go, but with great syntax. The main thing holding me back now is the lack of libraries, but it's definitely on my radar.
1. no JVM (Kotlin Native isn’t considered a stable thing, or is it?),
2. subjectively nicer language,
3. An optional non-GC runtime upcoming (already in there as beta), which is interesting for low-memory applications... which in the time of the Cloud is potentially any application. The more (AWS) lambda time you can get for free, the better, right?
4. Writing command line tools. Practically nobody is writing them on Kotlin. Everybody’s writing them on Rust, though, for some reason...
Disclaimer, full disclosure: I’ve only read about Kotlin, of course, not written a single line. It seems like an excellent language, and if I had to do JVM work, I’d have it as a top3 candidate for sure.
var arr1 = [4, 2, 3, 6]
sort arr1
# Doesn't work
let arr2 = [4, 2, 3, 6]
sort arr2
You'll get a warning about the latter from the compiler (and nimsuggest for editors).To address your question, the only complete back end web framework for Nim that has significant traction (that I know of) is Jester. Karax for the front side. The Prologue framework looks interesting though.
When I say 'primitive GC', I mean Boehm, which is obviously decades behind the state of the art, but easy to get off the ground. GNU Guile uses it, for instance. Serious garbage collectors are tremendously complex, and are something less popular languages unfortunately tend to lack. I believe even D is miles behind Java.
Can't say I know much about Go's GC.
Edit Oops I misread, TLSF isn't a GC, it's an allocator. It sounds then like Nim doesn't have a proper real-time solution, does it? useRealtimeGC is actually a leaky reference-counting system?
It isn't acceptable to just permit memory-leaks in case of cycles. There's no way we'd ever see something like that in a serious JVM.
Unless there's some serious machinery to provide assurances against reference cycles, of course. Which sounds like an interesting research project, come to think of it.
Obviously nim is free to make implement whatever options they want, but it seems to me like every second spent triaging/fixing/etc bugs about not properly maintaining broken things (not to mention the end user time spent experiencing them and debugging them!) is time that could be better spent improving the language.
Additionally, a C/C++ compiler in an older standard mode would disable certain features, of course, but not completely: it's still able to give diagnistics in the vein of "this thing isn't valid with the current version setting, but it would be valid in C++17", for example. That's useful to a programmer.
That is, if we had a GCC version manager that worked the same way things like choosenim or rustup or pyenv or rvm or what have you work, I can guarantee you GCC will ship with an -std flag, because you can bet someone needs to compile a C89 codebase and wants the latest and greatest compiler smarts to do it. Same deal for Clang, or Visual Studio, or `zig cc`, or whatever.
Great example of this (that I just had to deal with this week, lol) is Wine, which mandates C89-compliant code, and yet absolutely benefits from any compiler optimization improvements introduced with newer versions of GCC.
You may not have an environment that allows switching compiler versions for other reasons.
Even Rust has a similar concept that allows gating of features like this. They call it "editions".
Don't you also need to understand the go package manager or Nim's? I don't see how this is different than learning Gradle.
It’s pretty liberating to put some text in a single file, pass that file to a compiler, and have a single executable binary.
A devolved workflow I know.
> nimble install docopt
> echo "import docopt" > test.nim
> nim c test.nim
Nim's package management isn't exactly rocket surgery. Even if you use nimble as a build tool it's still extremely straight forward: > nimble init
> echo 'require "docopt"' >> projectname.nimble
> echo "import docopt" > src/projectname.nim
> nimble build
Notice the lack of explicitly installing docopt, nimble build takes care of unmet dependencies.That's it! Now you know everything there is to know about Nim package management. (Not quite, but close enough)
That's only in the new --gc:arc which is still somewhat experimental. The old gc, --gc:markandsweep IIRC, does detect cycles, and has a deadline schedule (i.e. you can tell it "I now have 5ms, collect as much as you can"); But it has per-thread heaps, which means passing data between threads often entails a copy. You also have --gc:boehm (no cycles, shared heap), and --gc:none (no gc, you should take care of freeing memory yourself).
I myself am hoping that either kotlin or Scala can finish their native compilers or Graal can make compiling jvm bytecode trivial.
Additionally, Nim also has its own runtime, https://nim-lang.org/araq/ownedrefs.html.
Which most likely doesn't have 25 years of optimization algorithms, and monitoring tools, invested into it.
So "No JVM" isn't necessary an advantage.
IntelliJ would be still dog slow even if written in C.
Non stopping indexing files on every startup isn't something that changes with the programming language, or the slowness doing code completion on C and C++ code, despite usage from clangd.
There's also Kotlin JS, which targets the JS ecosystem, and comes with tools that let you import TypeScript type definitions into Kotlin, so you can easily interact with third-party JS modules.
A pure Kotlin library could easily be used on JS, JVM, and native/LLVM seamlessly. Which is pretty impressive. All your non-platform-dependent logic could be placed in a decoupled shared pure Kotlin library. Which avoid code duplication that is so common when you need web + iOS + Android client apps. (And the Intel Multi-OS Engine could be used to write your iOS app in Kotlin.)
Does it mean that startup is slow (possibly due to AOT)?
Does it mean that consumes a lot more memory than the equivalent C/C++/JS/Python/etc program? (I don't think so.)
Does it mean that code execution is too slow? (This hasn't been true for over a decade or close to two; the JVM's JIT is one of best ever.)
Does it mean the GC pauses are too painfully apparent? (I don't think this is true at all.)
Does it mean that users of JVM languages have a tendency to write code that is in inefficient/slow/bloated on average? (Again, I'd say this isn't true; and I've seen code to tend heavily more on the inefficient more so with dynamically typed languages in general.)
So, what really does "heavy" mean here?
(Lastly, while the core compiler tooling for Kotlin is probably reliant on the JVM, you don't have to use a JVM-based IDE for sure - VS Code (which is written in TypeScript/JS) should work fine as well.)
Java and React are fast by bringing a lot of sophisticated (heavy!) machinery. Nim and Mithril are fast by being small and simple.
For example, the JIT makes Java fast – eventually. But initially it's interpreted and slow, with the additional overhead of bringing up the JIT compilation machinery in the background. AOT compiled code reaches its normal speed from the start. So Java programs take a while to get fast, which makes them feel heavy.
Startup is slow. Java 11 is slower than Java 8 which is slower than Java 6. Class-data sharing can make it faster – sometimes. You still have to load all that data, so when it's not cached in RAM and you have a slow disk it's still slow. A smaller program is always fast to load. This makes Java feel heavy.
When it comes to memory, Java does clever optimizations like escape analysis at runtime so that the programmer doesn't have to bother with deciding between allocating on the heap or the stack. This can also make it fast in certain scenarios, after warm-up, but a language with explicit value types can be made fast from the start. (Which is why Project Valhalla is coming.)
You would just essentially need an installation step, where you compile the binary (maximally optimized for the architecture that it's running on), and save that to disk. All of the problems you described disappear with that -- no startup/AOT delay nor any JIT compilation delays.
Pre-compiling stuff is a small price to pay for the benefit of better-optimized higher-performance execution.
Another thing: you could do memory safety and other static analyses and security checks during the pre-compile/install phase. There's a lot of benefits to that.
For e.g. if you are able to statically verify and guarantee (ie mathematically provably) that the code will not commit any memory violations, then you could optimize away many of the bounds and other related checks. These sorts of verification must be done on the machine that is actually executing the code, since you can't simply trust a third-party, and must yourself verify such assurances/claims.
However, you were asking why people consider Java to be heavy. When people normally use or talk about Java, Java means a JRE derived from Sun's Java implementation. If you download Java to run the Kotlin compiler or IntelliJ, you're not downloading the Android runtime or some hypothetical AOT compiler - you're using something based on OpenJDK, which suffers from the heaviness I described.