6

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.

BenM
  • 4,218
  • 2
  • 31
  • 58
  • 3
    What would be the benefit of it? How would it deal with block-level scopes? – zerkms Sep 12 '13 at 09:42
  • I noticed the issue when I declared a variable after a LINQ query, but the LINQ query was deferred until after the variable declaration. – BenM Sep 12 '13 at 09:44
  • 2
    Your code sample is Visual Basic not C#, which if I recall correctly will automaticly declare a variable if a name is used which hasn't been declared already. The first code you've posted would not compile under C#. – Ibasa Sep 12 '13 at 09:48
  • Sorry yes this is VB.NET. However the top one does not compile but the bottom one does, the same as C#. – BenM Sep 12 '13 at 09:50
  • I too am confused by the use of VB.net in a question regarding C#. – Jon P Sep 12 '13 at 09:51
  • I've updated it to C#, I am currently working on a VB.NET project but I always chose to code in C# where possible hence the code originally being VB.NET. – BenM Sep 12 '13 at 09:54
  • 1
    What if there was a field called `LoanTerm` in that class, and C# also supported hoisting? What output would you expect? The notion of [scope](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html) would also have to be changed to match Javascript, to provide any sensible behavior. – vgru Sep 12 '13 at 10:12

5 Answers5

12

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?

glenatron
  • 11,018
  • 13
  • 64
  • 112
  • I fully agree. I much prefer not using hoisting and it's certainly not something I want to see in C#. It's just good to understand the reasoning behind it. – BenM Sep 12 '13 at 10:04
9

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

Ibasa
  • 627
  • 4
  • 10
  • 1
    "to move all variable declarations to the top of the function" --- to the top of the scope. – zerkms Sep 12 '13 at 10:03
  • @BenM: "Why it was designed that way I can't say" "This is exactly what I was looking for" facepalm :-S – zerkms Sep 12 '13 at 10:04
  • @zerkms: it was a bet, and the guy just won 10 bucks. – vgru Sep 12 '13 at 10:07
  • 1
    @zerkms, Ibasa answered my question clearly, consisely and got straight to the point, he didn't spend ages asking me "Why would you want it in C#, it's terrible" etc. I'm well aware of this, I was curious as to the reasoning behind it, I'm not bothered about individual opinions on why it's so bad. – BenM Sep 12 '13 at 10:07
  • @BenM: the guy is not in a dev team, so he **cannot** know the real decision reason, it's just a guess. You've just heard what you wanted. – zerkms Sep 12 '13 at 10:08
  • @zerkms Well by answering that "No it's not a limitation" it really only leaves the option "it's a design choice" instead. Yes, he can't give me that exact design choice, but by confirming that it could be applied leaves the only option that it is not applied is because someone chose not to implement it. – BenM Sep 12 '13 at 10:15
  • ""to move all variable declarations to the top of the function" --- to the top of the scope" --- well yes, but Javascript top of scope is top of function. Scope is more accurate though. – Ibasa Sep 12 '13 at 11:33
6

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

Maverick Meerkat
  • 5,737
  • 3
  • 47
  • 66
2

Because it is a faulty concept, most probably existing because of rushed implementation of JavaScript. It is a bad approach to coding, which can mislead even experienced javascript coder about scope of a variable.

Nikola Radosavljević
  • 6,871
  • 32
  • 44
  • Could you explain why it is a faulty concept? Or perhaps point me to an article on why it is? – BenM Sep 12 '13 at 09:48
  • 1
    @BenM: 1. declare variable 2. use it. In this particular order – zerkms Sep 12 '13 at 09:50
  • 1
    @zerkms That doesn't explain why hoisting is a faulty concept. – BenM Sep 12 '13 at 09:51
  • @BenM: it requires you to read the WHOLE method to find out the variable type. – zerkms Sep 12 '13 at 09:52
  • @BenM It is in C#. Why on earth would you _ever_ use a variable before declaring it in C#? – doppelgreener Sep 12 '13 at 09:52
  • 3
    @BenM: c# dev team **could** design it if they wanted. The question you're asking "why there is no such feature" isn't correct. The correct one would be "Why the hell they would like this terrible thing to be in such an elegant language". Features in the language are added if it's proven it will be useful. How useful hoisting could be (in C# or any other language)? – zerkms Sep 12 '13 at 09:55
  • @zerkms My question, as I have stated before relates to the underlying reason why. I want to know if it's a design choice (which you seem to be suggesting) or more a limitation due to the nature of static languages. – BenM Sep 12 '13 at 09:58
  • @BenM: it's not a limitation. You definitely might implement it. But **FOR WHAT REASON**? "or more a limitation due to the nature of static languages" --- on a compile stage you could just move the definition line in the beginning of the current scope, it's not an issue. – zerkms Sep 12 '13 at 09:59
  • @zerkms Lol, right I'm not saying I WANT IT! I'm merely wondering what the reason is for not using it. – BenM Sep 12 '13 at 10:00
  • 2
    @BenM: what is the reason for using it? People make some design decisions because it's really necessary, not because "why not". If you follow "why not" design principles you end up with a language like javascript. – zerkms Sep 12 '13 at 10:01
  • @zerkms Yes, I fully appreciate that. I can understand why it's not implemented as it would be a horrible idea. – BenM Sep 12 '13 at 10:16
2

Function hoisting has a potentially unnecessary cost in work that the compiler has to fulfill. For example, if a variable declaration is never even reached because various code control decisions returned the function, then the processor does not need to waste time pushing an undefined null-reference variable onto the stack memory and then popping it from the stack as part of it's method's clean up operations when it wasn't even reached.

Also, remember that JavaScript has "variable hoisting" and "function hoisting" (among others) which are treated differently. Function hoisting wouldn't make sense in C# since it is not a top-down interpreted language. Once the code is compiled, the method might not ever be called. In JavaScript, however, the "self-invoking" functions are evaluated immediately as the interpreter parses them.

I doubt that it was an arbitrary design decision: Not only is hoisting inefficient for C#, but it just wouldn't make sense for the way that C# works.

Beebok
  • 385
  • 3
  • 12