I am TRWTF - compiler can't guess the keyword



  • Stared at this for 10 minutes this morning, trying to figure out why the controls were always showing disabled even though the database was connecting :rolleyes:

        private void PoForm_Shown(object sender, EventArgs e)
        {
            if (db.ConnectToDatabase())
            {
                EnableControls(true);
                lblInfo.Text = "Select PO";
            }
            {
                lblInfo.Text = db.Error;
                EnableControls(false);
            }
        }


  • Why does a method named EnableControls disable controls?


  • SockDev

    Compiler is not TRWTF. That's perfectly cromulent code in most C-likes and the main reason braces-on-their-own-line is a thing, so you can comment out the if (or in this case, the missing else) and things won't grind to a halt syntactically.



  • Oh - I'm quite happy to state that I'm TRWTF, not the compiler!



  • Good question. It's a pattern / name that I've used for years, across languages, but never really thought about it.
    Now that you raise the question I can see that it would be better called SetEnabledState(bool yezOrNoes)



  • And because is uglier... look at those braces all alone!



  • @skotl said:

    Oh - I'm quite happy to state that I'm TRWTF, not the compiler!
    You're not the only one. I was looking at it for two minutes and said it aloud a few times before I spotted the missing else.



  • Thank $DEITY for that - thought I was the only one :smile:


  • Discourse touched me in a no-no place

    @Arantor said:

    That's perfectly cromulent code in most C-likes and the main reason braces-on-their-own-line is a thing, so you can comment out the if (or in this case, the missing else) and things won't grind to a halt syntactically.

    In C and C++, braces-on-their-own is how you make a local scope. It's somewhat useful in C, and vital in C++.


  • SockDev

    The same applies to pretty much every C-family language.

    Apart from JavaScript. Because JavaScript is special like that.


  • SockDev

    In PHP, of course, you can do it anyway and it doesn't affect scope as far as I know.

    But seriously, you make a new local scope inside a function?!


  • Discourse touched me in a no-no place

    @Arantor said:

    But seriously, you make a new local scope inside a function?!

    Yes. Why is this remarkable?


  • BINNED

    @Arantor said:

    But seriously, you make a new local scope inside a function?!

    With RAII, it means you can more precisely control the lifetime of an object. It also allows you to reuse a name for different types of objects, but I can't think of a reason for doing that that wouldn't be :doing_it_wrong:


  • SockDev

    I come from PHP, where the scopes are 'global' and 'local to a function' and that always seemed like enough to me. Scoping inside a function seems a bit like :wtf: to me because I've never encountered a situation where it would actually help...


  • BINNED

    Is this the time for me to try and explain scoping in Asterisk? :stuck_out_tongue:


  • SockDev

    I want to keep my sanity plz?


  • BINNED

    Correct answer.



  • @Arantor said:

    I want to keep my sanity plz?
    Being a member here you've already lost it. Why not keep tumbling down the rabbit hole?


  • Discourse touched me in a no-no place

    @Arantor said:

    But seriously, you make a new local scope inside a function?!

    Convenient workaround for the stricter compilers/options using earlier standards that normally require all variable definitions at the top of the function - introducing the local scope allows you to have them further down the function.

    [version:root@centos tmp]# cat -n scope.c
         1  #include <stdio.h>
         2  int main(void){
         3          int i=0;
         4          printf("%d\n", i);
         5  /* lots more lines, some using i */
         6          int j=4;
         7          printf("%d\n", j);
         8  /*couple of lines using j, then it's no longer used*/
         9          return 0;
        10  }
        11  
        12  
    [version:root@centos tmp]# gcc  -pedantic scope.c -o scope 
    scope.c: In function โ€˜mainโ€™:
    scope.c:6: warning: ISO C90 forbids mixed declarations and code
    [version:root@centos tmp]# gcc
    
    [version:root@centos tmp]# cat -n scope2.c
         1  #include <stdio.h>
         2  int main(void){
         3          int i=0;
         4          printf("%d\n", i);
         5  /* lots more lines, some using i */
         6          {
         7                  int j=4;
         8                  printf("%d\n", j);
         9          /*couple of lines using j, then it's no longer used*/
        10          }
        11          return 0;
        12  }
        13  
        14  
    [version:root@centos tmp]# gcc  -pedantic scope2.c -o scope 
    [version:root@centos tmp]# gcc
    

  • area_deu

    @Arantor said:

    I come from PHP, where the scopes are 'global' and 'local to a function' and that always seemed like enough to me.

    What, loops and ifs don't cause scope in PHP?!


  • SockDev

    @aliceif said:

    @Arantor said:
    I come from PHP, where the scopes are 'global' and 'local to a function' and that always seemed like enough to me.

    What, loops and ifs don't cause scope in PHP?!

    nope. nor do they in Javascript, at least if you use the var keyword.

    var creates function scoped variables

    let and const introduce block scoped variables, but they require you to be in strict mode, and to get full advantage of them in ES6 mode to boot.


  • SockDev

    They don't in JS either, at least, not for vars; lets and consts are block scoped, though they only exist in ES6, which isn't- and :hanzo:'d by the missus :blush:


  • SockDev

    Nope. A variable declared inside an if or loop remains in scope until end of function/method. Which is also an interesting caveat with a for() loop where the iterator variable continues to exist until the end of function, as well as foreach.

    Which is really good if you do this:

    function my_function($array) {
        foreach ($array as $key => &$reference_to_current_value) {
            // do stuff
        }
    
        // $reference_to_current_value not only still exists here, but it's still a reference to the last item in $array
        // which has bitten my arse on occasion.
    }
    


  • @DogsB said:

    Why not keep tumbling down the rabbit hole?

    He's working with Asterix and PHP how much deeper in the rabbit hole can you go?


  • SockDev

    That's @Onyx; I only do the PHP rabbit hole.



  • @Arantor said:

    That's @Onyx; I only do the PHP rabbit hole.

    :confusius:

    :scroll up:

    :scroll down:

    :oeps:


  • Discourse touched me in a no-no place

    @Arantor said:

    Scoping inside a function seems a bit like :wtf: to me because I've never encountered a situation where it would actually help.

    It's vital in C++ where there's potentially non-trivial semantics attached to a value coming into existence and ceasing to be. The classic I've seen is locking done by RAII where lock-acquisition is done by declaring a variable of the right type and the lock is dropped by falling out that scope. The language semantics make some pretty strong guarantees about this, even in the presence of exceptions.

    It's not so important with C, where some compilers just do inner scopes by using under-the-covers renaming. It wouldn't be so bad, except that they don't reduce the size of the activation recordโ€ฆ


  • SockDev

    Yeah, in PHP things falling out of scope is typically less scary and generally PHP is not designed for cases where such semantics should actually be necessary.



  • That's essential in case you need to use similarly constructed code in switch statement in C#.

    switch (a)
    {
    	case 1:
    		SomeClass b = new SomeExtendedClassA();
    		c = b.SomeMethod();
    		break;
    	case 2:
    		SomeClass b = new SomeExtendedClassB();	// This will throw error
    		c = b.SomeMethod();
    		break;
    }
    

    Compare to this one:

    switch (a)
    {
    	case 1:
    		{
    			SomeClass b = new SomeExtendedClassA();
    			c = b.SomeMethod();
    		}
    		break;
    	case 2:
    		{
    			SomeClass b = new SomeExtendedClassB();	// This will NOT throw error
    			c = b.SomeMethod();
    		}
    		break;
    }

  • SockDev

    Wait, why will that throw an error?

    My reference point is PHP which won't throw an error on that!


  • SockDev

    In C#, code in cases is scoped to the enclosing switch if you don't use braces.



  • On the error line it'll tell you that you already have variable "b" declared at that point.

    Confine it in local scope helps to solve the problem.


  • SockDev

    Oh, I see now. I should have remembered that PHP was :doing_it_wrong: in something like this...



  • @cheong said:

    That's essential in case you need to use similarly constructed code in switch statement in C#.

    God, that's butt-ugly. Why would you ever not declare the variable in the outer scope?


  • SockDev

    So the object doesn't hang around longer than necessary? Then again, if you want the object lifetime to be that short, it should be IDisposable, and wrapped in a using block.



  • This post is deleted!


  • Bear in mind that it's just some code I make up to demonstrate the problem.

    Btw, my original rant for the change of behavior here.



  • private void PoForm_Shown(object sender, EventArgs e) {
    if (db.ConnectToDatabase()) {
    EnableControls(true);
    lblInfo.Text = "Select PO";
    } {
    lblInfo.Text = db.Error;
    EnableControls(false);
    }
    }

    There. Now that your braces are in the right places, the problem is much more obvious.


  • SockDev

    @RaceProUK said:

    if you don't use braces.

    :anger:

    braces are never optional!

    i don't care if all you do in that if is literally return null;! you use the braces!

    because OMITTING BRACES IS HOW BUGS GET MADE!!!!1!!1!!!111


  • BINNED

    @anotherusername said:

    private void PoForm_Shown(object sender, EventArgs e) {
    if (db.ConnectToDatabase()) {
    EnableControls(true);
    lblInfo.Text = "Select PO";
    } {
    lblInfo.Text = db.Error;
    EnableControls(false);
    }
    }

    There. Now that your braces are in the right places, the problem is much more obvious.

    Ewww! Get out!



  • About a million things is how bugs get made. The braces seem unnecessary in a switch.


  • SockDev

    *makes a note to never show @accalia any of her C# code...*


  • SockDev

    @loopback0 said:

    About a million things is how bugs get made

    i made no claim that my statement was exclusive of any other bug copulating method.

    @loopback0 said:

    The braces seem unnecessary in a switch.

    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:
    :anger::anger::anger::anger::anger::anger::anger::anger::anger:

    ..... oooh.... pretty pattern


  • BINNED

    @accalia said:

    @RaceProUK said:
    if you don't use braces.

    :anger:

    braces are never optional!

    i don't care if all you do in that if is literally return null;! you use the braces!

    because OMITTING BRACES IS HOW BUGS GET MADE!!!!1!!1!!!111

    Maybe we should advocate for languages to add ACBI as a standard...

    :trolleybus:


  • SockDev

    @Onyx said:

    ACBI

    twitch

    That's it!

    NO SOUP FOR YOU!


  • SockDev

    @accalia said:

    NO SOUP FOR YOU!

    How can you deny a person's basic right to soup?



  • Why are they necessary?

    Unless you're doing stuff like reusing variable names, I can't see how using them is any less likely to cause bugs than not using them.


  • SockDev

    I think the reasoning is if statements get added later, but the braces don't. Then again, any decent editor will make it painfully obvious what's wrong via indenting.



  • @loopback0 said:

    Why are they necessary?

    Do a google search for "goto fail".



  • @NedFodder said:

    Do a google search for "goto fail".

    That isn't a switch statement. You should goto fail;

    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
        goto fail;
        goto fail;  /* MISTAKE! THIS LINE SHOULD NOT BE HERE */
    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
        goto fail;
    

Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.