What factors led to the development of C# in spite of Java
stackoverflow.com
stackoverflow.com
EDIT: Maybe there weren't actually any language changes breaking backwards compatibility. I'm not sure.
I personally like C#'s philosophy better: PL research exists for a reason and newer features make coding easier; moreover, I can avoid doing really stupid things and so can be trusted with operator overloading! Others maintain the opposite and believe Java's more conservative approach is best.
It would be nice to compare how the two philosophies fare in getting their respective languages adapted, but I fear such a comparison would be flawed: C# is much too tied to Microsoft, so most people not keen on heavy coupling with any particular vendor or OS tend to avoid it for that reason. The opposite is also true: heavy MS shops are much more likely to choose C# just because it's part of .NET, and not because of the language characteristics.
Still, it is very interesting to see what has happened given two virtually identical languages with different backers and philosophies.
There was always a Microsoft rep at those Java user group meetings. After the meeting, he would come up to us and ask us again what we wanted and why. Unlike anyone from Sun, he'd ask good questions, listen carefully, and take notes.
Microsoft genuinely liked the language as a much-better C++, but wanted it to have native extensions on Windows for two reasons: 1) it would encourage the writing of code that would be less portable, thereby reducing the threat to MS's advantage of being the platform with the most apps, and 2) apps written in "pure" Java just weren't as good as native apps, and for Java to become the "better C++" that many programmers inside MS were hoping for (for their own use), it was becoming clear they would need native extensions.
MS tried to produce a Java with native extensions: Visual J++. Sun filed suit, claiming that MS was in violation of contract. I don't recall the outcome of the suit, because MS decided that Java's slowing acceptance as a general-purpose language for client-side apps (and part of that slowness was CAUSED by MS) meant that there was less need to claim support for Java. It wasn't going to take over the world after all. (Steve Jobs later made the same decision). Not supporting it wouldn't mean you would be left behind. They abandoned Visual J++.
Instead, MS wanted their own Java-like language with no strings attached. Java was a trademarked name, so they created a language with a different name but all the Java features (LANGUAGE features) that programmers liked so much, plus most of the features that Java programmers were begging for that Sun was sniffing at, plus the native extensions needed to write Windows apps that would only run on Windows AND would run so well they would, in general, be indistinguishable from native apps written in Visual C(++), and they built a great app builder (VC#) to go with it.
They did a beautiful job with Visual C# and rattled Sun so much that suddenly a lot of those "impossible" features we "didn't need anyway" became available in Java, but C# has always maintained a healthy lead over Java in nice features for client-side programming, IMO.
(And Java has maintained a superior overall adoption rate, especially on servers.)
Not exactly. MS replaced Java's existing native extension functionality (JNI) with Windows-only native hooks called JDirect. Interestingly, it did so with these @com (EDIT: sorry, I meant @dll -- @com was related to COM hooks, which stuck around well into the .NET era as attribute hooks) method macros that, in a way, prefigured attributes in both Java and C#.
EDIT: If by 'native extentions', you meant the WFC classes, then yes these were additions, not a replacement of JNI. But these were not part of the lawsuit per se. The suit focused on the removal of JNI and the corruption of the JVM spec with the JDirect functionality.
> plus most of the features that Java programmers were begging for that Sun was sniffing at
'most of the features' is pushing it a bit. The only feature that J++ had over Java 1.1 at the time was method pointers (delegate). The lawsuit focused on those corruptions of Java: removing JNI as well adding JDirect and the 'delegate' keyword. This, according to the court, violated the terms of the license agreement signed by MS.
Microsoft lost the lawsuit, and that was the reason they ditched J++ and began work on C#/.NET, which built upon many of the lessons learned in J++. I think otherwise MS's plan was to continue building an ecosystem around the MSVM not unlike what they eventually built around the CLR.
It would be interesting to compare the MS/Sun ruling with the recent Google/Oracle ruling, as the terms of the two suits were rather similar.
It would seem to me that the biggest difference there is that MS did in fact sign a license agreement with Sun that constrained the nature of their use of Java. Google did not sign any agreement, and I wonder if this was a calculated move on Google's part, in light of the MS/Sun J++ ruling.
Considering the recent ruling by Judge Alsup regarding Android's similar adoption/modification of the Java spec, does this mean Microsoft would have stood a better chance by simply implementing J++ with no agreement from Sun at all? On my naive, IANAL reading of it, that would seem to be the case.
>'most of the features' is pushing it a bit. The only feature that J++ had over Java 1.1 at the time...
The Java-like language with no strings attached with the different name and all the new features that I was talking about was C#, not Visual J++.
> Microsoft lost the lawsuit, and that was the reason they ditched J++...
But that's not the reason they created C#. They created C# because they wanted a Java-like language (Java-like as in having the Java advantages over C++, not as in Java-compatible) without any limits on how good they could make it for writing Windows client apps. When they created J++, they were still assuming that Java was a juggernaut that they would have to cooperate with to some extent or get left behind, like HTML. Over time, it became clear that Java was fizzling out on the client anyway, so the need to cooperate was fading fast while the desire to create something that would actually be great for Windows clients was becoming overwhelming. After Java failed as a client-side alternative for creating Windows apps, MS was going to fork their own language, regardless of its name.
[Java] does not evolve very fast
While this is true for Java the language, it's not true for Java the VM, which evolved a lot faster than the CLR.And because Java the language does not evolve very fast, the ecosystem has given birth to mature JVM compilers/interpreters for languages such as Clojure, Scala, JRuby and Groovy, amongst others.
The biggest difference between Java and .NET is that the "backers" of Java come from a really big and open-source friendly community.
I always thought Java went very heavy on the frameworks side. Evolution was faster on the frameworks end.
Have you seen the details of the new Java G1 garbage collector or the specs for JSR-292 (InvokeDynamic)? That's awesome evolution right there.
Its like calling the Pentium/AMD/ARM as C processing Machines.
The name is deceptive, JVM based languages gives an impression that the languages have to do some thing with Java. Sure they have Java interoperability, but that is different to liking them them with the 'Java programming language' brand. Since JVM was shipped to run Java programs, it was called Java virtual machine.
Otherwise its a virtual machine optimized to run Java programs. When people think of Java its 'Java the language'.
JVM improvements are not necessarily improvement on the Java programming language syntax and semantics.
Also, Java is now backed by Oracle which isn't the most friendly of open source companies either.
However, I was actually only really talking about Java the language and not the JVM.
The only alternative language for .NET that's worth talking about is F#. But it's interesting to note that F# is sponsored and developed by Microsoft, while a language like Scala came from a third-party community. This is important because Microsoft is known to just dump projects that aren't generating a good return on investment.
Java is now backed by Oracle which isn't the most friendly
of open source companies either
Java was always backed by a huge community that includes IBM, Google, Intel, Red Hat, Novell and the Apache Foundation. The recent lawsuit against Google only goes to show that the genie is out of the bottle.What they are doing with version 2 is even more impressive and they are now sponsored by JetBrains.
F# is an excellent language* if you are doing Windows programming right now, you would be doing yourself a disservice not to look at it due to preoptimized worries. The language source is available , hacked on and ahead of Microsoft's version in certain aspects. In the case of a dumping, the community is talented and F# generates IL, unless C# is abandoned there is really nothing to worry about.
* I'm experimenting with intelligent, data based programming with a mix of Steffen Forkmann's JSON schema inference + ConceptNet + custom query syntax + embedded prolog + machine learning.
Hasn't Microsoft abandoned C# for internal development?
SharePoint Visual Studio 2010 The C# compiler is being rewritten in C# Microsoft Dynamics
I'm curious as to what you mean by this; what part of the Java VM has evolved faster?
Here are the conditions I could find (you still have to comply with those conditions, but it's doable): http://msdn.microsoft.com/en-us/library/ms973265.aspx
And they can stop you through the EULA .NET gets distributed under, because no other license gives you the right to use .NET, so you have to do it under the terms of that license.
To begin with, there are basically three CLR backends with sufficient maturity: Microsoft.NET, Mono, and Mono/LLVM, of which Mono is probably the slowest, because it is optimized for fast startup; that is matched against java -server, which (unlike -client) does extra optimizations (like mono --llvm) at the expense of a slower startup time. This works for short benchmarks, because compilation time is fairly minimal for these tight-inner-loop benchmarks.
Second, none of these benchmarks really touch on any of the JVM's weak spots. The classical example here is complex number arithmetic, where even an addition can potentially trigger a heap allocation (the JVM escape analysis only helps as long as functions don't actually store results anywhere). There are unfortunately quite a few such features where you get extra overhead to implement the workarounds.
Third, the JVM tends to be a bit of a memory guzzler. Combined with java -server's fixed-size heap, that can create problems in some scenarios (such as a system process that forks a few instances of itself).
In the end, few people will pick one or the other for the raw performance (which, in the end, is not very far apart), but for the ecosystem that comes with each backend.
It is worth noting that there are also other VM-related concerns, and overall, the CLR has the superior design as a general-purpose language backend.
For example, CLR functionality is a superset of JVM functionality. That makes the CLR far more pleasant to use as a compiler backend than the JVM (the reason why JVM-based languages use the JVM primarily is probably to hook into the JVM ecosystem, not because they love devising workarounds to implement closures or value types somewhat efficiently).
Similarly, P/Invoke is in practically all aspects superior to JNI. If you need to call native code a lot, P/Invoke is almost always the easier way to do it.
Library versioning is another issue where the CLR has the better story.
Again, what will almost certainly drive the use of one or the other for 99% of all programmers is what infrastructure (frameworks, libraries) they need. If they want to develop web applications using Scala/Lift, the JVM it is. If you want to implement games using Unity, you're going to use the CLR. The benefits you get from reusing code will almost certainly dwarf other concerns.
That makes the CLR far more pleasant to use as a
compiler backend than the JVM (the reason why
JVM-based languages use the JVM primarily is probably
to hook into the JVM ecosystem, not because they love
devising workarounds to implement closures or value
types somewhat efficiently).
That's not true.The JVM has inherent advantages that the CLR does not have ...
(1) the JVM can inline virtual method calls and with some machinery attached (bytecode manipulation) you can get pretty close to zero overhead when invoking functions dynamically (the reason for why dynamic languages on top of the JVM have been pretty awesome)
On implementing closures efficiently ... you should check your facts, because delegate invocation on top of .NET always has overhead compared to plain method invocation, while on top of the JVM you can make it so that those invocations will be inlined at runtime (in server mode the JVM even inlines method calls made through plain reflection, which is considered extremely expensive).
Implementations such as JRuby successfully do this, but because of JRuby's nature, the call-stack sometimes gets too tall, beyond the capabilities of the JVM to inline, however this is addressed with the InvokeDynamic support from JDK 7, which will make dynamic method calls as efficient as normal calls.
Because the CLR is not capable of such optimizations, compiler authors have to do a lot of optimizations ahead-of-time, while on the JVM even a dumb compiler can produce good results ... for proof, compile 2 binaries from the same source-code, one with the Mono compiler, the other one with the official compiler, then run on the same platform and compare.
(2) compiler writers love the Jar/.class formats, being really easy to produce binaries for Java, coupled with the maturity of libraries such as ASM ... contrast this with the CLR .dll format, for which the .pdb format for attaching debugging symbols is proprietary and NOT documented, which pushed the people working on Mono to come up with their own format (.mdb). Of course, through reverse engineering and through some code that Microsoft published, the interoperability of Mono with .pdb has improved lately, but it's still painful.
(3) there are many tools available for the JVM that complement compiler authors, tools like ObjectWeb's ASM, which have poor substitutes for .NET. And if you want a good parser generator, there are plenty to choose from for Java, while for .NET the only reasonable choice being Antlr, which is primarily a Java tool that also supports .NET -- on the other hand if you wanted to express your grammar with PEGs I personally couldn't find an option for .NET, while there are several available for the JVM.
(4) the features in .NET that are not used in C# have received poor support. For instance tail calls were NOT guaranteed to be eliminated, even if you specified this behavior in the compiled bytecode. But more than this, tail-calls have severe overhead over plain method calls. And did I mention that tail-call optimizations, as produced by the F# compiler, simply won't work reliably on Mono?
On value types, this is not such a huge issue as many people think. In Scala there's the proposal SIP 15 (value classes) which are implemented in the latest Scala 2.10 milestone release. This will open the door to much needed primitives, like unsigned ints: http://docs.scala-lang.org/sips/pending/value-classes.html
Also, you're making a mistake if you think the CLR type system doesn't have flaws. For instance the CLR lacks a Union type, which makes it a bitch to implement lazy languages, such as Haskell.
The CLR also lacks anything that would aid in implementing continuation-passing-style. The JVM doesn't have anything for it either, however for the JVM exceptions can be used for unwinding the call-stack efficiently and compared with the CLR, exceptions on the JVM are very, very cheap.
This coupled with bytecode manipulation and library authors have been able to build libraries that make use of CPS efficiently.
(5) P/Invoke is basically JNA ... https://github.com/twall/jna
C# does make it easier because it has a couple of primitives that make the marshaling of data easier.
Picking either the JVM or the CLR as your compiler backend is generally done because you either want (1) to hook into the respective infrastructure, (2) want a mature GC technology without having to develop your own, (3) need to generate reasonably fast code at runtime, or (4) all of the above. Most likely, it's a combination of (1) and (2).
If not, you're probably better off picking a more flexible backend that does not limit your object model or (if you're doing concurrency) your memory model. In short, either the JVM or the CLR forces you to compromise when emitting code.
In particular, both the JVM and the CLR are hostile environments for functional languages; if you're compiling a functional language to either (instead of, say, LLVM or MLRISC), you're almost certainly doing it for the JVM ecosystem, i.e. interoperability, vendor support, availability of tools, and such, not because it is a great fit for your needs.
So, when most of your points are about the superiority of the JVM ecosystem, I'm not disagreeing at all.
What I am still maintaining is that the CLR has the superior design. And yes, I am painfully aware of its limitations, too. Superiority is relative, not absolute.
All that said, there are a few of your points that merit a specific response.
(1) First of all, virtual call optimization (not just inlining) is something that the JVM does to solve what is primarily a JVM-specific problem. Simply put, while the CLR allows you to emit both call and callvirt instructions, the JVM has only invokevirtual (invokespecial, which was originally called invokenonvirtual, is more limited). The only option to tell the JVM that a call is non-virtual is to target a final method, which may require code duplication.
Second, nothing in Ecma 335 prohibits virtual call inlining when it can be proven to be safe. I don't know why Microsoft .NET/Mono still don't do it, but I suspect that they just don't see a big need for it, given that C# (unlike Java) uses non-virtual methods by default, and compilers for other languages with different semantics (e.g., Eiffel) can emit non-virtual calls at non-polymorphic call sites if they need to. Virtual call optimization could still be useful for inter-assembly calls (where the target assembly isn't strong-named), but that's probably a rare enough case that it's not certain whether the overhead is justified.
(2)/(3) Generating DLLs is pretty straightforward with ILASM or Mono.Cecil. Including debug information. You can only generate .mdb information on Windows, but then you only need it on Windows, too.
(4) The Ecma standard actually does make tail call elimination not optional for non-virtual calls. "CLI implementations are required to honor tail. call requests where caller and callee methods can be statically determined to lie in the same assembly; and where the caller is not in a synchronized region; and where caller and callee satisfy all conditions listed in the 'Verifiability' rules below."
With respect to value types, you probably misunderstood me. SIP-15 is about adding a layer of abstraction around existing value types. That's valuable, but it's also largely a compiler frontend, not backend issue.
What I was referring to was that the JVM makes heap allocations for tuple types all but necessary, especially if you're looking at collections of tuples. Sometimes you can work around it (such as mapping an array of N complex numbers to an array of 2*N real numbers) if you don't mind the extra work, but just as often that's not easily possible.
Most of those examples you gave (i.e. Clojure, Scala, JRuby) also have CLR versions.
The only one I can think of is the upcoming change in closure semantics for loop variables - something that is being changed to make it work like people would expect for 99% of the case and risks breaking that 1% of cases where someone actually wants the same loop variable to be closed over in all functions defined within the loop.
(e.g. Linq is actually much like a monad with SelectMany as bind)
Correct me if I'm wrong but I believe, with SelectMany, Linq does in fact, provide everything required to support monads.
Agree with everything else you said - especially on flawed comparisons between the two languages.
I didn't think that was possible.
With that said, C# almost always breaks forward compatibility. It seems like a somewhat odd design goal to have for a language nowadays.
It would be great if somebody who knows one way or the other for sure chimed in.
However the C# compiler will produce bytecode compatible with the .NET 2.0 runtime from C#3-code. And all C#2 code will compile just fine with the C#3 compiler.
Basically what breaks is trying to shove C#3 code through a C# 2 compiler, and that can hardly be said to surprise anyone.
The part which may be confusing is that unlike Java and the JVM, C# is tied to CLR runtimes, and you can have several installed at the same time.
C#1 was tied to the .NET 1.x runtime. C#2 was tied to the .NET 2.x runtime (which also powered .NET 3.0 and .NET 3.5). C#3 was tied to the .NET 2.x runtime with some extra LInQ DLLs installed (aka .NET 3.5). C#4 (which again adds more features) depends on the .NET 4.x runtime. And all these runtimes can be installed at the same time.
The fact that Microsoft is willing to "leave old runtimes behind" and create new ones when the language features being requested requires it means they can iterate much faster than the Java can, since backwards bytecode compatibility is not required.
I think it is a decision which has worked out largely to their advantage.
http://blogs.msdn.com/b/ericlippert/archive/2011/11/07/break...
* You could call directly into the Win32 API (the issue that caused Sun and Microsoft to fall out)
* Value Types. Still being discussed for v8.
* Lambdas. Yes, in version 1.
* C# had enums, Java didn't. (Now Java has better enums than C#)
* A syntactic sugar for property get/set. This was extremely important to Microsoft.
* A decent COM-interop story. Again, very important to Microsoft.
Of course it was similar. It was a design goal to be able to run Java code on the .NET VM. But it was far from identical.
Jon Skeet could no doubt expand this list
Some of the comments in that thread illustrate a widespread misconception that C# isn't cross-platform. We're finishing up a game that runs on windows, osx, ios, and android, with a server on linux; and it's written in C#.
Microsoft's CLR and BCL implementation aren't cross-platform, but I haven't used those in quite some time.
Java, on the other hand, is, for better or worse, used heavily on all the different platforms. Moreover, most Java libraries (like Swing. Does anybody still use Swing?) are cross-platform.
I find F# a much more interesting language than C#. Do you know how F# behaves on Linux? While I've heard of people using C# on Linux and Android, I haven't heard anything about F#. Then again, the Linux people might just prefer OCaml.
WPF was a definite non-starter for mono. Just too huge of an undertaking; much more focus on GTK#. Sometimes it's easier to bring something else to Windows than to bring Windows to everything else. In the case of WPF, it seems like not bothering was probably the correct move...
My understanding is that F# works just fine on linux and mac, but I haven't had the opportunity yet. Quite interested in this as well.
Something that seems to be a disadvantage with Java over native builds is the way it complicates the task flow for users trying to install your software. Either they have to download a large distribution that includes the JVM inside it (are distributors even allowed to redistribute Java like this?) or else they have to download and install the JVM, and then configure their new application to point to it.
How does this work when you're using c#?
On desktop, the necessary parts of the mono runtime would just be included with the distribution package; much like any other DLL. I don't think any developer in their right mind would ask people to download the mono installer. On the plus side, this doesn't pollute their system with registry entries or system files.
It's clearly not optimal to have that overhead, but it was preferential to porting to each platform in this case.
How about your server code? Is that ASP.NET running on Linux? Or something else?
On the server side, we just build the latest stable mono release and we made a socket server wrapped around libev (similar to what Manos de Mono does).
(I guess I lied, we have a small amount of web stuff in Ruby, but mostly just to serve content.)
Edit: Ok, now they deleted whole thing instead... because someone pointed out that it shouldn't been closed...
That being said, my understanding is that JVM programs slightly outperform CLR programs in terms of speed while CLR programs do better than those on the JVM(s) in terms of memory.
The point being debated is that the JVM is being developed and advanced more rapidly than the CLR. Performance is one way to demonstrate this. Performance does matter in many cases, and most folks aren't prepared to write their web services in Fortran.
>is doing quite great against java 7 (commercial implementation, unless I misread)
I would hardly classify 7x slower as "quite great"
>It would be interesting to see how the openJDK is performing ? (the real question would be : is openJDK crippled compared to the Oracle - JDK ?)
OpenJDK runs HotSpot, so no major difference
Start off with a different initial and maximum heap size (or a different GC option!) and the results may be different.
Sun was adamantly against the notion of people writing Windows programs in Java (or Unix programs in Java, or Mac programs in Java). Java programs were supposed to be for the Java platform.