I use both Javascript and C# on a daily basis and I sometimes have to consider hoisting when using Javascript. However, C# doesn't seem to implement hoisting(that I know of) and I can't figure out why. Is it more of a design choice or is it more akin to a security or language constraint that applies to all statically typed languages?
For the record, I'm not saying i WANT it to exist in C#. I just want to understand why it doesn't.
EDIT: I noticed the issue when I declared a variable after a LINQ query, but the LINQ query was deferred until after the variable declaration.
var results = From c In db.LoanPricingNoFee Where c.LoanTerm == LoanTerm
&& c.LoanAdvance <= UpperLimit Select c
Order By c.LoanInstalment Ascending;
Int LoanTerm = 12;
Throws an error whereas:
int LoanTerm = 12;
var results = From c In db.LoanPricingNoFee Where c.LoanTerm == LoanTerm
&& c.LoanAdvance <= UpperLimit Select c
Order By c.LoanInstalment Ascending;
Does not.
Of all the programming languages I have used, Javascript has the most confusing scope system and hoisting is a part of that. The outcome is that it is easy to write unpredictable code in JavaScript and you have to be careful with how you write it to make it into the powerful and expressive language it can be.
C#, in common with almost every other language, assumes that you will not use a variable until you have declared it. Because it has a compiler it can enforce that by simply refusing to compile if you try to use an undeclared variable. The other approach to this, more often seen in scripting languages, is that if a variable is used without having been declared it is instantiated at first use. This can make it somewhat hard to follow the flow of code and is often used as a criticism of languages that behave that way. Most people who have used languages with block level scope ( where variables only exist at the level where they were declared ) find it a particularly weird feature of Javascript.
A couple of big reasons that hoisting can cause problems:
Finally, I cannot imagine a reason why it would be a useful addition to a language like C#- what possible benefit could it confer?
"Is it more of a design choice or is it more akin to a security or language constraint that applies to all statically typed languages?"
It's not a constraint of static typing. It would be trivial for the compiler to move all variable declarations to the top of the scope (in Javascript this is the top of the function, in C# the top of the current block) and to error if a name was declared with different types.
So the reason hoisting doesn't exist in C# is purely a design decision. Why it was designed that way I can't say I wasn't on the team. But it was probably due to the ease of parsing (both for human programmers and the compiler) if variables are always declared before use.
There is a form of Hoisting that exists in C# (and Java), in the context of Loop-invariant code motion - which is the JIT compiler optimization which "hoists" (pulls up) expressions from loop statements that don't effect the actual loop.
You can learn more about it here.
Quote:
“Hoisting” is a compiler optimization that moves loop-invariant code out of loops. “Loop-invariant code” is code that is referentially transparent to the loop and can be replaced with its values, so that it doesn’t change the semantic of the loop. This optimization improves runtime performance by executing the code only once rather than at each iteration.
So this written code
public void Update(int[] arr, int x, int y)
{
for (var i = 0; i < arr.Length; i++)
{
arr[i] = x + y;
}
}
is actually optimized to be somewhat like this:
public void Update(int[] arr, int x, int y)
{
var temp = x + y;
var length = arr.Length;
for (var i = 0; i < length; i++)
{
arr[i] = temp;
}
}
This happens in the JIT - i.e. when translating the IL into native machine instructions so its not so easy to view (you can check here, and here).
I'm not an expert in reading assembly, but here is what I got from running this snippet with BenchmarkDotNet, and my comments on it showing that the optimization actually took place:
int[] arr = new int[10];
int x = 11;
int y = 19;
public void Update()
{
for (var i = 0; i < arr.Length; i++)
{
arr[i] = x + y;
}
}
Generated:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With