September 09, 2022
On Thursday, 8 September 2022 at 22:49:05 UTC, Walter Bright wrote:
> goto can be handy to avoid needing to refactor a bunch of code when fixing a problem.
>
> The refactoring can come later in its own PR.

It almost never does though, let's be realistic.
September 08, 2022
On Fri, Sep 09, 2022 at 12:26:44AM +0000, max haughton via Digitalmars-d wrote:
> On Thursday, 8 September 2022 at 22:49:05 UTC, Walter Bright wrote:
> > goto can be handy to avoid needing to refactor a bunch of code when fixing a problem.
> > 
> > The refactoring can come later in its own PR.
> 
> It almost never does though, let's be realistic.

IME, typically code stinks come about this way:

1) Original code is reasonably clean and well-written.

2) A critical bug is discovered 2 days before the release deadline.

3) In the mad rush to get the release out the door, Good-Hearted
   Programmer #1 pulls an all-nighter to fix the bug by any means
   possible. He comforts himself, "I will clean up this messy hack code
   after the release."

4) Thanks to Good-Hearted Programmer #1's heroic efforts, the release
   makes it out the door on time.  There is celebration, and
   Good-Hearted Programmer #1 says to himself, I'll relax for a couple
   o' days to recover from the release.

5) But Just as Good Hearted Programmer #1 is about to clean up the hack
   code, PTB walks in and hands him High Priority Project X that has to
   be done by last week.  He gets totally occupied with Project X and
   forgets about cleaning up the code.

6) Meanwhile, another release deadline looms, and another bug is
   discovered in the code. Good Hearted Programmer #2 is assigned to fix
   it, and, not understanding the hack that GHP#1 has done, says to
   himself, "There's no time to figure this out, I'll just patch over
   the code and redo the fix properly after the release."

Steps (4)-(5) are repeated, now to GHP#2, and (6) is repeated with GHP#3.  Soon, GHP#1, GHP#2, and GHP#3 have moved on to other projects or to a different company altogether.  And so layer upon layer of hacks and bandages are accumulated on top of the code, the well-intentioned cleanups never happen.  Soon, so much cruft has accumulated that nobody knows how to clean it up anymore. Instead, the bugs and quirky behaviours are worked around and patched over, and customers begin relying on the quirky behaviour, further cementing it forever.


T

-- 
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
September 08, 2022
On 9/8/2022 5:26 PM, max haughton wrote:
>> The refactoring can come later in its own PR.
> It almost never does though, let's be realistic.

Quite a few of my PRs are refactorings.
September 09, 2022

On Thursday, 8 September 2022 at 17:04:28 UTC, IGotD- wrote:

>

Anyway, I haven't used goto a lot in C/C++ other than in "roll back error handling". D manage to do this even better with with its scope guards. How does other languages handle "roll back error handling" (is there a better terminology for this?).

Exceptions?

Goto is useful when implementing state machines, the resulting code is often more readable.

September 09, 2022

On Thursday, 8 September 2022 at 16:33:58 UTC, AnimusPEXUS wrote:

>

There was a discussion sometime ago in a Russian Dlang Telegram chat about 'goto' keyword. And there was some empiric theory, stating 'all good languages support goto statement'. Nor Rust, nor Carbon, nor Zig will never going to overcome D or C++
because of this. Language should give possibilities, not take them away.

This is what Zig did see https://github.com/ziglang/zig/issues/630.
I think that the rationale is quite good. Goto solves almost no problem.

>

And in some cases, goto able to make code more readable, more sane and more understandable. Also, goto is much safer in language with GC.

That's a good point.

>

corresponding section in wikipedia

See also https://wiki.c2.com/?GoodUseOfGoto

September 09, 2022
On Thursday, 8 September 2022 at 22:47:33 UTC, Walter Bright wrote:
> To be fair, nested functions along with function inlining has eliminated many of the reasons that I use gotos.
>
> Another reason for gotos is for ways of exiting loops without having to set flags that later control the flow.

I find it surprising that no language added something like "break all;" instruction to exit all loops.
September 09, 2022

On Friday, 9 September 2022 at 09:30:21 UTC, JN wrote:

>

On Thursday, 8 September 2022 at 22:47:33 UTC, Walter Bright wrote:

>

To be fair, nested functions along with function inlining has eliminated many of the reasons that I use gotos.

Another reason for gotos is for ways of exiting loops without having to set flags that later control the flow.

I find it surprising that no language added something like "break all;" instruction to exit all loops.

D can break on labels, which is even more powerful than that. To be honest, I don't recall ever using it in my own code, but it works.


import core.stdc.stdio: printf;

void main()
{
    outer: for (size_t i = 0; i < 4; i++) {
        for (size_t j = 0; j < 4; j++) {
            if (i * j > 4) {
             	break outer;
            }
         	printf("i = %lu, j = %lu\n", i, j);
        }
        printf("i = %lu\n", i);
    }
}
September 09, 2022

On Thursday, 8 September 2022 at 22:47:33 UTC, Walter Bright wrote:

>

To be fair, nested functions along with function inlining has eliminated many of the reasons that I use gotos.

Another reason for gotos is for ways of exiting loops without having to set flags that later control the flow.

Yeah, there's this code from dmd/dsymbolsem.d:

    if (FuncDeclaration func = sc.parent.isFuncDeclaration())
    {
        tm.symtab = func.localsymtab;
        if (tm.symtab)
        {
            // Inside template constraint, symtab is not set yet.
            goto L1;
        }
    }
    else
    {
        tm.symtab = sc.parent.isScopeDsymbol().symtab;
    L1:
        assert(tm.symtab);
        tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
        tm.symtab.insert(tm);
    }

You can write it as:

    (){
        if (FuncDeclaration func = sc.parent.isFuncDeclaration())
        {
            tm.symtab = func.localsymtab;
            if (!tm.symtab) return;
            // Inside template constraint, symtab is not set yet.
        }
        else
            tm.symtab = sc.parent.isScopeDsymbol().symtab;
    //L1:
        assert(tm.symtab);
        tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
        tm.symtab.insert(tm);
    }();

I'd prefer to write it as:

    switch
    {
        if (FuncDeclaration func = sc.parent.isFuncDeclaration())
        {
            tm.symtab = func.localsymtab;
            if (!tm.symtab) break;
            // Inside template constraint, symtab is not set yet.
        }
        else
            tm.symtab = sc.parent.isScopeDsymbol().symtab;
    //L1:
        assert(tm.symtab);
        tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
        tm.symtab.insert(tm);
    }

Where switch works like switch(0) default: today.

Using the function literal call means you can't return from the containing function, which may be needed.

September 09, 2022

On Friday, 9 September 2022 at 14:03:57 UTC, Nick Treleaven wrote:

>

I'd prefer to write it as:

    switch
    {
        if (FuncDeclaration func = sc.parent.isFuncDeclaration())
        {
            tm.symtab = func.localsymtab;
            if (!tm.symtab) break;
            // Inside template constraint, symtab is not set yet.
        }
        else
            tm.symtab = sc.parent.isScopeDsymbol().symtab;
    //L1:
        assert(tm.symtab);
        tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
        tm.symtab.insert(tm);
    }

Where switch works like switch(0) default: today.

I think maybe a more intuitive keyword for this would be do:

do
{
    // ...
    if (whatever) break;
    // ...
}

...which would work like do { ... } while (0); currently does.

September 09, 2022

On 9/9/22 10:03 AM, Nick Treleaven wrote:

>

I'd prefer to write it as:

     switch
     {
         if (FuncDeclaration func = sc.parent.isFuncDeclaration())
         {
             tm.symtab = func.localsymtab;
             if (!tm.symtab) break;
             // Inside template constraint, symtab is not set yet.
         }
         else
             tm.symtab = sc.parent.isScopeDsymbol().symtab;
     //L1:
         assert(tm.symtab);
         tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
         tm.symtab.insert(tm);
     }

Where switch works like switch(0) default: today.

Using the function literal call means you can't return from the containing function, which may be needed.

Instead of switch, you can use:

do {
   ...
} while(false);

And then use a break inside. But honestly, all this looks like "I want to avoid goto at all costs". The original looks better to me.

Another possibility that uses goto, but might be preferred, is:

    if (FuncDeclaration func = sc.parent.isFuncDeclaration())
    {
        tm.symtab = func.localsymtab;
        if (!tm.symtab)
        {
            // Inside template constraint, symtab is not set yet.
            goto L1;
        }
    }
    else
    {
        tm.symtab = sc.parent.isScopeDsymbol().symtab;
    }
    assert(tm.symtab);
    tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
    tm.symtab.insert(tm);
L1:

-Steve