Hacker News new | past | comments | ask | show | jobs | submit login
Introduction to the Common Language Runtime (2007) (github.com/dotnet)
143 points by StylifyYourBlog on Feb 7, 2015 | hide | past | favorite | 61 comments



Also known as The Best Virtual Machine. It would be nice to see the 64-bit Mono vs JVM vs V8 (or whatever monkey it's called this time) in a year or so. .NET CLR was already destroying every other on Win (even before RyuJIT and SIMD and native compilation), now Linux will be covered as well.


I'd like to hear this "best" substantiated against HotSpot. I enjoy writing code on the CLR, but I'm not aware of strong performance arguments in its favor relative to HotSpot.


That's kind of the million dollar question. It's always been faster than HotSpot... On Windows. And no-one cared. It'll be very interesting when people start to get some sense of the relative performance characteristics on Linux.

It's a hard problem, though. For instance, async IO is relatively faster on Windows vs sync IO. Whilst threads and processes are pretty expensive on Windows compared to Linux.


I think the JavaScript virtual machines are amazing. Thanks to browser speed wars, they pulled out a trick that I would not have thought possible - making JavaScript fast as hell.

Calling V8 "whatever monkey" is a bit ignorant.

Oh, I haven't said that JavaScript is a good language :)


I believe the comment meant V8 and {Spider,Trace,Jäger}Monkey (the Mozilla JS engine), which nowadays even beats V8 in some benchmarks.

http://en.wikipedia.org/wiki/SpiderMonkey_%28software%29#Tra...


Unfortunately it pushed the industry on the wrong path. Now everyone is coming app with transpilable super-sets and some folks are even pushing the unmaintainable code to the previously safe server-side (node, meteor etc.).


Yes.

Just look what Lars Bak did with JavaScript.

If he would work on the CLR, things could get really awesome.


You mean it could become as awesome as the HotSpot JVM, which was originally based on the StrongTalk VM for SmallTalk, which was in turn based on the Self implementation from Sun Labs? (hint: Lars Bak worked on all of the above)

http://www.strongtalk.org/ http://www.selflanguage.org/


I don't know how much hacks he had to use for the JVM and V8 that could be left out in the CLR.

AFAIK he didn't create those things from scratch, he had to use the Java, SmallTalk, Self and JavaScript specs that were already out in the wild.


JavaScript code is not unmaintainable.


Don't forget that JavaScript is singlethreaded, which makes a lot of things (e.g. GC) easier. I think if JVM or CLR was purely singlethreaded they would gain some more speed.

Web Workers don't as multithreading, they are more like isolated processes than threads.


".NET CLR was already destroying every other on Win "

Really? Care to provide some details?


interesting. usually the top comment is a little more substantial than an unsupported adversarial statement of opinion.


You are wholly correct but even still, sadly, you can expect a barrage of down votes for stating the truth.


From the article: "A GC is necessary to provide memory safety guarantees. [...] For any programs that need heap-style memory allocations, if you want to guarantee memory safety, you need a GC."

The main clame to fame of Rust is providing memory safety without a GC. Is the quote wrong, or is the quote still right because using a few unsafe blocks is unavoidable in practice? I haven't used Rust yet and know almost nothing about the language, so I'd be glad if someone could enlighten me.


You will always need a kind of GC if you start allocating things on the heap. This is because, in some cases, it's impossible for a human or an algorithm to know statically where a memory can be deallocated (you could solve the halting problem if you had a such algorithm, yet the halting problem has been proven unsolvable).

The GC can be very primitive such as in Rust ou C++11 by using reference counting. Reference counting is not a static allocation.

What Rust introduces is memory safety for statically allocated data. That's, the type system will prevent you use a reference/pointer to data a which has been deallocated.


Thank you for bringing this up. Rust does indeed use GCs when it is unable to perform static lifetime analysis, or perhaps more importantly, when the restrictions imposed by the lifetime analysis prove too restrictive for the programmer to solve a given problem.


If you use Rust for any length of time, I think you will find that you almost never need reference counting. You are right that Rust's borrow checker cannot always determine when memory needs to be freed, but the point at which that occurs is much more distant than "when you need to allocate on the heap."


A GC is necessary to ensure memory safety in the face of arbitrary heap graphs. Rust isn't a counter-example. You can't express arbitrary structures with owning and borrowed pointers. For those cases, Rust has GC (well, reference counting, a sort of GC), as well as "unsafe" and raw pointers. For example, to code a self-managing double linked list in Rust you need either RC or use a raw pointer and a few "unsafe" blocks.

This is not a criticism of Rust. I think it's a really interesting point in the design space. But there's no free lunch in memory management!


That's only somewhat true. You can express arbitrary graphs pretty easily with an arena, which has some similarities to GC in terms of how you use it but flat out isn't garbage collection (unlike reference counting) or unsafe (at least, not after an incoming Rust patch lands). There has also been discussion for some time in the Haskell community around the feasibility of a non-garbage collected implementation of Haskell (the consensus seems to be that it is doable, though perhaps not wholly practical).

More generally, Rust is not the final word in type systems around data structures, and for more complex ones there are more complex type systems.


Owning pointers, regions, arenas, etc, are various ways to take advantage of special cases in the correlation of object lifetimes. But here's no general solution that isn't GC. For example with arenas, you won't be able to reclaim any memory if your memory graph has nodes with uncorrelated lifetimes.

Consider, for example, a double-linked list that grows to a certain size, then every second a random node is deleted and a new one is inserted at the beginning. You can't represent the double-linked list with owning pointers, and while you can represent the list in an arena, you can't reclaim any memory until the whole list is deleted.


There was a reason I included the second paragraph. There are type systems that can handle intrusive data structures. However, they aren't used in any mainstream language (affine types in Rust is already a major achievement).


I think Rust demonstrates the quote is wrong, but the article was written in 2007, before Rust was public and well before the core system of borrow- and "lifetime"-checking was implemented for it, so it wasn't "obviously" wrong at that time. Also, Rust does provide reference counting pointers and these are sometimes necessary; this can be considered a form of GC, although I have a feeling its not in the spirit of the quote.

(I believe there were some research languages around that tackled this sort of task, but I'm not sure how many tried to tackle the general heap.)


I'd be surprised if theories of static memory safety weren't well-developed by 2007. They merely weren't in any practical scope for the CLR.


"To ensure memory safety [given that you can't guarantee in the language layer that the bytecode we'll be operating is safe] you need a GC"

Rust invalidates the bracketed assumption. It's been known this is possible for a long time, but Rust is the first time a language with this capability has hit semi-mainstream audiences. C# sure doesn't do it, VB certainly doesn't do it!

Ultimately it comes down to a promise of conceptual cleansliness from the entirety of a language Frontend. It's a big commitment.


Isn't this saying that because the MSIL is generated from C#, VB.Net, F#, etc, that there can be no guarantee? As far as I know, Rust isn't compiling to a CLR, so the GC in .Net is happening at a lower level than the language, it's happening in the runtime.


GC is almost certainly best handled in the RTS if you're going to expect to have one. In theory, Rust could pick MSIL as a new target and then they'd pay overhead for a GC which is not useful at all.

Alternatively, due to the existence of the GC as a given in the CLR, it might be that manual memory isn't exposed (as well or as nicely) in the MSIL making the idea of targeting Rust to it kind of silly. I have no personal clue.


Since you can compile C and C++ to the CLR you can completely circumvent the GC if you want/need to. Interoperability with other CLR languages might be a bit hard, then (which raises the question on why target the CLR at all).


That's why Rust is so important. It demonstrates that it is possible to drop to the lower-level concepts which do __not__ need GC for memory safety, and then build the "easy" abstraction on top of them.

I suspect that we will see more languages like Rust in future, because Rust has essentially proved the feasibility of the ownership model with working implementation.


Very nice. I'm wondering and hoping that Microsoft will start releasing design/architecture documentation and walkthroughs. Something that's sorely lacking from most open source projects is any sort of documentation to help would-be contributors get up to speed and wrap their heads around things. On a lot of smaller projects it's not a huge deal, but some of the new dotnet foundation stuff is MASSIVE.


Yeah this is great. I'm really looking forward to detailed docs and explanations of some of the more low level and not-so-publicly understood parts.

For instance, AFAICT, the whole double locking initialization question doesn't have a sold public answer. It's unsure that "myfield = new Foo()" is totally safe if the constructor throws. Obviously that'd be a huge flaw if not safe, but even top C# experts don't seem to be sure. With a fully open source CLR and docs, we should be able to figure this stuff out, rather than finding a few things of blog posts from 2004 and guessing.

We could also learn why some things are the way they are. For instance, why can you lock (Monitor) on every object? The syncblock on each object can't be free, so why is this encoded into each object (or even available at all), versus dedicated sync objects (which are what gets used in practice, anyways).

And maybe someone will provide much needed enhancements, like a way to effectively use the stack when safe. Or maybe some research projects will add advanced type features, which spark the way forward into the actual implementation.

I'm very much looking forward to this and really hope it marks a new era beyond hassle-free use on Linux.


Just to point out that, as much as the CLR was specced as cross-language, it's damn hard to run Java on it, Python and Ruby are abandoned, no-one's even tried Haskell.


Isn't this a general problem of cross-language VMs? Different languages need different object models, and different data representations. [0] At least according to one Parrot developer, the Parrot object model was one of the biggest pain points for porting JS/Ruby/Python to Parrot... Where that object model was meant to be universal, and work for any language. [1] That said, IronPython does still semi-exist [2], and I'm not sure how well JRuby handles interoperability with Java or Jython...

[0] One former dev on one of the Iron* languages posted on reddit about how the CLR failed on its cross language ambitions. I can't find the post, but they gradually found it was mostly C# centric anyways, and ports of other languages were mostly incompatible and second-class

[1] http://whiteknight.github.io/2015/01/15/parrottheend.html

[2] http://ironpython.net/announcements/ for what it's worth...


It's a hard problem, which the COMPlus team knew when they started out. During the early pre-release period, there was a then-NDA-only project, Project 7, which gave grants to people trying to port both commercial languages like perl and academic languages like scheme. I was at Northwestern, where we got a Project 7 grant to work on a scheme implementation (under Ian Horswill, done by Pinku Surana in my group) and scheme language service (done by me).

We provided a lot of feedback, but it's tough for a group of a couple of students (or in the case of Perl, one commercial dev) to keep up with the then massive-breaking-changes drops we'd get from DevDiv every 3 months or so and provide feedback when it was on stuff that was, to the developers, around 6 months old. Often, by the time feedback landed, it was "too late" to incorporate because of product cycles and got postponed. Or the stuff we'd request was a dupe of "add tail call instruction" which had been postponed long before any of us got started in Project 7.

I say this as somebody who then graduated and then went to work in DevDiv for the next 7 years, where I was treated very well, so I certainly have no axes to grind on that front :-)


The strange thing is they seemed to have had a bit of cognitive dissonance from the outset. They wanted to support Java and JavaScript, but the semantics of their Java and JavaScript basically made them different syntaxes for C#. On the other hand, they've put a lot of effort into support tail calls. On the third, it's only really used by F#, which is .NET specific. :(


JRuby interops fine with Java. Any specific thing you might be curious about?

One example is Rack applications are hosted by Java web containers Just Fine via a server -> Rack mapping. We use this in production for both a Sinatra app and a Rails app.


Interesting! Does that (partially) obsolete this answer [0]? Do Ruby programs see Java objects as a separate kind of Object, or is it seamless? Is there a translation layer anywhere? Does JRuby-Rack have to use wrappers for Java functions?

[0] http://stackoverflow.com/questions/2752979/using-jruby-jytho...


Blame communities and past lack of OSS spirit. E.g. Clojure CLR is doing well, Scala kind of missed the opportunity to win C# devs with their CLR version by abandoning it. CLR is the enabler, not implementator.


> Blame communities and past lack of OSS spirit

The communities aren't to blame, but Microsoft. Like you said, the past lack of OSS spirit.

But maybe things are changing now :)


The thing is, ClojureCLR is a demonstration of of exactly what's wrong with the CLR: it isn't Clojure. Instead it's a language with similar decisions and similar syntax but slightly different semantics.


Would you say that is true of ClojureScript as well? If not, what sort of differences are there in ClojureCLR?


The problem with ClojureCLR is not technical, its just that most people dont care about it. There are some things moving there but not anywhere close to Clojure or ClojureScript.

Clojure has never, ever been about equality between diffrent versions, the were always meant to be simular but diffrent when the platform is diffrent.


I think you're getting mixed up. ClojureCLR demonstrates that CoreCLR doesn't deliver on its intended functionality, not that Clojure's approach is wrong. Indeed, Clojure's approach is dead on: don't even try to make platforms compatible.

With that said, I'd like a better lib story between Clj and Cljs.


> I think you're getting mixed up. ClojureCLR demonstrates that CoreCLR doesn't deliver on its intended functionality

What do you base this on? I have not heared major complaints, I clearly remember Rich saying that it was not technical early on.

> With that said, I'd like a better lib story between Clj and Cljs.

They are working on feature expression, that should help.


Yeah it was a great dream, and to be sure, they do support a fair amount more than C#. The availability of pointers, for instance. It's slightly ironic that the inferior JVM is where all the languages run. But that might just be MS being pigheaded with the license to the CLR up until now. (They had an open source version called Rotor that ran on FreeBSD and Mac OS X, but a very limited license - this was around 2003 IIRC.)

But it's clear that MS does not really care about other languages. The APIs they ship are often C# only, taking advantage of quirks in the C# compiler, even. This document would have been better off written several years before, when reality hadn't set it. And also vice versa. The C# compiler has always needed "duck" typing, but instead of exposing it in any principled way, they simply hack it into the compiler on an as-needed basis.

The runtime hasn't been updated in about a decade, to boot. So, apart from the F# folks valiantly getting generics pushed in for v2, everything's been essentially frozen for over a decade. There may have been some kerfuffle around boxing of null nullable types, but nothing serious. Serious, deep, flaws, line reference types always being allowed to be null, just go unquestioned as part of the C way of thinking.

I feel like this was the same as IE. MS saw a huge threat in Java, and responded excellently. Then, after matching it, they got complacent.

Part of the issue may have been the Longhorn fiasco. Without a strong runtime (apart from whatever managerial issues), they couldn't ship an OS, and I think the managed code people lost too much political capital to really drive a continuing difference. Although, even before that, teams inside MS (like Office), were totally against taking a dependency on .Net.

I wonder if a light, optional, ownership system would have provided the performance necessary to have pulled it off. Then you could do something like play with an array without making heap allocations galore. The GC is great, but even short lived, gen0 garbage has considerable costs. (In practice, I could measure a single allocation's impact on a per packet (network sniffer app) basis.)

The CLR advancing at this point seems highly unlikely. C# and it's nearly isomorphic verbose flavor, VB.NET, have decided that advancement is a compiler thing only. Something like type classes? Simple annotations for ownership to allow some use of the stack? I will always dream.


* DLR

* LINQ+Generics(It's my understand much of the generics work was done for LINQ, not F#)

* RyuJIT

* New GC Modes

* Re-Jit

* MPGO

* Thread pools and TPL

The CLR is under constant development. I think, if anything, now that you can upgrade your CLR version on a per-project, per-build basis there should be an acceleration of released improvements.


The generics work was done by the people behind the F# team for the CLR overall (for v2), well before LINQ existed. (And F# had generics in the compiler using an erasure system before that.) If those MSR folks had not risen to the occasion, C# prolly would have had to used a lame erasure approach just like Java.

DLR and LINQ don't modify the runtime, nor does the TPL.

So there's been some incremental improvement in GC, some advancements in JIT (perhaps driven by Windows Phone needing more AOT support). And this was stuff that was known for a long time, but MS stubbornly refused to do, just like they did with static linking for C#.

But come on, no real serious advancements since the CLR v2. The IL is still the same. MSR came in and gave them a vastly improved type system, and things have sat there ever since.

Maybe that'll soon change, but seeing as how C#'s been just slowly adding F#'s features and toting their compiler rewrite for years, somehow I'm not really counting on any revolutionary language tech coming out of there.


Can you elaborate on the issues with running Java on the CLR? I always thought IKVM had a great reputation.


Not sure why you say Python on the CLR is abandoned. The last release of IronPython was on December 6, 2014.


Mono team is now actively merging this into Mono (see Miguel De Icaza github) - this is very good news for .NET


2016-s default gentlemen's choice: Azure, Win10, Docker, CoreCLR, ASP.NET Web API, F#, TypeScript.


Azure is a nice offering, pretty slick. But the costs of compute on Azure are literally 200% of Google Cloud Compute Engine. And the performance of GCE is also better.

I'm very anti Google, and I had dismissed GCE out of hand. But then I looked into it and tried it out and I'm blown away. VMs launch like instantly, and are much faster than their Azure counterparts. Niceties, like SSH in the browser really are cute, too. And, each machine can have a public IP, instead of Azure's quirky "cloud service" one IP limitation.

But pricing, that's what kills you. While Azure makes a big deal about how they match pricing, it's only on the storage/transfer sides. The same specs on Azure are 200% more money. The same performance is... a lot more money. I think it's cause the main tier of Azure runs on some older AMD series, but GCE is running Ivy/Sandy bridge.

As a longtime Azure user, I was rather distressed to find I was paying so much more for less. Even after the discounts MS had for 6 or 12 month commits, their pricing is still far more.

Also s/TypeScript/WebSharper.


Wait a second. Isn't the elefant in the room the fact that Microsoft is open sourcing a core piece of their software? And MIT license!!! What's happening?


I'm wondering how this relates to LLVM or JAVA bytecode.


>fundamentally only simple things can be easy


Look at the repository the file belongs to. :)


I have no idea who Vilius Kairys is, care to elaborate?


The repo. It's coreclr. .NET is now open source to the core.


It seems that it also works on linux? So it works as a replacement for Mono then? I guess the compilers are missing. But I guess you can use the mono compilers and then clr.


They open sourced their compilers earlier: https://github.com/dotnet/roslyn


build:failing :/




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: