top of page

C# vs Javascript in Unity

Updated: Nov 15, 2023

OBSOLETE CONTENT: Since this post was written several years ago, Javascript support (and Boo support, for that matter) has been entirely phased out from Unity. I'm keeping the post here for posterity, but you should be aware that its contents are entirely irrelevant today.




Which language to use?

Unity supports two programming languages for your main game code: C# and JavaScript. (Well, it also supports Boo, but that support is so widely ignored and hidden away that's it's not even worth discussing.) Which of these languages to use has been a matter of debate many times on the Unity forums, and classical wisdom would suggest that ultimately, the best answer is to say "I prefer this one, but to each his own." and be on your way. Some have said that JS is a good way to dip your toes in the water of Unity development, and that budding developers who stick with it will eventually "graduate" to the more advanced language of C#. I'm not going to do either of those things.

C# is, objectively, better than JavaScript in Unity. It has been for many years, and the gap between them has only widened as time goes on. This is true for advanced coders and newbies Unity users alike; as much as I like the condescension of treating JS as baby's first programming language, it's honestly a stumbling block for new users, far more than C# is.

I'm going to break down the many reasons that this is the case, but ultimately it boils down to one fact: C# is a programming language, and JavaScript is a lie from the marketing department.

History Lesson: JavaScript, UnityScript, and Unity's Marketing Department

When Unity was first being created, one thing that Over-the-Edge Entertainment (what the Unity company called itself at first) wanted was to make the engine accessible to amateur developers. Many decisions were based on this, one of them being the inclusion of JavaScript, which is familiar to many a web developer.

But JavaScript is, inherently, an interpreted language; it's not possible to compile it into bytecode, which Mono (Unity's script-running backend) runs on. In order to appeal to this potential customer base who had web dev experience, a new language was created, which would take C# and make it look like JavaScript.

This was all well and good until they marketed it as JavaScript. The simple fact is, if you find any Javascript sample code on the web and paste it into Unity, it won't work except for the most very basic of code samples. These aren't minor syntactical differences; it's major structural changes. What this means is that Unity is the onlyplace where you'll find this particular language. Eventually, Unity made a decision that they would stop lying so blatantly in their marketing and would start calling it UnityScript. Unfortunately, that decision has not been adhered to particularly well, and right now we have a hodgepodge in the marketing and documentation materials.

As of February 2017, when I checked the page where they describe Unity to new users (which I haven't looked at in several years), there's Javascript, sitting there right next to C#. Putting myself in the shoes of a new Unity user excited about using Javascript, I clicked on. The next page deep also calls it JavaScript, and it's not until you get several pages into the documentation that it starts calling it UnityScript.

Following that discovery, I clicked around in archive.org a bit to investigate the history of JavaScript/UnityScript marketing. In 2008 it had JS and C# listed on the main page. Starting in 2011 they have C# listed alone. In 2013 the website got retooled, and JavaScript was back, and Boo makes the cut this time too! A bold move, given that Boo would be killed off a year later, at which point it would also be removed from this page - JS remains there, however. The story gets interesting again in 2015 when Boo is added back to the page at the time of the next redesign! Boo was being advertised next to C# and JS until literally last month, 3 years after its deprecation, which brings us to the current page.

In summary: There was a brief time when the website did not advertise JavaScript on equal footing with C#; however, there has never been a time when it was called UnityScript in marketing materials. And amusingly, it seems like someone forgot to tell marketing that Boo was dead. Perhaps someone should let marketing know that UnityScript isn't JavaScript.

It's worth noting at this point that Unity is not the first piece of software to pull this naming switcheroo: JavaScript itself (as in, the one used on the Web) is deceptively named! Its proper name is ECMASCript, or was, once upon a time; it was named JavaScript to appeal to the developers who, at the time, were learning the Java programming language. Much like the relation of JavaScript to UnityScript, you could not simply copy and paste Java code into JavaScript, which makes its own name kind of a lie. Java - the original - ironically enough, is a precursor in many ways to C# and .NET (which is what Unity's Mono runtime is based on), which means that Unity's JavaScript is named after web JavaScript which is named after Java - while also being built on C# which is itself built on the concepts of Java. We've come full circle.

All of this is a long, roundabout way of getting to the point: Unity's JavaScript is a marketing department lie.

Language clarity

While some JS coders will cite C#'s wordiness as a point in JavaScript's favor, in most cases this wordiness makes it much clearer what is going on. For example, in JS, any code that is outside the body of any function (such as Update) is presumed to be a Start() function. On rare occasions, this is a good thing; you can write a one-line JavaScript file that actually does something productive. Unfortunately, game projects tend to be made of larger script files than that, and as a script file grows larger, clarity becomes more important. Having an explicitly declared and scoped Start() function helps make it much clearer when things are executing. It ensures that your initialization code will all be in one place, whereas in JS it can be scattered throughout the entire script file, between all the other functions.

This sort of explicit "wordiness" is a huge boon when you're working on a team and sharing code. There's a certain amount of "okay, do what you want" on a solo project, but C# enforces coding practices that are far better if you're going to be modifying someone else's code. In the above example, how am I supposed to discover that you added a line of code on line 412 (which will execute as part of Start() ) which is interfering with the feature I'm now adding? I really have no way to find it except to scour the entire script file for it.

It's also clear from the get-go in C# that all scripts derive by default from MonoBehaviour, and gives a clear example of the syntax of inheritance - whereas to do the same in JS would require you have the syntax onhand from elsewhere, or search for it online.

When it comes to variable and function declarations, C# actually goes against its reputation by being less verbose. While both languages support type inference via the "var" keyword (and it can look identical):

var x = 5; //creates an int with value of 5

If you want or need to explicitly type your variable, JS becomes really inconvenient:

// C#
int x = 5;

// JavaScript
var x : int = 5;

Given that "declaring variables" is one of the most frequent things you do in programming, this becomes a constant thorn in your side in JS.

On function declarations, JS seems to go out of its way to put the return type of the function in an inconvenient place:

// JavaScript
function addNumbers(var x: int, var y: int, var z: int) : int {

// C#
int addNumbers(int x, int y, int z) {

Thanks to this backwards way of specifying variable types, that JavaScript function definition is nearly twice as long - and much more annoying to type! - than the C# version.

Using "var" as your sole means of declaring variables makes sense in web JavaScript. There, variables basically don't have a type; they get a type when they get a value, and then they get a new type if you assign a different value. So all variables in web JS are more or less the same type, so it makes sense to use the same word to declare them. UnityScript, however, just imitates this behavior - it pretends that variables are typeless, which leads to one of two things: either A) this annoying colon-based syntax, or B) the potential for nasty bugs if you're not very careful about the values you initialize a variable with. (see the section on inferred typecasting, below) It turns out that being a poorly designed language might be a natural consequence of being a marketing department lie. Who knew?

IDE support

C# has better support in the IDE's (MonoDevelop and VS) than JavaScript. Again, this goes back to C# being a more established and popular language. MonoDevelop has support for a lot more features in C#, and these features are seriously important for writing good code quickly.

Autocomplete & Intellisense: The most obvious feature; it's much more limited in JS. In C#, it can autocomplete pretty much everything - local variables, class members, class names. When you start typing a function name, not only can it autocomplete the function name, but when you start entering the parameters, it gives you a list of the parameters that function expects, including multiple overrides of the function when applicable, and often with smart suggestions popping up that you can simply hit enter and fill out. This is known as Intellisense, and if you've never used an IDE that supports it, you haven't lived. It's especially handy when exploring a new class - rather than digging through pages of documentation to find the answer to "Does this pathfinding class let me access its waypoints?", you just type "pathfinder.wayp" and suddenly every class member or method that has to do with waypoints shows up in front of you, ready to be filled out for you.

And, honestly, I'm _under_selling the usefulness of Intellisense in that paragraph. Coding without Intellisense is like being a carpenter without a ruler; it's possible, but once you've used one, it's honestly tough to justify not using it.

Error Highlighting: When you make a mistake in C# - which, let's face it, Intellisense makes tougher to do - you often don't need to tab over to Unity to find them. If a member or method or variable doesn't exist, it turns red. If you're missing a parenthesis or a semicolon, little squiggly underlines appear as you type.

Code Refactoring: If you have a class or variable used throughout your project and decide to rename it, this is an absolute nightmare in JS. Likely your only option is to Find & Replace In Files. This works okay if the variable you're renaming is particularly unique to begin with, but what if you're renaming "name" into "displayedName", for example? You're so incredibly screwed. You're stuck with that lousy, non-descriptive name forever.

The capabilities of an IDE when you're using C# are best described with a screenshot:


If you're a JS coder, this is the sort of thing you may be shocked to learn is even possible, let alone available for you to use, free, if you only switch to C#. Not only is this more convenient than Find & Replace, it's context-aware; it'll only change that particular member, even if every class you've ever written has a member by the same name. Because MonoDevelop and VS actually have an understanding of the code you're writing, they can do amazing things.

Comparison: Autocomplete kinda exists in Javascript, sometimes, but it's not context-aware and is a bit of a crapshoot. Intellisense, error highlighting, refactoring? Fuhgeddaboutit. Because C# is a Real Language(TM), actual professional tools are written to make writing code in it as seamless as physically possible. Tools like this are written for programming languages, not marketing department lies.

Programming Community

The C# community is just better than the JavaScript community. I don't mean this as an insult to any particular developer who uses JavaScript; hear me out. For one thing, it's bigger: even just among Unity users, C# coders outnumber JS coders by at least 4 to 1. And C# also has a massive developer community outside of Unity, thanks to the fact that .NET exists independently of Unity, while UnityScript is used only in Unity. This means a bigger community to turn to for support (it's difficult to get answers on the Unity forums if the problem code you post is in JS), a bigger pool of devs to hire from or collaborate with if you start a project, and a bigger set of sample code for any algorithm you could possibly want.

While I don't generally like to quantify the value of a human, I don't mind quantifying their usefulness, and by that measure, C# coders are, on average, objectively better than JS coders. Because C# is better for collaboration as outlined above, and every professional team collaborates, the result is that almost any Unity dev who codes for a living uses C#, whether they're forced into that choice or otherwise. C# is actually taught in schools, which means that C# coders are more likely to be professionally educated in their language. In addition, anyone who has experience with other object-oriented languages - generally, other professional developers - will feel more at home in C# than in JS. And the few professional developers (web devs) that might prefer JavaScript in fact find themselves incompetent at UnityScript because Unity's marketing department misled them about what that language was.

As the other arguments for using C# over JS continue to grow stronger, it becomes more and more likely that a randomly chosen JS coder will be someone who is just picking up the engine for the first time, who hasn't had a chance to read an article like this one or discover for themselves the reasons not to use JS. Put another way, the community of JS coders as a whole is far better at asking for coding help than giving it - which is not really good for anyone.

Tutorials & Sample Code

This point is straightforward: All of Unity's tutorials and the vast majority of their sample code is in C#, especially for their modern API. Increasingly, Javascript is so ignored by Unity's own developers and documentation writers that the presence of Javascript sample code on a particular class's documentation tends to be a sign that that class is deprecated or obsolete.

Additionally, C# has the benefit of the massive community of C# outside of Unity. If you search for a particular algorithm, odds are pretty good that you'll be able to find some C# code that you can paste into Unity and have it just work. C# also gets the boon of MSDN, a fantastic resource for learning all the more obscure bits of the language. There is nothing remotely close to equivalent for MSDN when it comes to UnityScript.

While this seems like a simple point unto itself, and it is, its importance is paramount: it absolutely shatters the idea that JavaScript is easier to learn and, thus, better for newbies. C#, with its far superior online library of resources, is the language where every answer is a google search away.

Did people ever like UnityScript?

Once upon a time, there were situations in which UnityScript was more convenient than C#, and you could make a genuine case that rookie Unity users would have an easier time learning it. Indeed, in its original conception, it was intended to be a programming language designed for Unity, which would overcome several annoyances that were present in the version of C# that shipped with Unity 1.0. This, of course, was before the marketing department got ahold of it.

For example, to modify a value on another script in Unity as of 2006, this is what you had to do:

// Javascript
GetComponent("PlayerScript").life -= 2;

// C# (Unity 1.x)
PlayerScript player = GetComponent(typeof(PlayerScript)) ) as PlayerScript;
player.life -= 2;

Pretty cumbersome, indeed. And the C# vs JS debates of 2006 were, appropriately, fairly evenly split.

But then Unity 2.0 was released, including C# 2.0, which included a magical thing called generics.

Suddenly, C# looked like this:

GetComponent<PlayerScript>().life -= 2;

And not only was this on par with the old JavaScript code, it was determined at compile time, which means that it was easier to track down issues if you misspelled the class name, and harder to misspell the class name in the first place because your IDE would be able to autocomplete it.

JavaScript also got upgraded with support for generics (albeit with a slightly awkward dot syntax), but this did wipe out one of the advantages JS had up until that point, which was C#'s verbosity when it came to functions that are extremely common in Unity games.

Another JavaScript advantage - especially for coding newbies - was "duck-typing". Essentially, this means that in the GetComponent example above, JavaScript doesn't necessarily need to know what type the result of that GetComponent call was going to be at compile time; it's happy to wait until the code actually runs, then it will see what type it is and find the ".life" member of it.

There are a few issues with duck-typing, though.

1) It's slower. Duck-typing requires that the engine check each member to see if it has the name "life" before modifying it; with a static typed member, it does all that work at compile time and, when running, can go directly to that spot in memory.

2) It gives runtime errors, not compile-time errors. By the same token as the above, a typo in the variable name won't be discovered until the code actually gets run. This is not a big deal for small projects, but on large projects, it's really easy for a line of code to go un-executed until it's time to do a full playtest, at which point it's much more annoying to go back and fix the code.

3) It solves a problem that is easily solved with inheritance and/or interfaces.

And most importantly:

4) Duck-typing can't be done on mobile devices. This isn't a limitation of power or speed, but of security - Apple in particular doesn't permit code on iOS apps that supports features like duck-typing because it's impossible to be certain about the security of such code. For this reason, when it started supporting iPhone in 2.x, Unity started using a preprocessor directive to JS - "#pragma strict" - which flat out disables duck-typing.

#pragma strict is now on the JS template file, so while you can delete it, duck-typing effectively doesn't exist anymore.

Throwing JS a Bone: Inferred typecasting

There is one syntactic advantage that JS has over C#, which may be literally its only saving grace, and that is inferred typecasting. This code compiles in JS, and functions basically as you'd expect:

var x : int = 0;
x = 2.1;

Because x is an int, it ends up with a value of 2 (the closest it can get to the floating-point value 2.1). The equivalent code in C# will not compile:

int x = 0;
x = 2.1f;

Because C# basically wants you to be absolutely, positively sure that you actually want to truncate 2.1 to 2. C# draws a distinction between implicit and explicit casting. If I reversed the example - assigned an int value to a float variable - it'd work fine, because there is an implicit cast operator available for int-to-float (which exists because no data is lost in the conversion).

C#'s approach to casting can prevent nasty, hidden bugs, especially when you combine it with other things like type inference meant to make life easier. For example, if you didn't make sure to give "x" a type:

var x = 0;
x = 2.5;
Debug.Log("Doubling x gives you "+(x * 2) );

...you might be surprised and justifiably baffled when the above code tells you that 2.5 times 2 is 4. What's happening there is that x was inferred to be an int in the first line, so the assignment of 2.5 caused it to end up with the int value of 2 instead. And, again, this is not how web JavaScript works; there, all variables are "whatever type they happen to be at the moment", so assigning 2.5 to x would have made it become a float, which would be correctly multiplied to give the result of 5. In C#, the above code would give you an error in the second line, tipping you off that x may not be the type you expect.

All that said - while I believe that C# has made the right decision on this, I fully understand that rookie coders may find this sort of thing frustrating. Thus, I will grant JS this one small victory in the realm of being an attractive language for rookie developers.

That said, all you have to do to make it work in C# is to make it explicit, like this. So, you know, advantage nullified.

int x = 0;
x = (int)2.1f;

Conclusion

While I haven't hit on every reason that C# is objectively better than JS, I've gotten around to all the highlights. If you've read this and are still not convinced to switch - if you honestly still believe that JS has more value than the marketing department lie that it is - I would honestly, genuinely like to know why. For science.

コメント


bottom of page