
Nim – Natively compiled language with hot code-reloading at runtime [video] - Clyybber
https://www.youtube.com/watch?v=7WgCt0Wooeo
======
jamieson-becker
Nim is an amazing language. The syntax is cleaner (IMO) and easier-to-read
than Go and approaches Python in its readability, which is impressive for a
statically typed, compiled language[0]. The design is focused on performance
above all else, but it still has metaprogramming[1] and functional features.

However, Go and other languages have a huge ecosystem and many more libraries.
Nim only has a few web servers/frameworks, for example. Even if Nim's web
frameworks/servers (like httpbeast) are quite fast[2], they lack the
completeness that exist for other languages.

Until then, if you are looking for a _systems_ programming language, you owe
it to yourself to investigate Nim[3], alongside Go, Crystal, Julia, D, Rust,
Haskell, etc. The tooling is fantastic and the Nim compiler produces clean,
cross-platform C code (or JS[4]!) that can be automatically fed into gcc,
clang, mingw-w64, etc. It's a language that's undergoing rapid changes, but
almost all of the changes are in the libraries and it's exciting to see all of
the innovation there -- and as libraries increase and mature, it will become a
really compelling application language as well.

The community is extremely active, and issues are promptly dealt with. For
HNers, it's an opportunity to still make a huge difference by contributing to
a relatively young language, compared to getting drowned out by all the noise
in a more mature language community.

0\. [https://nim-lang.org/docs/tut1.html](https://nim-lang.org/docs/tut1.html)

1\.
[https://en.wikipedia.org/wiki/Metaprogramming](https://en.wikipedia.org/wiki/Metaprogramming)

2\.
[https://www.techempower.com/benchmarks/](https://www.techempower.com/benchmarks/)

3\. [https://nim-lang.org/features.html](https://nim-lang.org/features.html)

4\. [https://picheta.me/snake/](https://picheta.me/snake/)

~~~
echelon
Minor nit. Every language you mentioned with a GC is not a systems language.

~~~
sl1ck731
Go is a systems language. The term isn't confined to device drivers. It
includes platform/backend software such as web servers and things like message
queues or the Docker ecosystem.

The term is nebulous though.

~~~
echelon
That's wrong! Those fall squarely in the application domain.

By your argument Ruby and Python are also systems languages because they can
be used to write servers and job queues.

You're not doing real time programming with Go. Don't make systems programming
lose its meaning by promulgating this myth.

~~~
sl1ck731
Real-time programming can be done in any language, Java for example.

I think you're conflating writing device drivers/kernels with systems
programming, which includes those things but is not limited by them.

Regardless, the term's meaning can't be lost if its apparently this hazy.

~~~
zepolen
I don't think you understand what real time programming is.

~~~
sl1ck731
Enlighten me, please.

[https://www.aicas.com/cms/rtsj](https://www.aicas.com/cms/rtsj)

[http://blogs.windriver.com/wind_river_blog/2017/05/java-
on-v...](http://blogs.windriver.com/wind_river_blog/2017/05/java-on-vxworks-
using-micro-runtime.html)

~~~
echelon
This is swapping out the JVM. It's not even the same language at that point.

~~~
sl1ck731
Maybe it would be easier for both of us if you wrote the definition for real-
time or systems programming, rather than just saying something isn't one or
the other.

~~~
crimsonalucard
Look, a good systems language should have predictable assembly instructions
that the code compiles into. You should be able to literally with your eye map
from code to asm and jump back and forth in a systems level language. GC
enabled languages don't have this property as the assembly would be littered
with GC code to clean up things. You won't be able to map back and forth.

You will note that rust advertises themselves as a systems level language and
it is deliberately designed with the term zero cost abstraction. All this
means is predictable asm from code. No black magic. Rust is advertised as
systems level and this is the property that enables it. I hope that allows you
to understand what it means to be systems level.

I truly believe that you are completely wrong and only few languages nowadays
are system languages without a GC. C++, C, D (when used without the GC) and
rust are examples. All the other languages you listed aren't.

~~~
sl1ck731
This is what I was looking for, and I truly believe you are completely wrong
as well.

I follow the line of thinking that includes utility software and backend
services/platforms as described here:

[https://en.wikipedia.org/wiki/System_programming_language](https://en.wikipedia.org/wiki/System_programming_language)

Hence, the word has different meaning from person to person. So there is no
wrong, or at least it exists on a spectrum, and everyone complaining about the
original comment's word choice is just jerking their ego off.

~~~
zepolen
Mate you said:

> Real-time programming can be done in any language, Java for example

That's absolute bullshit. Please get a Computer Science education before
making yourself look like a fool.

~~~
dang
Attacking another user like this will get you banned here. Please review
[https://news.ycombinator.com/newsguidelines.html](https://news.ycombinator.com/newsguidelines.html)
and don't do it again.

Edit: we've had to warn you about this repeatedly. Please fix this so we don't
have to ban you.

------
nonsince
To add another existing implementation of this, Naughty Dog's Lisp-based
assembler could do hot code reloading, and that workflow was extensively used
for developing Jak & Daxter. Plus, obviously any JIT'd language can do this
but it's fair not to count that. Still, that's just splitting hairs and it's
really exciting to see this in Nim. It's a great language and it's a shame
that it doesn't seem to have found a real niche yet.

[http://www.codersnotes.com/notes/disassembling-
jak/](http://www.codersnotes.com/notes/disassembling-jak/)

~~~
OskarS
There are many game engines do some form of hot code reloading of the game
scripting code (as opposed to engine code). Unity supports it for C#, for
instance (though it's finicky, you have to program with hot reloading in
mind).

~~~
pjmlp
And Unreal does it for C++ as well now.

------
drmeister
IMHO - you should learn Common Lisp - it solved the problems described in the
talk (Nim can't redefine types on the fly) decades ago. In Common Lisp you can
redefine _everything_ on the fly. You can change types (classes) in a running
system and objects in memory that have the layout of the old class get
upgraded automatically when they are used. Programming with Common Lisp in
Slime/emacs is an amazing experience that will spoil you for other languages.

------
cmm
I see that at this point in time Smalltalk and Lisp machines have become
completely memory-holed (oh wait, Smalltalk & Lisp are interactive, thus
"interpreted", thus obviously not compiled! I'll show myself out)

~~~
IronBacon
Don't know about Smalltalk but there are numerous CL compilers...

~~~
bitwize
Smalltalk is compiled to bytecode.

~~~
gokr
Smalltalk is a family of dialects and implementations. Most of them are indeed
compiled to bytecode which is then executed by a JIT VM. Most of them use the
"image" concept where you are always in runtime like in a classic Lisp, and
yes, the VM handles shape changes etc etc. But some Smalltalks actually have
other characteristics, like non JIT or even compiling via C (Smalltalk/X does
that I believe).

------
quangio
+1 Nim is a really nice and simple language. Extremely easy FFI and Python-
like. For me, using Nim and Julia to write small "scripts" for my data science
(student) works (processing 10Gb-20Gb of data) makes me feel quite productive
compared to something like Go (too `ugly` for me), Python (too slow)

~~~
everdev
Are there any Nim benchmarks vs. Go, Crystal, Python, Rust, etc.?

~~~
maow83jejj
You can find them although they tend to be out of date and/or piecemeal. I
think they're still useful.

For example:

[https://github.com/drujensen/fib](https://github.com/drujensen/fib)

[https://gist.github.com/sdwfrost/7c660322c6c33961297a826df4c...](https://gist.github.com/sdwfrost/7c660322c6c33961297a826df4cbc30d)

[https://github.com/kostya/benchmarks](https://github.com/kostya/benchmarks)

My general sense is that Nim is most competitive as an alternative to Python
and/or things like Julia, in that it's as expressive and easy to understand as
those, but has performance closer to C or Rust than something like Python.
Julia is similar to Nim but I think Nim seems cleaner in its implementation
overall, and targets much more general use scenarios.

I've been really impressed by Nim. There are some little things that have
irritated me, like case insensitivity, but I wish it got more traction in the
community. Right now the only thing that it doesn't seem to have going for it
is library support. For the numerical applications I do I'd prefer it over
everything else, except everything else has huge resource bases, so something
that's already packaged in those languages would have to be done from scratch
in Nim, which isn't feasible.

~~~
0xdeadbeefbabe
Isn't the stdlib problem made less of a problem by the easy FFI to C? (it
wasn't easy last time I tried btw)

------
naasking
Could be a cool feature, but I wouldn't say "first". Been done in C for years:

* Safe and Automatic Live Update for Operating Systems, [https://www.cs.vu.nl/~giuffrida/papers/asplos-2013.pdf](https://www.cs.vu.nl/~giuffrida/papers/asplos-2013.pdf)

* Automating Live Update for Generic Server Programs, [https://www.cs.vu.nl/~giuffrida/papers/lu_tse16.pdf](https://www.cs.vu.nl/~giuffrida/papers/lu_tse16.pdf)

And I'm sure hot code reloading has been done in Forth for decades.

------
zevv
Can't recommend this enough: Nim is a very low-friction language with
performance in the C/C++ range, also offers introspection and metaprogramming
with a very powerful macro system.

------
interfixus
Whenever I've been working in Nim, going back to other languages is always -
codewise - a letdown. Alas, I often _must_ go back, almost always for the same
reason: The lack of libraries (and || or) attendant documentation. One doesn't
always have the time, inclination, or ability to work everything up from
scratch.

Otherwise, it's such an overwhelmingly pleasing toolset to work with. Clean
code, ultrafast compilation producing rocksolid executables as small and tight
as you care to make them. Joy all around.

~~~
canada_dry
> The lack of libraries

Yup. It's too bad there has been no en-mass conversion/import of popular
libraries.

The thing that makes python such a terrific swiss-army-knife is that there are
libraries available for just about every imaginable use case.

------
dunefox
Afaik Common Lisp would be the first, wouldn't it?

~~~
vthriller
The answer to that would depend on the CL implementation, since not all of
them can do AOT compilation.

~~~
jlarocco
Not really...

It's in the CL standard, and compliant implementations support it. SBCL,
LispWorks, Allegro, CCL, and others all do AOT native compilation, from the
REPL and via eval (which should be avoided, in any case). ABCL does AOT
compilation to JVM bytecode, and Clisp to its own bytecode.

It's a cool feature for Nim to have, but claiming to be the first makes them
look bad.

~~~
lispm
Several Lisp implementations even do similar things which were shown in the
video: compiling Lisp to C/C++, then calling the C or C++ compiler, then
loading the compiled code into a running Lisp, replacing/extending code.

For example ECL. The maintainer of ECL also showed how to write inline C in a
Lisp function and compile/load that in a REPL - using only a couple of lines
of code - basically a C REPL inside Lisp.

[https://www.reddit.com/r/lisp/comments/bgwtsh/fun_ecl_hack/](https://www.reddit.com/r/lisp/comments/bgwtsh/fun_ecl_hack/)

------
ungzd
I remember using "edit and continue" in Visual C++ 6, seems that this feature
still exists in newer versions[1], but I don't know what limitations it has.

[1] [https://docs.microsoft.com/en-
us/visualstudio/debugger/edit-...](https://docs.microsoft.com/en-
us/visualstudio/debugger/edit-and-continue?view=vs-2019)

~~~
Jach
That's a great doc page. In the "Supported Code Changes" for C++ and C# it has
a helpful list of what _isn 't supported_ too. Java also has the feature in
the JVM (IDEs / mvn-hotswap plugin can hook into it), but it's similarly
limited. There's a proprietary java agent called JRebel that significantly
expands the support ([https://jrebel.com/software/jrebel/features/comparison-
matri...](https://jrebel.com/software/jrebel/features/comparison-matrix/)),
and a couple open source versions I haven't tried, but it's still got some
limitations.

It's worth a comparison to Common Lisp which thought about this feature a lot
more and built it into the language rather than having it hacked in by
external tools... e.g. if you redefine a class definition in Java say to add a
new storage field, well you can't using default hotswap but with JRebel you
can, but still any existing objects will continue to point to the "old
class"'s code and the new field won't be available... Common Lisp defines a
generic function 'update-instance-for-redefined-class that you extend before
you do the class edit, and now your existing objects will work with the new
code.

------
revskill
Nim is an interesting language. Main features:

\- Type system: Strong and static typings.

\- Support Generics (Unlike Go)

\- Support Modules (Unlink C++)

\- Multiple and optional GC.

\- Metaprogramming support.

\- Executed binary.

What excites me most is the efficiency as C.

I hope it'll get mature more this year. At least for the Javascript backend,
so that i could write Nim for frontend (with bindings for popular JS
frameworks like React, Vue,..) , too.

~~~
pjmlp
C++20 does support modules.

------
lelf
(Natively compiled) Erlang might want to have a word with you.

~~~
teilo
Educate me if I am wrong, but there are natively compiled Erlang modules, but
no longer any natively compiled Erlang. It only runs on the BEAM, and ever
since BEAM/C fell out of use in OTP R5 no native code is generated.

~~~
strmpnk
BEAM is still present but HiPE interfaces with it using some specific ABI that
allows mixing AOT compiled native modules (just machine code) and the BEAM
register machine. I'm not sure if there are new caveats as I regard HiPE as a
compatibility feature rather than something under active development (I may be
wrong but it seems to fail to compile all of OTP's Erlang code now).

The overhead of that context switch is a bit high but it allows the code
loading facilities of the BEAM to reload HiPE compiled modules. This works
because all processes yield to the scheduler, which acts as a kind of code-
swap safe-point. The usual module-local vs module-remote call rules apply here
when old versions are purged.

~~~
anthony_doan
>
> [http://erlang.org/download/otp_src_22.0-rc3.readme](http://erlang.org/download/otp_src_22.0-rc3.readme)

It's in active dev. ctrl+f "hipe-3.19"

> I may be wrong but it seems to fail to compile all of OTP's Erlang code now

See OTP-15596.

------
azhenley
Nim enticed me to create my own systems-ish language:
[https://github.com/AZHenley/knox](https://github.com/AZHenley/knox) It is
still just a toy and in the early stages.

It’s been fun. Thanks for that, Nim.

------
peheje
I really like Nim. I hope the threading interface improves though, I found it
lacking last time I checked about half a year ago.

~~~
hathawsh
I'm curious, what more are you looking for? From the nim manual:

"Each thread has its own (garbage collected) heap and sharing of memory is
restricted to global variables. This helps to prevent race conditions. GC
efficiency is improved quite a lot, because the GC never has to stop other
threads and see what they reference. Memory allocation requires no lock at
all! This design easily scales to massive multicore processors that are
becoming the norm."

To me, that sounds perfect for writing typical apps.

~~~
KallDrexx
How does Nim do thread-based GC if an object is shared across threads? Does it
not allow that sharing references cross-thread (not sure how it would without
lifetimes though)?

~~~
hathawsh
If I understand the Nim manual correctly, there is no sharing of objects
across threads. Instead, Nim assumes message passing. When you communicate
between threads, Nim makes a deep copy of the message.

In theory, that strategy could be very inefficient if the messages are large,
but it also means the garbage collector is unaware of threads and therefore
simpler.

~~~
btym
>there is no sharing of objects across threads

You can message-pass a pointer if you are sure the referenced object won't be
GCed.

------
pjmlp
In addition to several other examples.

C++ did it in the 80's with Lucid C++ and the ill fated Visual Age for C++
v4.0.

Eiffel also thanks to its MELT VM.

------
jdc
Looks like it's still a pre-release feature at this point.

Hot code-reloading part of the talk:
[https://youtu.be/7WgCt0Wooeo?t=1519](https://youtu.be/7WgCt0Wooeo?t=1519)

RFC: [https://github.com/nim-lang/Nim/issues/8927](https://github.com/nim-
lang/Nim/issues/8927)

Code:
[https://github.com/onqtam/Nim/tree/hcr-1](https://github.com/onqtam/Nim/tree/hcr-1)

~~~
narimiran
> _Looks like it 's still a pre-release feature at this point._

It has been merged to devel branch: [https://github.com/nim-
lang/Nim/pull/10729](https://github.com/nim-lang/Nim/pull/10729)

~~~
akavel
What's the situation with the TODOs mentioned in the presentation? Primarily,
the missing standard library support cleanup ("Currently no real-world project
can be built with HCR")?

~~~
onqtam
those issues will hopefully be addressed in the coming months - when I get the
time

~~~
akavel
Cool, and thanks for all the work! Keeping fingers crossed that you'll manage
to make the final push!

------
squarefoot
+1 for Nim. I'm dreaming some day to see a RAD where Lazarus generates Nim
code with full LCL support; that would be a truly killer dev system for
desktop apps. Lazarus is already a wonderful RAD, one can build native apps on
a *PI board and run them directly on that target; Nim support would make it
even greater.

~~~
pjmlp
Not sure what that would buy over Object Pascal and the plethora of libraries
develop since Turbo Pascal/Apple Pascal days.

~~~
squarefoot
Admittedly not much on the technical side beyond new languages constructs etc,
but the main benefit would be ending for good the wrong argument "Pascal is
old therefore Lazarus sucks". Like 20 years ago I've written network code in
Delphi that would send and receive binary data between different endianess and
word size machines, so I had to align them and manage data down to bitfields
in the Pascal equivalent of C unions, that is, the language offers enough
bullets and rope to hang then shoot oneself in the foot just like C, but every
time I talked with someone about Delphi and later Lazarus, it was just about a
matter of minutes before the inevitable "yeah, but Pascal is old".

~~~
pjmlp
Here is an answer for them, all mainstream languages in use today are at least
20 years old.

And their beloved C is reaching 50 years old.

------
bjourne
I only skimmed the video, but I couldn't see him describing it doing type
reloading. Perhaps that is what he is planning on implementing. It is very
hard to implement (especially if you can't control the compiler) but very
useful for general code reloading. Of course everything is relative, and even
if I think it is "very hard" it might be a weekend project for someone else.
Generally though, code reloading is one of the hardest things to implement in
a vm.

The holy grail of code reloading is to upgrade the code of a HTTP server while
it is running and without disturbing any requests being processed. Very few
languages except for Erlang are able to do that correctly. Some languages
_claim_ to support that, but when you experiment with them you discover
"quirks" making it impossible in practice.

~~~
jerf
If you put your mind to it just a bit (i.e., I wouldn't call this "automatic"
exactly but it's not too hard to use the support the language, runtime, and
libraries have), Erlang can even do a harder thing, which is update the code
handling a given socket connection or something live, in a principled manner,
while never dropping the connection.

Since HTTP is transient, it's actually a bit easier than a raw socket since
you can expect it to go away soon, or even in the case of HTTP2, you can often
expect to just close a socket as long as it's not currently active and get
away with it. Many languages can smoothly upgrade an HTTP server by handing
off a listening socket to a new process with new code. But even that won't
save you for live sockets, because even if you hand off the socket, you
haven't got a clean mechanism for handing off its accompanying state.

Several interpreted languages can sort of do this, but I'd call it in an
"unprincipled" manner by just slamming new code in place and hoping for the
best. Erlang explicitly upgrades the gen_* instances and you can provide a
function for converting the old state to the new state cleanly.

~~~
bjourne
> Erlang can even do a harder thing, which is update the code handling a given
> socket connection or something live, in a principled manner, while never
> dropping the connection.

That's what I meant. :) Hot reloading when nothing is "in flight" isn't so
hard. The Erlang the Movie example, hot-fixing a PBX without disturbing phone
calls in progress (real time requirements!), is really hard.

~~~
jerf
Ah, my apologies, because when you said "The holy grail of code reloading is
to upgrade the code of a HTTP server while it is running and without
disturbing any requests being processed." I thought you were referring to the
ability of the BEAM VM to also have multiple versions of the same gen_*
running, so that old requests can still be running on the original code while
the new requests come in on the new code. This is in contrast to the things
that came to mind like Python, which technically can replace a function
reference live, but there's no such ability to partition who's in the old vs.
new space like that, so it's too dangerous to be practically used (or at least
not without a _lot_ more supporting code).

BEAM's really got it all on this front.

------
KallDrexx
I can't tell from the video if the hot code reloading is meant for production
workflows or dev only workflows. For example being able to use HCR to update a
long-lived TCP server (like a video streaming server) without disconnecting
clients.

It seems like it forces pointers for everything which, which seems to me will
break a lot of optimizations (like inlining)

 _Edit_ : I guess production use is limited anyway since you can't add,
modify, or remove types with HCR yet.

 _Edit2_ : I just saw in the video they said it's 2x times slower, so
definitely can't be used for a lot of workflows in production. Still useful
though.

~~~
onqtam
that is indeed the case - HCR is meant mainly for development. But if you can
stomach the x2-x3-x4 slowdown for production nothing would stop you

------
wdroz
You can hotpatch C function too :
[https://news.ycombinator.com/item?id=11403263](https://news.ycombinator.com/item?id=11403263)

~~~
kazinator
Loading and unloading dynamic libraries (dlopen in Unix, LoadLibrary in
Windows ...) and operating system kernel modules are also examples of hot code
reloading in C.

------
benj111
Can someone give me some pointers to reading material on this.

I'm aware of hot code reloading for interpreted languages, google just gives
links to web page loading. I'm also aware of it at the OS level. I don't
really understand why you'd want this in a compiled language.

~~~
detaro
If you understand why people have it in interpreted languages, why do those
reasons not apply to compiled languages?

~~~
benj111
Because for an interpreted language you can use it for interactive
development. I had thought different reasons would apply to a compiled
language but judging by the other replies obviously not!

~~~
lispm
One can use compilers for interactive development, too. That's not a feature
of being 'interpreted'.

~~~
benj111
Interpreters tend to have repls, which tends to influence how development
happens. I'm not stating an absolute law though.

I think you may be misinterpreting my original question. It was asked out of
ignorance, it wasn't a challenge. I was hypothesising some kind of self
modifying code, or realtime adaptive optimising or something. I was attempting
to show you my current level of knowledge so you could ELI7 instead of 5 :)

~~~
akavel
It's mostly just that the feature is always useful (that's why it's present so
often in interpreted langauges), but _muuuuuch_ harder to do for non-
interpreted languages. Notably, a subsequent goal for the Nim feature is
indeed to add a full-blown REPL to Nim too, I believe. Also, worth to note
that some non-interpreted languages do also have REPLs, e.g.: Haskell, OCaml,
C++ (! — see CLING).

~~~
benj111
I'm aware of plenty of exceptions myself.

Forth, and I've even come across an ASM REPL.

Theres exceptions the other way, Awk is interpreted but doesn't as far as I'm
aware have a REPL, Sed doesn't either. But then both of those have varying
implementations, so there could be exceptions to the exceptions.

------
gregwebs
Haskell (a compiled lanaguage) has done hot code reloading with ghci for a
long time. Facebook actually deploys in production by reloading.
[https://simonmar.github.io/posts/2017-10-17-hotswapping-
hask...](https://simonmar.github.io/posts/2017-10-17-hotswapping-haskell.html)

