Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't hoisting exist in C#?

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.

like image 926
BenM Avatar asked Sep 12 '13 09:09

BenM


3 Answers

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:

  • It is absolutely counter-intuitive and makes code harder to read and its behaviour harder to predict unless you are conscious of this behaviour. Hard to read and hard to predict code is far more likely to include bugs.
  • In terms of limiting the number of bugs in your code, limiting the lifetime of your variables can be really helpful. If you can declare the variable and use it in two lines of code, then having ten lines of code in between those two lines gives a lot of opportunities to accidentally affect the behaviour of the variable. There is a lot of information on this in Code Complete - if you haven't read that, I heartily recommend it.
  • There is a classic UX concept of the Principle Of Least Astonishment - features like hoisting ( or like the way Javascript handles equality ) tend to break that. People don't often think of user experience when developing programming languages, but actually programmers tend to be quite discerning users and more than a little grumpy when they find themselves routinely caught out by odd features. Javascript is very lucky that it's unique ubiquity in the browser has created a kind of enforced popularity that meant we have to tolerate its many quirks and problematic design decisions.

Finally, I cannot imagine a reason why it would be a useful addition to a language like C#- what possible benefit could it confer?

like image 74
glenatron Avatar answered Nov 04 '22 13:11

glenatron


"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.

like image 21
Ibasa Avatar answered Nov 04 '22 15:11

Ibasa


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:

enter image description here

like image 31
Maverick Meerkat Avatar answered Nov 04 '22 13:11

Maverick Meerkat