32

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 an inept 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

ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
BenAlabaster
  • 39,070
  • 21
  • 110
  • 151
  • 26
    I'm guessing you found this via Reflector. This is not neccesarily the actual code they wrote. – Foole Mar 30 '10 at 01:47
  • What MembershipProvider is this from? Just curious. – Daniel Ballinger Mar 30 '10 at 01:52
  • 11
    I can say that holding "Microsoft programmers" in high or low regard is not a good idea. It is too large and too diverse a company to permit a gross analysis of its skill level. You can't run an organization that large without your fair share of bad apples and you can't have that much money without being able to hire a few good ones. –  Mar 30 '10 at 02:15
  • 1
    @Daniel Ballinger - If you figured out that it was part of a membership provider in that short time, it should take you all of 3 minutes to figure out which one ;) – BenAlabaster Mar 30 '10 at 02:15
  • @MaxGuernseylll - I did say "fairly" high... after all, they got through MS's vetting - I don't seem to be able to get them to even return my phone calls :P – BenAlabaster Mar 30 '10 at 02:17
  • 1
    there is, some are just afraid to give examples for fear of being downvoted. goto should be used only for jumping forward(here's one example: http://stackoverflow.com/questions/863172/how-can-i-break-out-of-two-nested-for-loops-in-objective-c/863392#863392), jumping backward is already provided by loops, another good example is Donald Knuth's prime numbers generator, i read it in my C book(was borrowed, forgot to return), the code is elegant, i just can't seem to find it in net. – Michael Buen Mar 30 '10 at 02:41
  • 1
    Seems like it is System.Web.Security.ActiveDirectoryMembershipProvider http://msdn.microsoft.com/en-us/library/system.web.security.activedirectorymembershipprovider.aspx – Daniel Ballinger Mar 31 '10 at 20:02
  • 6
    I think all `GOTO` statements should be paired with descriptive labels... like `OVER_THERE`, `HELL`, `JAIL` and `BED` – Armstrongest Apr 01 '10 at 16:58

20 Answers20

45

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.

Clearly you'll want to favor the actual source code instead of the decompiled version. The comments in themselves are quite helpful and you can count on the source being accurate. Well, mostly accurate, there's some minor damage from a buggy post-processing tool that removed the names of the Microsoft programmers. Identifiers are sometimes replaced by dashes and the code is repeated twice. You can download the source here.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 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 Mar 30 '10 at 02:13
  • 3
    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 Mar 30 '10 at 02:34
  • 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 Mar 30 '10 at 05:28
  • 1
    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 Mar 30 '10 at 11:05
  • 1
    I love how this answer didn't actually answer the question in the subject line. – marknuzz Oct 10 '13 at 00:34
12

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

heisenberg
  • 9,665
  • 1
  • 30
  • 38
  • But would you still have a variable labeled '_PasswordStrengthRegularExpression' and not some random character set? – John MacIntyre Mar 30 '10 at 01:39
  • 2
    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 Mar 30 '10 at 01:43
  • 1
    @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. – heisenberg Mar 30 '10 at 01:43
  • That would make sense. Thanks – John MacIntyre Mar 30 '10 at 02:06
  • +1 for pointing out that it's probably not actually in the code. –  Mar 30 '10 at 02:14
12

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

How can I break out of two nested for loops in Objective-C?

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

Community
  • 1
  • 1
Maynza
  • 748
  • 5
  • 18
  • 1
    Couldn't you use `break [n]`? – Armstrongest Apr 01 '10 at 16:54
  • @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. – Igby Largeman Apr 07 '10 at 05:00
  • 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. – Armstrongest Apr 07 '10 at 13:33
  • @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 Apr 09 '10 at 19:45
  • @Gary, PHP has `break n;` and `continue n;`. – Rob Jul 02 '10 at 17:44
  • 2
    I can only imagine what bugs are introduced with `break n` over time as code is maintained, possibly copied & repurposed, and the new programmer does not correctly update `n`. – Eric J. Aug 03 '13 at 18:33
  • @EricJ. - Excellent observation. This is probably why Java uses labeled breaks instead of break with a number. – ArtOfWarfare Sep 15 '13 at 16:23
11

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
  • 3,932
  • 4
  • 35
  • 48
8

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?

5

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
  • 10,141
  • 3
  • 34
  • 46
4

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
  • 123,721
  • 27
  • 225
  • 246
  • I agree, I'm thinking this is something the compiler has changed from the original source code. – Daniel Ballinger Mar 30 '10 at 01:37
  • 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 Mar 30 '10 at 01:38
  • 1
    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 Mar 30 '10 at 01:38
  • @Daniel: Yeah, that doesn't look like a label a human would invent. – Eric J. Mar 30 '10 at 01:39
  • 2
    @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 Mar 30 '10 at 01:40
  • 2
    @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. – heisenberg Mar 30 '10 at 01:40
  • @Anthony - I got the joke, don't worry - all taken in good humour – BenAlabaster Mar 30 '10 at 01:41
  • 1
    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 Mar 30 '10 at 01:45
  • @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 Mar 30 '10 at 01:51
  • @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 Mar 30 '10 at 01:55
  • @itowlson - Do you have a link to that? I'd be interested in getting my hands on it... is it on Codeplex? – BenAlabaster Mar 30 '10 at 02:06
  • @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 Mar 30 '10 at 05:34
  • @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 Mar 30 '10 at 06:01
  • 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 Mar 30 '10 at 08:00
  • 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 Mar 30 '10 at 12:38
3

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.
  • 147,927
  • 63
  • 340
  • 553
  • 4
    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 Mar 30 '10 at 01:40
  • 1
    If I ever use goto in an actual program I will make sure I add a comment about forgiving me for my sins. :) – Maynza Mar 30 '10 at 01:54
3

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
  • 74,184
  • 40
  • 190
  • 334
3

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

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
  • I'm not an expert, but my parser guy at work tells me recursive-descent is often not the best solution for various reasons. – i_am_jorf Mar 30 '10 at 04:49
  • 2
    @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. –  Mar 30 '10 at 05:11
  • 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 Mar 30 '10 at 05:36
  • CORRECTION: Gotos are frequently used when writing lexers. – Joshua Jul 02 '10 at 03:09
  • 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 Sep 24 '10 at 20:47
2

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
  • 28,542
  • 5
  • 55
  • 68
2

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.

  • I've sometimes argued that state variables should really be viewed not as number-holders, but rather than selectors among different versions of the code. For example, a piece of code which has two flags, both of which may independently true or false, is equivalent to four pieces of code, one in which both flags are false, one where the first is true, one where (only) the second is true, and one where both are true. Conditional tests on the flags become either "if false" or "if true", while a write to the flag in one version of the code is a "goto" to the corresponding spot in another. – supercat May 13 '12 at 15:42
  • 1
    While such an approach may seem extreme, it merely makes explicit the actual state transitions represented by the flags. Consider that if one wanted to, one could use state variables to write a program with only a single "while" loop (surrounding everything) and only simple "if" statements, but that would hardly be the clearest way of expressing things. A lot of programmers use state variables to "avoid gotos", but often in reality all they're doing is making the state transitions harder to see and understand. – supercat May 13 '12 at 15:45
1

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
  • 125,917
  • 54
  • 300
  • 447
1

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

Community
  • 1
  • 1
Matthew Whited
  • 22,160
  • 4
  • 52
  • 69
0

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
  • 10,126
  • 9
  • 43
  • 46
  • 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 Jul 02 '10 at 02:25
0

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
  • 4,978
  • 1
  • 31
  • 34
  • 2
    .Net *does* have better ways - they're called "methods". :) – MusiGenesis Mar 30 '10 at 02:07
  • @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 Mar 30 '10 at 05:34
  • @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 Mar 30 '10 at 07:36
  • @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 Mar 30 '10 at 10:56
  • @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 Mar 30 '10 at 11:14
  • @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 Mar 30 '10 at 11:28
  • @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 Mar 30 '10 at 12:01
  • @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 Mar 30 '10 at 12:16
0

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
  • 12,848
  • 2
  • 29
  • 33
0

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
  • 77,506
  • 18
  • 119
  • 157
0

No. (The point has been made that in this case it's a de-compiler artefact, mind.)

The only exception is CASE GOTO which allows you to share code between switch cases. This isn't really a GOTO though, it just happens to share the same name.

The issue with the GOTO statement is not ideological like many suggest, it's that there are always better, clearer, more maintainable alternatives in modern high level languages, and using a GOTO always adds complexity, which isn't justified by saving a minute or so coding it properly. It's worth taking the time to use one of those instead, even if it means you have to meet the criteria to exit a number of nested loops or conditions.

Block constructs like WHILE and DO-UNTIL and FOR do looping much better and in a standard form that is inherently obvious to someone maintaining the code, and you can't fall out of the block or forget to terminate it in some code paths. They are inherently better code for that reason. That's why they were invented and widely adopted. You can, of course achieve the same loop thing with a GOTO, but you can also make a mistake somewhere within it (especially if you GOTO a place outside of the loop). These dedicated statements are also optimised for that purpose so they probably save the return address in an more efficient manner than a GOTO finds it's target.

Similarly conditional blocks of code, negate the need to jump over multiple lines that don't apply in a given circumstances (yup, in early languages, a condition could only be applied to a single line of code), and a conditional block is easier to see as an atomic section of code, and the condition is quite clearly specified at the top of the block. If you are using GOTOs there could be several places you jump over it and the code flow has to be carefully and faultlessly worked out each time the code is visited, which is very time consuming and prone to errors and misunderstanding. I used to print out programs and use a highlighter pen to mark up the flow. You don't have to with modern constructs.

Better still, modern best practice would be to encapsulate that conditional functionality into a function with a self explanatory name, so instead of having to read through it to see what it is doing or skip over it, if it's not relevant, you just see a nice little function name that tells you what it does (which of course you can look at in isolation if you need to, and which can use local variables if it needs working variables, that definitely can't interfere with other code elsewhere).

Another issue is stack state. I don't know that .net doesn't check if you are jumping out of a function, or loop, or other block, but traditionally GOTO doesn't do any such checks, which means that any state or local information like local variables, or return addresses stored on the stack, are left on the stack, and when you end up entering that construct again, new copies get added, until eventually the stack overflows. It's the oldest bug in the book; it's even inspired a well known technical Q&A site name.

I used to use GOTO extensively in languages without any alternative 35 years ago, and indeed on retro computers in more recent years (because they still don't have alternatives), but in modern languages, I've not had to since about 1990. I didn't even know it existed in C# until I googled it a month ago following a similar discussion elsewhere.

You might also see people say it's equivalent to a machine code jump. It isn't at all. It very much depends on the language implementation but it has to find the exact memory address to go to, and that can involve a brute force search of the source code (normal in interpreters, where you are most likely to use a GOTO), a vector table lookup (more likely with C# or compiled languages), or some such. It doesn't really matter but it's unlikely to be the equivalent of just loading a hardcoded address into the CPU Program Counter, and even if it is when you write it, it might not be when it's running in an emulated implementation in the future. Dedicated loop constructs are probably more optimised and therefore faster.

-1

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
  • 305,152
  • 44
  • 369
  • 561