tags:

views:

1085

answers:

21

I just found this code in reflector in the .NET base libraries...

    if (this._PasswordStrengthRegularExpression != null)
    {
        this._PasswordStrengthRegularExpression = this._PasswordStrengthRegularExpression.Trim();
        if (this._PasswordStrengthRegularExpression.Length == 0)
        {
            goto Label_016C;
        }
        try
        {
            new Regex(this._PasswordStrengthRegularExpression);
            goto Label_016C;
        }
        catch (ArgumentException exception)
        {
            throw new ProviderException(exception.Message, exception);
        }
    }
    this._PasswordStrengthRegularExpression = string.Empty;
Label_016C:
    ... //Other stuff

I've heard all of the "thou shalt not use goto on fear of exile to hell for eternity" spiel. I always held MS coders in fairly high regard and while I may not have agreed with all of their decisions, I always respected their reasoning.

So - is there a good reason for code like this that I'm missing? Was this code extract just put together by a shitty developer? or is .NET reflector returning inaccurate code?

I'm hoping there is a good reason, and I'm just blindly missing it.

Thanks for everyone's input

+2  A: 

I have not seen a valid case for Goto in many, many lines of .NET code both written and reviewed.

In languages that do not support structured exception handling with a finally block (PASCAL - a grandfather of structured programming languages, as well as classic C come to mind), tactical use of a GOTO could lead to much easier to understand code when used to perform cleanup when execution terminated inside nested loops (as opposed to correctly setting multiple loop termination conditions). Even back in the day, I did not use goto personally for that reason (probably for fear of "exile to hell eternally").

Eric J.
I can honestly say that in 10 years of writing .NET code, I've never once used goto in a .NET application. It's as if my brain doesn't compute that it exists.
BenAlabaster
If I ever use goto in an actual program I will make sure I add a comment about forgiving me for my sins. :)
Maynza
+3  A: 

Thou shalt not look at reflector code.

Although if you ever look at disassembled IL, you'll see gotos all over the place. In essence, all of the loops and other control constructs we use are converted to gotos anyway, it's just that by turning them into constructs in our code, it becomes more readable and easier to maintain.

I don't think the code you posted would be a good place to use goto, by the way, and I struggle to think of one.

Anthony Pegram
I agree, I'm thinking this is something the compiler has changed from the original source code.
Daniel Ballinger
When I first saw this I thought it might be decompiled IL, but if so, it wouldn't have a variable named '_PasswordStrengthRegularExpression' would it? Which leads me to believe somebody actually wrote this.
John MacIntyre
Sometimes the quickest path to figuring out how to exploit the .NET framework is to go through reflector. I understand there are pitfalls and inaccuracies when using reflector - but sometimes I look at the code and think "er, what was that developer thinking?"
BenAlabaster
@Daniel: Yeah, that doesn't look like a label a human would invent.
Eric J.
@Ben, I was just making a play on "thou shalt not use goto." ;) By all means, use whatever means necessary when dissecting and learning.
Anthony Pegram
@John - Reflector can get at the variable/member names, but it can't always work backwards from the optimizations the compiler makes to get the disassembled code look like the source.
kekekela
@Anthony - I got the joke, don't worry - all taken in good humour
BenAlabaster
Ben - Microsoft have made the actual source code of the .NET framework libraries available. So you can actually pull it down and see if they really did use a goto, or whether this is just Reflector not being able to figure out from the IL what the original source code construct was that got compiled into an IL jump.
itowlson
@Eric do label names get compiled into the IL? I know they don't in most other languages (when including symbols but not debug info)
Earlz
@Earlz, in ildasm, you can see the labels that the compiler generates are hex notation. So you would see stuff like IL_0001, IL_000e, IL_002f, and (yes) IL_016c.
Anthony Pegram
@itowlson - Do you have a link to that? I'd be interested in getting my hands on it... is it on Codeplex?
BenAlabaster
@Anthony, yes I'm aware. but I mean the original code could possibly have had a GOTO, as in, you can't rule it out.
Earlz
@Earlz, it turns out the original code has been posted as part of an answer. These gotos were artifacts leftover from a compilation->decompilation cycle.
Anthony Pegram
Ben, you can configure VS to pull it down for you (see http://weblogs.asp.net/scottgu/archive/2007/10/03/releasing-the-source-code-for-the-net-framework-libraries.aspx) or you can download en bloc from http://referencesource.microsoft.com/netframework.aspx.
itowlson
Though shall NOT trust reconstructed code from Reflector! (Except for IL) I have been bitten by this way too many times to ever rely on it again.
leppie
A: 

There is one valid case - when you are trying to simulate a recursive procedure call and return in a non-recursive code, or do something similar (this kind of requirement also occurs in a Prolog interpreter). But in general, unless you are doing something requiring micro-optimization like a chess program or language interpreter, much better to just use the regular procedure stack and use function/procedure calls.

Larry Watanabe
I completely agree... that's what I was talking about in my answer with regards to potentially infinite (or very large) repeating code block where recursion would be inadvisable. Of course this could be refactored into multiple methods.There are multiple ways to skin a cat. Or program a loop. :)
Simon Gillbee
+11  A: 

Its probably not in the source code, that's just how the disassembled code looks.

kekekela
But would you still have a variable labeled '_PasswordStrengthRegularExpression' and not some random character set?
John MacIntyre
John: Yes, you would. That's a member field (note the `this.` prefix), not a local variable. Member field names are preserved in compiled code (unless obfuscated, which Microsoft didn't do to the .NET framework libraries).
itowlson
@John - Well, Reflector can get at the original member names, but can't always reverse engineer the compiler optimizations. That's been my experience anyway.
kekekela
@kekekela-That would make sense. Thanks
John MacIntyre
+1 for pointing out that it's probably not actually in the code.
+3  A: 

I think this is a valid use of goto. The alternative would be:


    bool psreIsSet = false;
    if (this._PasswordStrengthRegularExpression != null)
    {
        this._PasswordStrengthRegularExpression = this._PasswordStrengthRegularExpression.Trim();
        if (this._PasswordStrengthRegularExpression.Length == 0)
        {
            psreIsSet = true;
        }
        else 
        {
            try
            {
                new Regex(this._PasswordStrengthRegularExpression);
                psreIsSet = true;
            }
            catch (ArgumentException exception)
            {
                throw new ProviderException(exception.Message, exception);
            }
        }
    }
    if(!psreIsSet)
         this._PasswordStrengthRegularExpression = string.Empty;

    ...//Other stuff

And for me at least, the goto version is easier to understand. I think gotos are fine when they are simple and linear like this.

Stephen Swensen
I'm not going to down-vote you since you're new here, but get ready for it. :)
MusiGenesis
Haha, thanks, I'm bracing myself.
Stephen Swensen
I guess everybody went to bed. Try answering "no" to a question about whether source control is a good idea. :)
MusiGenesis
Or tell someone that html table layouts are fine.
Rob
+1  A: 

No, there's no good reason to use goto. I last coded a goto statement in 1981, and I haven't missed that particular construct since.

MusiGenesis
+8  A: 

I have seen goto used to break out of nested loops:

http://stackoverflow.com/questions/863172/how-can-i-break-out-of-two-nested-for-loops-in-objective-c

I don't see anything wrong with using it that way.

Maynza
Couldn't you use `break [n]`?
Atømix
@Atomiton: break only breaks out of the inner loop. With nested loops, goto is a way to break out of all the loops in one jump.
Charles
Yes, I meant `break 2;` or `break(2)` which should break out of a loop and its parent... which I thought was a C# feature, but when looking for it, apparently it isn't. I swear I've seen it somewhere, though... in some language.
Atømix
@Atomiton: Java has labeled breaks. IMHO, C# should add them as well. I almost never need them, but when I do, it's a pain to code around without them.
BlueRaja - Danny Pflughoeft
@Gary, PHP has `break n;` and `continue n;`.
Rob
+2  A: 

In addition to all of these nice valid things, when you are looking at disassembled code keep in mind that the developers COULD have used an obfuscator on those assemblies. One technique of obfuscation is adding random goto's to the IL

Muad'Dib
+1  A: 

Take a look at a state diagram. If you believe that the best code structure to use is the one that most directly and clearly expresses your intent, then every one of those state transitions should be coded as a goto.

This tends to break down in the real world, though. The first issue is that we often need to halt the machine, exit out to other code, and resume the machine later - meaning that every one of those transitions tends to be a change to state variable, used to identify the correct state in a switch/case statement. This is really just a way to hide and delay the goto - writing to a state variable isn't much different to writing to the program-counter register, really. It's just a way to implement "goto there - but not now, later".

There are cases, though, where a goto works well to express what is happening in some kind of state model - I'd guess that an example would be one of those diagnostic flowcharts that doctors sometimes use. If you implement one of those as a program without using gotos for transitions, then really you're just making life difficult for yourself by encrypting the intent of your code.

It's just that by far the most common cases aren't likely to be hand-written code. I've written code generators that generate goto statements for transitions in various kinds of state model (decision handling, regular grammar parsing, etc) but I don't remember the last time I used a goto in hand-written code.

Steve314
A: 

I never even coded with GO TO back when I wrote FORTRAN.

I've never had to use it. I can't see why any modern language would demand such a thing from a user. I'd say unequivocally "no".

duffymo
A: 

goto is perfectly valid for cleanup stuff in languages like C at least, where it somewhat simulates the notion of exceptions. I'm sure that .NET has better ways of handling stuff like this, so goto is just obsolete and error prone.

Maister
.Net *does* have better ways - they're called "methods". :)
MusiGenesis
@MusiGenesis: goto and method calls are not even close to the same. Try to write a Duff's device, nested loop break/continue, fast retry without using gotos. You will either end up with a mess of methods or nested if's and loops. I'd go for the clean goto myself.
Matthew Whited
@Matthew: easy. Nested loops with break/continue can be implemented by basic decomposition – i.e. putting them into an extra method. Same goes for fast retry. As for Duff’s device – you want to use that in C#?! I would rather let the JITter unroll my loops automatically or use block copying algorithms.
Konrad Rudolph
@Konrad: I didn'y say they couldn't be turned into methods. I just said they aren't the same. You can make very performant code in C# (and you may want to check out the Micro .Net Framework.)
Matthew Whited
@Matthew: you said, “Try to write a Duff's device, nested loop break/continue, fast retry without using gotos” – and I showed you how that would work. And I didn’t dispute the performance of .NET. I just disputed the usefulness of trying to outwit the JITter.
Konrad Rudolph
@Konrad: Very true, they could be written with methods. I just get annoyed by the "don't pre-optimize" crowed. Because of my electronics background; I just see the "faster" ways to write the code even when I'm not trying to trick anything.
Matthew Whited
@matthew: I didn't say goto and methods are the same - I said methods are "better". Interestingly, I haven't *needed* to write a Duff's device, nested loop break/continue, or fast retry in the last 29 years or so.
MusiGenesis
@Matthew: we’re on the same page there – I work in bioinformatics and most of what I do centers around implementing algorithms as efficient as possible.
Konrad Rudolph
+3  A: 

Goto's are frequently useful when writing parsers and lexers.

jeffamaphone
Really? I usually just follow the recursive-descent approach...
pst
I'm not an expert, but my parser guy at work tells me recursive-descent is often not the best solution for various reasons.
jeffamaphone
@jeffamaphone - same issue as I describe in my answer. Hand-written parsers use some mix of recursive descent and precedence parsing. Parser generators generate a state model automatically, and generate code to implement that model automatically, and that code may or may not use gotos. The principle is there - the goto may be the best way to implement the state transition - but since it rarely if ever happens in hand-written code, it doesn't prove much. And in any case, many parser generators don't generate gotos because other issues mean the goto isn't necessarily applicable.
Steve314
Well, you have to implement tail recursion in things like StatemenList, etc. by loops. But otherwise you can really get by with recursive decent. I would only switch to tables if there is a significant performance improvment and it was actually measured. Recursive Decent parsers are much easier to debug so I personally stick with them.
Carsten Kuckuk
CORRECTION: Gotos are frequently used when writing lexers.
Joshua
A somewhat easy way to understand their usefulness is to take a look at some of the code ANTLR generates, see how many `goto`s there are, and then try rewriting the lexer/parser without them.
Allon Guralnek
+28  A: 

Reflector is not perfect. The actual code of this method is available from the Reference Source. It is located in ndp\fx\src\xsp\system\web\security\admembershipprovider.cs:

        if( passwordStrengthRegularExpression != null )
        { 
            passwordStrengthRegularExpression = passwordStrengthRegularExpression.Trim();
            if( passwordStrengthRegularExpression.Length != 0 ) 
            { 
                try
                { 
                    Regex regex = new Regex( passwordStrengthRegularExpression );
                }
                catch( ArgumentException e )
                { 
                    throw new ProviderException( e.Message, e );
                } 
            } 
        }
        else 
        {
            passwordStrengthRegularExpression = string.Empty;
        }

Note how it failed to detect the last else clause and compensated for it with a goto. It is almost certainly tripped-up by the try/catch blocks inside the if() statements.

In case you are interested in reading actual commented source code instead of the disassembled version of it, take a look at the .NET Mass Downloader project.

Hans Passant
Sweet - thanks for posting that. That code looks a whole lot better :D Sorry I doubted you MS programmers, must be sleep deprivation clouding my judgement ;)
BenAlabaster
Not to disappoint you but the .NET framework code contains goto statements. Not many, but where used they always *clarify* the code flow.
Hans Passant
And as always, it should be noted that goto's still have their place. They are a useful tool, just like any other...so long as it is not abused (like so many others), it should still be a viable tool.
jrista
It should also be noted that all loops and branches are really goto's and looking at the IL (especially optimized release code) you have no way to tell the original from other models. http://stackoverflow.com/questions/2542289/is-there-ever-a-reason-to-use-goto-in-modern-net-code/2542416#2542416
Matthew Whited
A: 

I don't like that code.

I would prefer to store the Regex in the member, and validate it when setting it, avoiding all of the need for logic when reading it.

kyoryu
+2  A: 

With respect to this point:

So - is there a good reason for code like this that I'm missing? Was this code extract just put together by a shitty developer? or is .NET reflector returning inaccurate code?

I disagree with the premise that these are the only three possibilities.

Maybe it's true, as many others have suggested, that this simply isn't an accurate reflection of the real source code in the library. Regardless, we've all been guilty (well, I have, anyway) of writing code "the dirty way" for the purpose of:

  1. Getting a feature implemented quickly
  2. Fixing a bug quickly
  3. Squeezing out a slight performance gain (sometimes with justification, sometimes not so much)
  4. Some other reason that made sense at the time

That doesn't make someone a "shitty developer." Most guidelines such as "thou shalt not use goto" are mainly put in place to protect developers from themselves; they shouldn't be treated as a key for distinguishing between good and bad developers.

As an analogy, consider the simple rule many of us are taught in grade school English: never end a sentence with a preposition. This isn't a real rule; it's a guideline to help prevent people from saying things like, "Where's the car at?" It's important to understand this fact; once you start treating it like an actual rule, instead of a guideline, you'll find yourself "correcting" people for perfectly good sentences like "What are you afraid of?"

With this in mind, I'd be wary of any developer who called another developer "shitty" because he used goto.

I'm certainly not trying to defend goto, per se--just arguing that its use doesn't indicate incompetence, by any means.

Dan Tao
+6  A: 

I'm not crazy about gotos, but to say that they're never valid is silly.

I used one once to fix a defect in a particularly messy piece of code. To refactor the code and test it would not have been practical given the time constraint.

Besides, haven't we all seen conditional constructs that were so poorly coded that they make gotos seem benign?

uncle brad
Your last sentence is a good point.
MusiGenesis
A: 

As other's have shown the code you see in reflector is necessarily the code that is written in the Framework. The compiler and optimizers can change code around to something that functions in a similar manner as long as it does not change the actual work done by the code. It should also be stated that the compiler implements all branches and loops as goto's (branches in IL, or jumps in assembly.) When the release mode is ran and the compiler tries to optimizes code to the simplest form that is functionally the same as your source.

I have an example on different looping techniques that are all compiled to 100% the same IL when you compile for release. See Other Answer

(I can't find it right now but Eric Lippert posted an note on how the C# compiler processes code. One of the points he made is how all loops are changed to goto's.)

That being said, I have no problem with goto. If there is a better looping structure, use it. But sometimes you need something slightly then what you can squeeze out of for, foreach, while, do/while but you don't wanted the added mess and pain that comes from method calls (why waste 5 plus lines to convert a nested for into recursive methods.)

Matthew Whited
A: 

I've wanted a good excuse to write a GOTOstatement. I'd make a label called Hell or JAIL_DO_NOT_COLLECT_TWO_HUNDRED_DOLLARS.

Atømix
+2  A: 

There are several valid uses for goto in .NET (C# specifically):

Simulating Switch Statement Fall-through Semantics.

Those coming from a C++ background are used to writing switch statements which automatically fall-through from case to case unless explicitly terminated with break. For C#, only trivial (empty) cases fall-through.

For example, in C++

int i = 1;
switch (i)
{
case 1:
  printf ("Case 1\r\n");
case 2:
  printf ("Case 2\r\n");
default:
  printf ("Default Case\r\n");
  break;
}

In this C++ code the output is:

Case 1
Case 2
Default Case

Here is similar C# code:

int i = 1;
switch (i)
{
case 1:
  Console.Writeline ("Case 1");
case 2:
  Console.Writeline ("Case 2");
default:
  Console.Writeline ("Default Case");
  break;
}

As written, this will not compile. There are several compilation errors that look like this:

Control cannot fall through from one case label ('case 1:') to another

Adding goto statements make it work:

int i = 1;
switch (i)
{
case 1:
    Console.WriteLine ("Case 1");
    goto case 2;
case 2:
    Console.WriteLine("Case 2");
    goto default;
default:
    Console.WriteLine("Default Case");
    break;
}

... the other useful goto use in C# is...

Infinite Loops and Unrolled Recursion

I won't got into detail here since it is less useful, but occasionally we write infinite loops using while(true) constructs that are explicitly terminated with a break or re-executed with a continue statement. This might happen when we are trying to simulate recursive method calls but don't have any control over the potential scope of the recursion.

You can obviously refactor that into a while(true) loop or refactor it into a separate method, but also using a label and a goto statement works.

This use of goto is more debatable, but still something worth keeping in your mind as an option in very rare circumstances.

Simon Gillbee
A: 

This may not be the best example but it does show a case where goto can be very handy.

private IDynamic ToExponential(Engine engine, Args args)
{
    var x = engine.Context.ThisBinding.ToNumberPrimitive().Value;

    if (double.IsNaN(x))
    {
        return new StringPrimitive("NaN");
    }

    var s = "";

    if (x < 0)
    {
        s = "-";
        x = -x;
    }

    if (double.IsPositiveInfinity(x))
    {
        return new StringPrimitive(s + "Infinity");
    }

    var f = args[0].ToNumberPrimitive().Value;
    if (f < 0D || f > 20D)
    {
        throw new Exception("RangeError");
    }

    var m = "";
    var c = "";
    var d = "";
    var e = 0D;
    var n = 0D;

    if (x == 0D)
    {
        f = 0D;
        m = m.PadLeft((int)(f + 1D), '0');
        e = 0;
    }
    else
    {
        if (!args[0].IsUndefined) // fractionDigits is supplied
        {
            var lower = (int)Math.Pow(10, f);
            var upper = (int)Math.Pow(10, f + 1D);
            var min = 0 - 0.0001;
            var max = 0 + 0.0001; 

            for (int i = lower; i < upper; i++)
            {
                for (int j = (int)f;; --j)
                {
                    var result = i * Math.Pow(10, j - f) - x;
                    if (result > min && result < max)
                    {
                        n = i;
                        e = j;
                        goto Complete;
                    }
                    if (result <= 0)
                    {
                        break;
                    }
                }

                for (int j = (int)f + 1; ; j++)
                {
                    var result = i * Math.Pow(10, j - f) - x;
                    if (result > min && result < max)
                    {
                        n = i;
                        e = j;
                        goto Complete;
                    }
                    if (result >= 0)
                    {
                        break;
                    }
                }
            }
        }
        else
        {
            var min = x - 0.0001;
            var max = x + 0.0001; 

            // Scan for f where f >= 0
            for (int i = 0;; i++)
            {
                // 10 ^ f <= n < 10 ^ (f + 1)
                var lower = (int)Math.Pow(10, i);
                var upper = (int)Math.Pow(10, i + 1D);
                for (int j = lower; j < upper; j++)
                {
                    // n is not divisible by 10
                    if (j % 10 == 0)
                    {
                        continue;
                    }

                    // n must have f + 1 digits
                    var digits = 0;
                    var state = j;
                    while (state > 0)
                    {
                        state /= 10;
                        digits++;
                    }
                    if (digits != i + 1)
                    {
                        continue;
                    }

                    // Scan for e in both directions
                    for (int k = (int)i; ; --k)
                    {
                        var result = j * Math.Pow(10, k - i);
                        if (result > min && result < max)
                        {
                            f = i;
                            n = j;
                            e = k;
                            goto Complete;
                        }
                        if (result <= i)
                        {
                            break;
                        }
                    }
                    for (int k = (int)i + 1; ; k++)
                    {
                        var result = i * Math.Pow(10, k - i);
                        if (result > min && result < max)
                        {
                            f = i;
                            n = j;
                            e = k;
                            goto Complete;
                        }
                        if (result >= i)
                        {
                            break;
                        }
                    }
                }
            }
        }

    Complete:

        m = n.ToString("G");
    }

    if (f != 0D)
    {
        m = m[0] + "." + m.Substring(1);
    }

    if (e == 0D)
    {
        c = "+";
        d = "0";
    }
    else
    {
        if (e > 0D)
        {
            c = "+";
        }
        else
        {
            c = "-";
            e = -e;
        }
        d = e.ToString("G");
    }

    m = m + "e" + c + d;
    return new StringPrimitive(s + m);
}
ChaosPandion
A: 

You can use a GOTO to perform recursion with better performance. It's a lot harder to maintain, but if you need those extra cycles you may be willing to pay the maintenance burden.

Here's a simple example, with results:

class Program
{
    // Calculate (20!) 1 million times using both methods.
    static void Main(string[] args)
    {
        Stopwatch sw = Stopwatch.StartNew();
        Int64 result = 0;
        for (int i = 0; i < 1000000; i++)
            result += FactR(20);
        Console.WriteLine("Recursive Time: " + sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        result = 0;
        for (int i = 0; i < 1000000; i++)
            result += FactG(20);
        Console.WriteLine("Goto Time: " + sw.ElapsedMilliseconds);
        Console.ReadLine();
    }

    // Recursive Factorial
    static Int64 FactR(Int64 i)
    {
        if (i <= 1)
            return 1;
        return i * FactR(i - 1);
    }

    // Recursive Factorial (using GOTO)
    static Int64 FactG(Int64 i)
    {
        Int64 result = 1;

    Loop:
        if (i <= 1)
            return result;

        result *= i;
        i--;
        goto Loop;
    }

Here are the results I get on my machine:

 Recursive Time: 820
 Goto Time: 259
Matt Brunell