Hacker News new | past | comments | ask | show | jobs | submit login
DotNetAnywhere: An Alternative .NET Runtime (mattwarren.org)
147 points by matthewwarren on Oct 20, 2017 | hide | past | favorite | 24 comments

I'm the original author of DotNetAnywhere.

For all its flaws (and there are quite a few) it was a very interesting learning exercise, and it worked better than I ever really expected ;)

I don't really intend to ever do any more work on it, especially now that there are open source "real" implementations. But it's been nice to see it used in Blazor :)

If you have any questions about it, please ask.

Firstly, thanks for writing it!

Here's my questions (assuming you can remember from 6+ years ago):

1) What was the hardest part of .NET to understand and/or implement?

2) Were there any surprising things about the .NET runtime/specification that you learnt about along the way?

3) Should JIT.c really be called Interpreter.c :-)

My memory is a little vague...

But I'm fairly sure the hardest part to implement was the support for generic types/methods. It made all the code that handles types way more complex (as expected I suppose!), and there's definitely a bug or two remaining. Correctly handling open/closed generic types and construction of types from generic arguments was painful. It didn't help that I initially implemented only non-generic type support, then had to hack generics into it. Were I to start again I'd implement the whole thing in a generic-first way.

The design of classes/structs and they they interact with generics is nice. And the `constained` IL prefix is a really neat optimization to avoid boxing. The use of type-agnostic CIL instructions (e.g. `add` can work on int, float, ...) is also a nice touch.

JIT literally stands for "Just In Time". It doesn't say what it's actually doing just-in-time ;) So (in my opinion) JIT.c is correct. It's translating CIL opcodes to dna-internal opcodes, which it does just-in-time just before a method is executed for the first time. The reason it does this at all is because there are many things to resolve when working from CIL that it's much better to do just once rather than every time a method is executed. A simple example is method references, which are by name in CIL, but are a simple pointer in dna-internal opcodes.

Thanks so much for your replies, very informative.

r.e. 'JIT v Interpreted', I should've checked wikipedia, it backs up what you're saying:

> Most often this consists of translation to machine code, which is then executed directly, but can also refer to translation to another format

From https://en.wikipedia.org/wiki/Just-in-time_compilation

This may be a selfish request but would you consider moving the original repo to it's own organization? The canonical repo gets a higher placement in search results and for link juice.

Plus if you were to move it to it's own repo/organization, it would allow the forks to submit their changes upstream and have one master repo instead of multiple forks with their own changes.

I probably won't get around to doing this.

But someone else is very welcome to do so :)

Pinged you on GitHub but you'll need to initiate the transfer to move the repo: https://help.github.com/articles/transferring-a-repository-o...

The main reason i move from c# to “typescript js” because c# not working on client side web. I love c#, maybe if dotNetAnywhere is ready for production, i start using c# again. Keep the good work. Maybe someday aspcore, xamarin and dotNetAnywhere. It would be awesome

Sadly DotNetAnywhere definitely isn't ready for production, and by the sounds of it Blazor is not either (I'm not involved in Blazor).

It's possible some of the other DNA forks mentioned here may be more suitable for production, I'm not sure.

But because those are weekend projects. There are enough microsoft or microsoft-related people getting excited about it that I hope microsoft will put its strength behind a production version. That would certainly make a lot of sense.

There are a couple partial .NET runtimes reimplemented in JavaScript rather than compiled to WebAssembly; they are usually tied in with C# -> JavaScript generators.

https://github.com/nikhilk/scriptsharp was kind of the granddaddy of them all, with no updates since 2013.

https://github.com/bridgedotnet/Bridge Saltarelle was acquired by Bridge.NET mid-2015: https://blog.bridge.net/bridge-net-acquires-saltarelle-c77a9... and seems to be going strong.

https://github.com/SharpKit/SharpKit went the other way and is now open source, but original L/GPL/references to licensing for commercial use may have limited growth; it is now MIT.

http://jsil.org/ mostly demonstrates games, and focuses on translating MSIL bytecode rather than any specific language or runtime.

I wrote an CIL-to-JS translator too:


It's not complete, certainly not usable for anything remotely real, but could handle quite a bit of C#. And was fun to work on :)

What I find most impressive about the DotNetAnywhere runtime is that it was developed by one person and is less that 40,000 lines of code!!

Nice write up, thanks. I wasn't aware of this project, it is very impressive. Does anyone know of similar projects for .net or Java?

There's IKVM, which is a managed JVM written in C# and is also capable of converting Java bytecode to CLR bytecode.


IKVM is feature-complete enough to remain useful for quite some time (with the full .NET framework), but keep this in mind:

The End of IKVM.NET | https://news.ycombinator.com/item?id=14174774 (Apr 2017, 108 comments)

Had I read an article opening with the sentence: «Here is a .NET runtime alternative which is however 100 times slower…», I would have quickly dismissed it, shame on me. This article is right, the DotNetAnywhere code really seems a gem, well worth to study!

> Had I read an article opening with the sentence: «Here is a .NET runtime alternative which is however 100 times slower…», I would have quickly dismissed it

I deliberately didn't start with Benchmarks, pretty much for that reason! Plus I put a huge caveat in before I showed the results.

> This article is right, the DotNetAnywhere code really seems a gem, well worth to study!

Glad you think so as well, that's exactly the reason that I wrote about it. It's relatively unknown and if nothing else it's a really useful resource (whether it's suitable for production is another matter)

run .Net in your browser via DotNetAnywhere in wasm: https://github.com/aspnet/blazor-hackathon (interpreted) https://www.youtube.com/watch?v=MiLAE6HMr10

Great suggestion, this is probably the killer app for this. I heard that the Mono and .NET teams are working on a new linker that should also help bring down the bloat, and help make .NET via WebAssembly less ridiculous in terms of overhead.

I have no idea if it would be compatible with DotNetAnywhere


The memory issues with DNA are frighting. If Chrome didn't hog enough of your ram before... it will NOW! Bwahahahahaha!

> The memory issues with DNA are frighting.

Which memory issues do you mean? The items that are covered in this section http://mattwarren.org/2017/10/19/DotNetAnywhere-an-Alternati... ('Garbage Collector') or something else?

Yeah, trusting the GC - reading the original author's comments on it:

> Mind you, the whole heap code really needs a rewrite to reduce per-object memory overhead, and to remove the need for the binary tree of allocations. Not really thinking of a generational GC, that would probably add to much code. This was something I vaguely intended to do, but never got around to. The current heap code was just the simplest thing to get GC working quickly. The very initial implementation did no GC at all. It was beautifully fast, but ran out of memory rather too quickly.

Yeah, the GC code is certainly not optimal (in terms of memory usage), but I don't know if that means you can't trust it.

At least in the simple tests I did it behaved as expected, but I know that testing a GC for correctness is not a simple task!!

>What I find most impressive about the DotNetAnywhere runtime is that it was developed by one person and is less that 40,000 lines of code!! For a comparison the .NET framework Garbage Collector is almost 37,000 lines.

Keeping the code base small is a double edged sword. The trouble with everything going web-based these days is that script kiddies (myself included) should have some awareness of how memory is being managed and when to worry about holding IEnumerables in memory. Your write-up here is interesting and it's the first I've heard of Blazor. This is all very fascinating you have me reading the codebase now.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact