TIL (about the Dark Arts of HTML)


  • Java Dev

    @anonymous234 said in TIL (about the Dark Arts of HTML):

    TIL there's these spiral "cable protectors"

    Well, I'm not sure they protect anything, but they make amazing elastic strings! Tie a mouse toy in one end and you have the perfect cat toy (just make sure they don't swallow it, strings are dangerous for cats).

    It costs money, and is so much work to apply, so it must work right?


  • Considered Harmful

    @Tsaukpaetra
    Vinheteiro!
    .
    .
    ☝
    .
    .
    🎼 🎵



  • @anonymous234 said in TIL (about the Dark Arts of HTML):

    Well, I'm not sure they protect anything

    Shittily-made iPhone chargers (because they only have to last a year, amirite) are notorious for breaking here:

    0_1541885932137_frayed-lightning-cable.png

    0_1541886043421_maxresdefault.jpg

    Those "cable protectors" are supposed to add enough stability to that weak point so that it doesn't break.


  • Java Dev

    @anotherusername I think it's a feature for most Apple cabling. The outer layer of my MBA power cable has cracked and broken off, which is... not optimal. But then again, that entire laptop is due for recycling and replacement now.



  • I read some time ago that green olives have a similar chemical to catnip and have the same effect on cats.

    I was skeptical. But I let one of our catnip-sensitive cats smell one and he immediately started slapping the shit out of it.

    So:



  • Not sure whether to put that here or in a :wtf: thread, and maybe C/C++ coders already know it, but here you go...

    If you've ever written a bit of C or C++, you probably know that this is invalid code:

    switch (...) {
        case foo:
            int i = 0;
        ...
    

    But TIL that the following is valid C, but not C++:

    switch (...) {
        case foo: ;
            int i = 0;
        ...
    

    And TIL also that the following is valid C++ but not C:

    switch (...) {
        case foo:
            int i;
            i = 0;
        ...
    

    And various other :wtf: about case that I found in this SO question...


  • BINNED

    @remi Since switch statements work purely the way language lawyers defined them, not the way normal people would guess they work, you might be interested to see Duff's device.



  • @topspin I already knew it, but it seems pretty tame compared to those other things. I mean, it's just using the fact that there is no automatic break (which is something you learn the first time you use a switch) and that the while loops across the labels (which is weird, granted).

    These ones use the fact that "statement" is indeed not really what you intuitively expect in C (a declaration is not a statement), or that C++ forbids "initialisation" of variables but not "declaration". That's one more level of nitpicking.



  • @remi This is what you get for continuing to B♭.



  • @Magus Given the millions of LoC that we have in C++, I think it's rather unlikely that we will ever switch to anything else.

    Now, starting to use more than just C++98 would be nice and is a more realistic goal...


  • BINNED

    @remi said in TIL (about the Dark Arts of HTML):

    and that the while loops across the labels (which is weird, granted).

    That’s the unintuitive part, since only labels can be interleaved like that. Wouldn’t work if each case was a real block, but switch is really just fancy gotos.


  • Java Dev

    @remi

    I don't tend to put variable declarations in the middle of the function, and anyway my compiler warnings only allow them at the start of a block. However I think this works? Too lazy to try.

    switch (...) {
        case foo: {
            int i = 0;
            ...
        } break;
    
        case bar: {
            int i = 0;
            ...
    


  • @PleegWat Yes, that is the usual solution to that problem, and the easiest to understand. Limit the scope of the variable to where you actually want to use it, and all is fine. It also removes the ambiguity about what the scope of the variable actually is, which is one of the gotchas of switch (intuitively, you would expect the scope to be just to the next label, i.e. what happens when adding explicit brackets, but in reality the scope is the switch itself).

    This scope issue means that after "fixing" the code like I showed (for either C or C++), if you enter the switch through another label than foo, then the variable is defined. So the following is, I think, entirely valid (in C):

    switch(...) {
        case foo: ;
            int i = 0;
            break;
        case bar:
            i = 42; // or you could even use i, it would already have value 0
    ...
    

    (same goes for the C++ version using the C++ "fix" I mentioned)

    In fact, you can even go one step further (this was also mentioned in one of the SO answer) and put the declaration outside of any of the case since the scope is actually the switch anyway (and as said by @topspin, case are just labels):

    switch(...) {
        int i = 0;
        case foo:
            i = 41;
            break;
        case bar:
            i = 42;
    ...
    

    (again, same goes for the C++ version if you just put the declaration without initialisation -- I think)

    I knew the things relative to the scope of variables (and I have implemented your solution many times), but I did not knew the subtle C/C++ workarounds that I mentioned in my first post, nor the one about putting the declaration before any case (even though that one follows quite logically from what I already knew). And TBH, I'm still not sure if that should have gone into the TIL thread or a :wtf: thread, because there is no way I'm using either of those in any of my code!


  • Java Dev

    @remi In my book, if putting the declaration at the top of the function separates it too much from its use, your function is too large.


  • 🚽 Regular

    @remi said in TIL (about the Dark Arts of HTML):

    you can even go one step further (this was also mentioned in one of the SO answer) and put the declaration outside of any of the case

    0_1542273324641_545a4989-7857-4142-a181-178ebbc1cb19-image.png

    😵

    So I guess it does the ""right thing"" and consider the outer switch as having no branches.



  • @PleegWat I disagree on that principle, but I think that's part of the things that we (as in, the developers' community) will never agree on.

    To me continuity of purpose in a function is more important that length. I'm happy with a relatively long function that does one complex thing that all ties together, rather than splitting it into several smaller functions that are meaningless outside of the wider context. Although I accept that this may be a bias due to the type of code I'm writing (complex scientific code) where breaking out a single step of a long list of equations wouldn't mean much.

    Anyway, I guess following your principle you would be happy to put the declarations at the top of the switch, before any of the labels, as in my last example 😛



  • @Zecc Oh that's a nice one, I would never have thought about it!



  • @remi You don't have to port your existing stuff. You can write some glue code and start writing new stuff in a different language.



  • @anonymous234 That's definitely a suggestion better suited to one of the :wtf: threads...

    We actually kind of tried that, and the problem is that most of our code isn't structured in small independent services with clear APIs (or other I/Os). It's not that it's not modular (well in part it is...), but the modules are all built around each other and pass a lot of data in a lot of formats between them. So writing some glue code is not a simple thing as it needs to cover a lot of things about all the various data that the current modules are using (tons of different types of data with tons of subtleties that we can't really hide away as they are what makes the data valuable).

    So when we tried that, building the glue code was a lot of work, and maintaining that glue code was even worse, to the point that after a few years we abandoned it. And of course the performance of all that was dismal (because simply getting it to work was already hard, we never got to worry about trying to make it work fast!).

    Also, your suggestion means we're going to mix even more languages in the codebase. It's already hard enough to get people able to work on more than just their own module when the language is the same, so if some bits are in a different language, this would be even harder. We already have that with some code in Fortran (yeah, I know) and basically we have two groups of developers, one working in C++ and the other in Fortran and the two never look at code from the other. Even though C# is closer to C++ than Fortran, I know that this is just how it would end up.

    Plus, overall, I'm not convinced that even if all our codebase was magically converted to another language and all developers trained in that language, we would develop much more efficiently. I don't get the feeling that we spend a lot time on stuff due to specificities of the language we're using (as compared to e.g. development methodology, company strategy, or domain-specific issues).


  • Java Dev

    @Zecc said in TIL (about the Dark Arts of HTML):

    @remi said in TIL (about the Dark Arts of HTML):

    you can even go one step further (this was also mentioned in one of the SO answer) and put the declaration outside of any of the case

    0_1542273324641_545a4989-7857-4142-a181-178ebbc1cb19-image.png

    😵

    So I guess it does the ""right thing"" and consider the outer switch as having no branches.

    I've encountered nested switches in the wild (and even written one or two) in hand-written state machines where the state code switched on the value of input bytes.


  • Java Dev

    @remi said in TIL (about the Dark Arts of HTML):

    Anyway, I guess following your principle you would be happy to put the declarations at the top of the switch, before any of the labels, as in my last example 😛

    I keep them all the way at the start of the function, because otherwise you can forget about inspecting them in gdb completely.



  • @PleegWat Are you saying that if a variable isn't defined at start of function, then gdb can't display them properly?

    'cause that doesn't match at all my own experience, but 1) I'm mostly doing C++ (not C) so if you're in C I have no experience and 2) I almost never use gdb directly, I usually use some GUI on top of that (usually QtCreator) so there might be something there as well.

    Still, that sounds very strange to me.


  • Discourse touched me in a no-no place

    @remi said in TIL (about the Dark Arts of HTML):

    Are you saying that if a variable isn't defined at start of function, then gdb can't display them properly?

    If the binary's debugging metadata includes information about the scope of variables (which it should) then gdb can display it. C has similar scoping rules to C++, but without constructors or destructors it doesn't really matter as much so people don't pay attention.


  • Banned

    @dkf said in TIL (about the Dark Arts of HTML):

    Except on my machine, where gdb can't display jack shit for reasons I don't understand.

    That sums up GDB experience of everyone I know who has ever used GDB. Including myself.


  • ♿ (Parody)

    @Gąska said in TIL (about the Dark Arts of HTML):

    @dkf said in TIL (about the Dark Arts of HTML):

    Except on my machine, where gdb can't display jack shit for reasons I don't understand.

    That sums up GDB experience of everyone I know who has ever used GDB. Including myself.

    I've never had an issue with that sort of thing. My problem is that I always forget how to list / switch to different threads.



  • @boomzilla Stop using a stupid text interface like you're stuck in the 80's!!!11!! </blakeyrant>

    (info threads and thread <nb>, AFAIR, which really isn't that hard to remember compared to other stuff... like, which is which between next and step...)


  • ♿ (Parody)

    @remi said in TIL (about the Dark Arts of HTML):

    Stop using a stupid text interface like you're stuck in the 80's!!!11!! </blakeyrant>

    Already done. I use an awesome text interface! 🏆

    (info threads and thread <nb>, AFAIR, which really isn't that hard to remember compared to other stuff... like, which is which between next and step...)

    Yeah, except I don't do it that often really so when I actually need to I've forgotten it.



  • @boomzilla said in TIL (about the Dark Arts of HTML):

    @remi said in TIL (about the Dark Arts of HTML):

    Stop using a stupid text interface like you're stuck in the 80's!!!11!! </blakeyrant>

    Already done. I use an awesome text interface! 🏆

    Oh, so you've found a way to use vim in gdb? Nice! 🍹

    Yeah, except I don't do it that often really so when I actually need to I've forgotten it.

    I know, it's always like this with stuff you don't use often. "Duh, it's easy, next time I'll remember... <next time> nope, I dont!"


  • Java Dev

    @remi said in TIL (about the Dark Arts of HTML):

    Oh, so you've found a way to use vim in gdb? Nice! 🍹

    The other way around (gdb in a vim buffer) might be useful, but AFAIK vim doesn't support that kind of thing.



  • @remi said in TIL (about the Dark Arts of HTML):

    breaking out a single step of a long list of equations wouldn't mean much.

    At minimum, that block can have a name, though. It's all about making the code more readable. Reuse is one thing methods help with, but I'd say improving readability is equally important.



  • @Magus said in TIL (about the Dark Arts of HTML):

    @remi said in TIL (about the Dark Arts of HTML):

    breaking out a single step of a long list of equations wouldn't mean much.

    At minimum, that block can have a name, though. It's all about making the code more readable. Reuse is one thing methods help with, but I'd say improving readability is equally important.

    Yeah, but that's what comments are for, no need to make a new function. What I dislike about using functions in that case is that it breaks the flow of reading. It's no longer up-to-down, line after line, but suddenly it's jumping to here and there, and when you keep doing that, at one point you get lost in your browsing history, so to speak. A linear single function makes it easier to back-track.

    But I agree, readability is the key thing here. I probably have more difficulty understanding an easy code that is poorly written (inconsistent coding convention, no or bad comments etc.) than a hard one properly written (coherent, good comments...). Length of functions is kind of orthogonal to all that.



  • @remi said in TIL (about the Dark Arts of HTML):

    Yeah, but that's what comments are for, no need to make a new function.

    On the other hand, comments tend to get out-of-sync with the code they're describing over time. Not to say that function names don't, but it's easier to overlook comments being wrong than code.



  • @remi said in TIL (about the Dark Arts of HTML):

    Yeah, but that's what comments are for, no need to make a new function. What I dislike about using functions in that case is that it breaks the flow of reading. It's no longer up-to-down, line after line, but suddenly it's jumping to here and there

    No. The whole point is that you read the name, and you don't go jumping in there unless it's relevant to what you're looking for. You see the name of the step, which makes sense, and you keep going.

    @remi said in TIL (about the Dark Arts of HTML):

    but suddenly it's jumping to here and there, and when you keep doing that, at one point you get lost in your browsing history, so to speak. A linear single function makes it easier to back-track.

    I don't want to have to understand every little conditional in a thousand-line method. I, in fact, cannot do so. I want irrelevant things to be clear based on a name so they do not get in my way.



  • @hungrier Nothing is perfect. I'm just saying that, from my personal experience, I prefer not to go through the "short functions everywhere" route as I've seen too many uses of it that reduce readability. But to each his own, and as long as your code is readable, I don't really care which coding principles you use.


  • ♿ (Parody)

    @remi said in TIL (about the Dark Arts of HTML):

    @hungrier Nothing is perfect. I'm just saying that, from my personal experience, I prefer not to go through the "short functions everywhere" route as I've seen too many uses of it that reduce readability. But to each his own, and as long as your code is readable, I don't really care which coding principles you use.

    Yeah, it really depends on what you're doing. One of my favorite ways to refactor into tiny methods are long / complicated if conditions. Those can get tedious but there's often a clear name you can give to the condition. If I really want to check what's going on I can go look at the details, but the name makes it obvious what I'm trying to accomplish.



  • @Magus said in TIL (about the Dark Arts of HTML):

    No. The whole point is that you read the name, and you don't go jumping in there unless it's relevant to what you're looking for. You see the name of the step, which makes sense, and you keep going.

    Yeah, that's a nice ideal world you live in. When you look at existing code, it's not just because you suddenly decided you'd like to read that code. It's because you're tracking a bug (or want to modify some behaviour), and when that happens, suddenly you're going to find out that actually your function name isn't telling you what happens if there is a null pointer in there, or a list with a single element, or whatever other edge case you're in, and whether the bug comes from that function or another one (and don't tell me "tests should cover that", we all know that tests, if they even exist, are not going to cover an edge-case before someone found the bug, because there is no way you can think of all possible edge-cases in advance -- tests are great to cover your bases and to avoid regressions, but not for this specific goal). So now you have to go to the function, because you can guess as much as you want from the name what it's supposed to do, but there is no way you can know what it actually does.

    But again, to each his own, I'm not saying using functions is a bad thing. I'm just pushing against the school of "no function must be more than [some ridiculously small number] lines".

    I don't want to have to understand every little conditional in a thousand-line method. I, in fact, cannot do so. I want irrelevant things to be clear based on a name so they do not get in my way.

    And again, if the code is properly made readable, be it through comments or functions (and everything else that makes code readable or not), you don't have to understand everything in a large function.

    You're displaying the mentality that I dislike, equating "readability" with "short functions" (or rather, "long functions" with "un-readability"). I'm saying there is little to no correlation between the two.



  • @remi said in TIL (about the Dark Arts of HTML):

    You're displaying the mentality that I dislike, equating "readability" with "short functions" (or rather, "long functions" with "un-readability"). I'm saying there is little to no correlation between the two.

    Yes, but all of that is because you're wrong.

    If a function is short, it has less possible points of failure, which means that whichever way it IS wrong is easy to understand and fix. This is not an opinion.

    I'm not on the bandwagon of 'methods should do as little as possible' but it is absolutely true that less code has less bugs. And if those smaller components have names, they are inherently trustworthy. If those names are good, then when looking back for a bug, it is easy to find which step the bug is in, without having to understand the whole context.

    This is basic, logical stuff.


  • Banned

    @remi when I'm tracking down a bug, I consider small functions that build up bigger functions a better thing than a single huge monolith of code. I can, for example, step over each of the function call, and see if the variable I'm interested in has the value it should have at this point - and when it's not, I know in which sub-function the bug is in, even if I haven't read the sub-function's code yet.

    But yes, a strict rule of "no more than 4 lines" is dumb. Especially when you write in languages that naturally tend to have lots of boilerplate, like C++.



  • @Magus said in TIL (about the Dark Arts of HTML):

    less code has less bugs

    Software engineering rules:

    No code runs faster than no code
    No code has fewer bugs than no code
    No code uses less memory than no code
    No code is easier to understand than no code


  • ♿ (Parody)

    @Magus said in TIL (about the Dark Arts of HTML):

    I'm not on the bandwagon of 'methods should do as little as possible' but it is absolutely true that less code has less bugs.

    But...you don't have less code. You actually have more (because you have the code, plus you have to call all the bits of code that you've moved out of the single function).

    @Magus said in TIL (about the Dark Arts of HTML):

    And if those smaller components have names, they are inherently trustworthy.

    What?

    @Magus said in TIL (about the Dark Arts of HTML):

    If those names are good, then when looking back for a bug, it is easy to find which step the bug is in, without having to understand the whole context.

    This is basic, logical stuff.

    Except that often you still have to trace it back to the stuff that called the function. So it might be less clear, plus you need to check to make sure no other place calls it, etc, so it's often more complicated to track stuff down across functions.



  • @Magus said in TIL (about the Dark Arts of HTML):

    @remi said in TIL (about the Dark Arts of HTML):

    You're displaying the mentality that I dislike, equating "readability" with "short functions" (or rather, "long functions" with "un-readability"). I'm saying there is little to no correlation between the two.

    Yes, but all of that is because you're wrong.

    If a function is short, it has less possible points of failure, which means that whichever way it IS wrong is easy to understand and fix.

    I'd like you to show me how 1000 lines of code, broken into 100 methods of 10 lines each, have less possible points of failure than the exact same 1000 lines of code in a single method.

    (hint: you can't)

    This is not an opinion.

    It most definitely is, and the only reason I'm still discussing this is that you're not even aware of it.

    Again, you're conflating (at least) two different things. Shorter code that does the same thing than longer code is (generally and within reason) better. Code that clearly explains what it does is better than code that doesn't. Shorter functions don't really help the first point (ignoring code reuse, which is an obvious case where functions are better), they don't reduce the overall amount of code (if anything, they increase it by adding declarations etc.). The second point can be achieved in many different ways, short functions being just one possible way (and short functions can also be abused in such a way that goes against that point).


  • Banned

    @remi said in TIL (about the Dark Arts of HTML):

    @Magus said in TIL (about the Dark Arts of HTML):

    @remi said in TIL (about the Dark Arts of HTML):

    You're displaying the mentality that I dislike, equating "readability" with "short functions" (or rather, "long functions" with "un-readability"). I'm saying there is little to no correlation between the two.

    Yes, but all of that is because you're wrong.

    If a function is short, it has less possible points of failure, which means that whichever way it IS wrong is easy to understand and fix.

    I'd like you to show me how 1000 lines of code, broken into 100 methods of 10 lines each, have less possible points of failure than the exact same 1000 lines of code in a single method.

    No, you don't understand. Each of those 100 10-line methods, when considered in isolation from the rest of code and from the outside world, has less points of failure than the entire 1000 lines of the original method. It doesn't mean jack shit for anything practical, but it makes for a nice rallying cry.



  • @remi said in TIL (about the Dark Arts of HTML):

    I'd like you to show me how 1000 lines of code, broken into 100 methods of 10 lines each, have less possible points of failure than the exact same 1000 lines of code in a single method.
    (hint: you can't)

    Each of those methods has a much smaller set of points of failure than the large method, which you cannot disagree with. If you can't look at them in isolation, congratulations, you wrote some horrible code. At least you now have a smaller context to fix it within.

    @remi said in TIL (about the Dark Arts of HTML):

    It most definitely is, and the only reason I'm still discussing this is that you're not even aware of it.

    No, here's what you don't get: If I have a method, and there is a block within it that is completely self-contained, I don't want to see it. I don't want, every time i have to look back at that code a year later, to have to re-read that entire block to understand that it does its thing correctly before I move on.

    Drilling down to what's failing isn't an issue. It's all the time wasted looking through things that actually do work correctly that's worthless. I don't care how geniusly well-written your thousand lines of gook are, I need to find the part that's wrong, and being able to limit my context is the absolute most valuable way to save my time.



  • @Gąska said in TIL (about the Dark Arts of HTML):

    No, you don't understand. Each of those 100 10-line methods, when considered in isolation from the rest of code and from the outside world, has less points of failure than the entire 1000 lines of the original method. It doesn't mean jack shit for anything practical, but it makes for a nice rallying cry.

    I think you've nicely summed up the problem.

    I remember a presentation from someone arguing for the "small functions" school, and they wrote some kind of toy program (Eratosthenes' sieve or something like that) where they started from the original "ugly" code made of a single function of 20 lines or so, and broke it down into 10 1-line functions where the function name itself was longer than the content of the function, and then argued that the later was better than the former. :rolleyes:

    At the time I thought they were the only person stupid enough to actually believe that, but every time this kind of discussion pops up, I find out they're not.



  • @Magus said in TIL (about the Dark Arts of HTML):

    No, here's what you don't get: If I have a method, and there is a block within it that is completely self-contained, I don't want to see it. I don't want, every time i have to look back at that code a year later, to have to re-read that entire block to understand that it does its thing correctly before I move on.

    Oh, I see, so your problem is that you are unable to skip forward when reading code. You have to read all lines one by one, regardless of whatever clues there might be that it's not the part you're looking for.

    I really feel for you, reading a dictionary must be very slow.

    (less snarky: you're still mixing function length and readability. A longer function is not necessarily a less readable one.)


  • Banned

    @remi said in TIL (about the Dark Arts of HTML):

    @Magus said in TIL (about the Dark Arts of HTML):

    No, here's what you don't get: If I have a method, and there is a block within it that is completely self-contained, I don't want to see it. I don't want, every time i have to look back at that code a year later, to have to re-read that entire block to understand that it does its thing correctly before I move on.

    Oh, I see, so your problem is that you are unable to skip forward when reading code. You have to read all lines one by one, regardless of whatever clues there might be that it's not the part you're looking for.

    To be fair, considering the style in which extremely long functions are usually written in, reading carefully from beginning to end is the only way to be sure what value any given variable holds (or should hold). Local variables in an extremely long function have many of the same properties as global variables, except there's no alternative.



  • @remi No. Again, you don't get it. If I'm reading a 1000 line method, I have no way of knowing what kind of spaghetti mess you've made. If you're using these 8 variables across 300 lines, I have to read all of it. I have no choice. Presumably you have multiple files and methods, so structured programming is at least something you understand on some level, but generally speaking structure is good, because it limits what you have to think about.



  • @Gąska said in TIL (about the Dark Arts of HTML):

    @remi said in TIL (about the Dark Arts of HTML):

    @Magus said in TIL (about the Dark Arts of HTML):

    No, here's what you don't get: If I have a method, and there is a block within it that is completely self-contained, I don't want to see it. I don't want, every time i have to look back at that code a year later, to have to re-read that entire block to understand that it does its thing correctly before I move on.

    Oh, I see, so your problem is that you are unable to skip forward when reading code. You have to read all lines one by one, regardless of whatever clues there might be that it's not the part you're looking for.

    To be fair, considering the style in which extremely long functions are usually written in

    Long functions are usually used in bad code, that's true. But that's because most people are bad developers and don't even think of doing it otherwise.

    reading carefully from beginning to end is the only way to be sure what value any given variable holds (or should hold).

    Meh. With a proper IDE, highlighting all uses of the variable takes one click. So yeah, if it's defined at the very start, then reused for many different things during the life of the function, you're going to have trouble following it. But again that's a readability issue (and horrible code in the first place), not a length issue (if the variable really needs to be used in all those places, then having small function would have the same issue since the variable would be passed to all of those).



  • @Magus said in TIL (about the Dark Arts of HTML):

    @remi No. Again, you don't get it. If I'm reading a 1000 line method, I have no way of knowing what kind of spaghetti mess you've made.

    Right, 'cause splitting those 1000 lines into 100 functions will guarantee me this is no longer a spaghetti mess. Have you ever looked at real code?

    If you're using these 8 variables across 300 lines, I have to read all of it. I have no choice.

    And if you've broken this into methods and each of those methods takes the 8 variables as arguments (because if I'm using those 8 variables across 300 lines, that's because I need them), you have the exact same problem. Shorter functions won't help you.



  • @remi said in TIL (about the Dark Arts of HTML):

    each of those methods takes the 8 variables as arguments (because if I'm using those 8 variables across 300 lines, that's because I need them), you have the exact same problem.

    Just make those 8 variables global 🐠


Log in to reply