Visual Studio WTF


  • Winner of the 2016 Presidential Election

    Today, I got a strange linker error in Visual Studio: It complained that it could neither find the public constructor nor the public destructor of one of the classes. So I opened the header file:

    bar/foo.h

    #pragma once
    
    namespace bar
    {
        class foo
        {
        public:
            enum class tdwtf {
                _true, _false, FILE_NOT_FOUND
            };
            foo();
            ~foo();
        }
    }
    

    Hm, looks good. Clean, rebuild, same error. That's strange, so I try a few things and end up typing…

    #pragma once
    
    namespace bar
    {
        class foo
        {
        public:
            enum class tdwtf {
                _true, _false, FILE_NOT_FOUND
            };
        public:
            foo();
            ~foo();
        }
    }
    

    …and for reasons that works (compiles)! Since I don't believe the compiler could possibly be that stupid, I spend the next 30 minutes trying to figure out WTF is happening. Of course, the problem is something completely different:

    baz/foo.h

    #pragma once
    
    namespace baz
    {
        class foo
        {
        public:
            foo();
            ~foo();
        }
    }
    

    As it turns out, Visual Studio throws all .obj files in the same directory by default and therefore cannot handle two .cpp files with the same name in its default configuration.

    WTFs:

    • That default configuration is completely insane. Who thought there'd never be two files with the same name in different folders?
    • Why on earth did my "fix" work? (It wasn't the simple fact that I edited the file. I tried a few times, and every time I removed the second "public:" it'd stop working.)


  • Is it just setting the visibility back to private when it sees class, not caring about nested classes?

    It seems like that if it was just looking at the wrong object file, adding a public shouldn't change a thing. I'm not all that well versed in either Windows or C++, though.


  • Winner of the 2016 Presidential Election

    @marinus said:

    Is it just setting the visibility back to private when it sees class, not caring about nested classes?

    Nope. After I renamed the second file, everything worked fine. Also, after changing VS's stupid default configuration to something sensible (making it re-create the original directory structure where it stores the .obj files), everything works fine if you keep the original file names.

    @marinus said:

    It seems like that if it was just looking at the wrong object file, adding a public shouldn't change a thing.

    Emphasis on should, because it definitely did. I still haven't managed to reproduce that behavior in another project, though, I'm not even getting the same linker warning. I'd love to find out why this is/was happening.

    @marinus said:

    I'm not all that well versed in either Windows or C++, though.

    Fun fact: Me neither.



  • Did it actually work when you added the extra public, or did it just compile and then crash or call the wrong function?

    If you really want to know what's behind it, you should compile it both ways and then compare the object files, but that's work.


  • Winner of the 2016 Presidential Election

    @marinus said:

    Did it actually work when you added the extra public, or did it just compile and then crash or call the wrong function?

    I don't know, because there were still other bugs in the code that caused an exception to be thrown before any foo could be constructed.

    @marinus said:

    If you really want to know what's behind it, you should compile it both ways and then compare the object files, but that's work.

    If tomorrow proves to be a slow day, I might do that. But I've had enough "fun" for today already, thanks to Visual Studio.



  • @asdf said:

    That default configuration is completely insane. Who thought there'd never be two files with the same name in different folders?

    TRWTF is having different source files with same name. The only time I've seen it is in my current work, where core of our product is autogenerated hierarchy of hundreds of classes that work as DB-like thingy and interface for cooperation with other products. This system is big pile of various WTFs, and not-really-separation of logic and data (ie. class methods and class fields) is done by having two classes, db::X and db::data::X, whose headers are located in db/X.h and db/data/X.h respectively.

    @asdf said:

    Why on earth did my "fix" work? (It wasn't the simple fact that I edited the file. I tried a few times, and every time I removed the second "public:" it'd stop working.)

    I'd say race conditions.



  • So much for namespaces.


  • Winner of the 2016 Presidential Election

    @Gaska said:

    I'd say race conditions.

    For the sake of my sanity, I'm going to accept that explanation.

    @Gaska said:

    TRWTF is having different source files with same name.

    @CodingHorrorBot?


  • 🔀

    @asdf Is Doing It Wrong™

    <!-- Posted by SockBot 0.13.0 "Devious Daine" on Thu Nov 27 2014 21:33:41 GMT+0000 (UTC)-->

  • Discourse touched me in a no-no place

    @Gaska said:

    I'd say race conditions.

    I'd say practice conditions. We're not up to qualifying, let alone race conditions here…



  • @delfinom said:

    So much for namespaces

    Namespaces and filenames are orthogonal concepts.


  • Discourse touched me in a no-no place

    @Gaska said:

    Namespaces and filenames are orthogonal concepts.

    Indeed they are, but having problems because two source files in different directories have the same local name? That's “special”.



  • Depends on what you mean by special. Because when working with C or C++, it's actually standard practice (ie. not VS-specific) to dump all object files into one directory. Usually it's not a problem, because usually you don't have multiple files named the same. If you do, it might indicate design flaws. Kinda like tall and narrow class hierarchies - they're not bad per se, but if such things happen, someone probably fucked up the design.


  • Discourse touched me in a no-no place

    It's more common than you might think. That said, you normally don't notice it because disparate parts tend to be packaged into separate libraries, where they don't conflict.

    Filenames aren't class names or namespace names.



  • @dkf said:

    It's more common than you might think. That said, you normally don't notice it because disparate parts tend to be packaged into separate libraries, where they don't conflict.

    That's whole different story. I can have my own implementation of vec2f, my physics library can have its own, my graphics library can have its own etc. But having multiple vec2f implementations within same project is just asking for trouble. Same with any other class, even much bigger ones than my example (especially the bigger ones).

    @dkf said:

    Filenames aren't class names or namespace names.

    Yes.


  • Discourse touched me in a no-no place

    @Gaska said:

    But having multiple vec2f implementations within same project is just asking for trouble.

    Feel for me, please. We've got 8 versions of the same library in one of our products, all in simultaneous use in the same process. It's one of the most WTFy parts, and we know it. (We're doing this in Java so we can apply stronger separation between things than is the norm in C or C++, but even so…)



  • @dkf said:

    Feel for me, please. We've got 8 versions of the same library in one of our products, all in simultaneous use in the same process. It's one of the most WTFy parts, and we know it.

    You see, TRWTF is your project. Simple projects suffice with simple configurations. Overly complex projects need overly complex configuration. Pile-o'-WTFs projects exhibit the most WTF bugs of the build systems - because no one has prepared for that.

    @dkf said:

    We're doing this in Java so we can apply stronger separation between things than is the norm in C or C++

    The norm in C and C++ is little separation because they're about performance, and each layer of indirection is performance penalty, and they use only one version of given library so there's no problem at all with cooperation. But I think you're implying that strong separation is not only not normal, but also impossible in those languages. That's very asterisked statement - care to elaborate on how Java is better at abstracting away differences between libraries than C++?


  • Discourse touched me in a no-no place

    @Gaska said:

    But I think you're implying that strong separation is not only not normal, but also impossible in those languages. That's very asterisked statement - care to elaborate on how Java is better at abstracting away differences between libraries than C++?

    I never said that it abstracts away the differences. I said that it enforces stronger separation. Basically, classes in Java have a coordinate system that consists of two things: the full class name (namespace + local name) and the class loader which provided it. Most programmers ignore the second part, but it can be used to do some very clever stuff. Or to make sane programmers nauseous. ;)

    This is an area where Java is very different from normal practice in C and C++, where you'd have to do evil tricks with the dynamic library loader to achieve something similar.

    The other part of Java's stronger separation is the fact that code is verified before you can execute it; you can't execute random crap in a file, it has to not break the low-level rules (and the standard classes can enforce the high-level rules on that basis if they wish) and the check of that is on the only path from “bytes I've read into memory” to “class containing executable code”. That's something that's just not there at all in C or C++ (which rely on compilers to enforce sanity) and is critical to many line-of-business applications, but it's nothing to do with the point I was making.



  • I still don't know what exactly it helps with. Locating the appropriate file to load classes from? Sounds like typical use case for DLLs. Loading (or not) libraries on demand, and in specific version? Doable with DLLs too. It's much harder to load-or-not DLLs containing C++ class methods than Java class, but it's doable, and isn't any more "evil" than, say, dynamically-sized structures in C.


  • Discourse touched me in a no-no place

    @Gaska said:

    Doable with DLLs too.

    I did say that it was doable with C++. Do try to keep up<!-- even though you're a C++ programmer-->.


  • Winner of the 2016 Presidential Election

    @dkf said:

    That said, you normally don't notice it because disparate parts tend to be packaged into separate libraries, where they don't conflict.

    That's what's going to happen to those two classes as well, in the future.

    @Gaska said:

    Because when working with C or C++, it's actually standard practice (ie. not VS-specific) to dump all object files into one directory.

    As someone who doesn't write much C/C++, that still strikes me as stupid, even if it's the usual behavior.


  • Discourse touched me in a no-no place

    @asdf said:

    As someone who doesn't write much C/C++, that still strikes me as stupid, even if it's the usual behavior.

    The bigger the project, the more likely this is to be troublesome. Why? Because the bigger the project, the more likely it is that there'll be a file called eval in it (with some extension, so eval.c or eval.cpp or …) and subprojects evolve to be their own project-within-a-project. Why? “Because.”


  • Winner of the 2016 Presidential Election

    Fortunately, my project doesn't contain any file called eval.cpp.



  • @dkf said:

    I did say that it was doable with C++. Do try to keep up.

    You said it requires evil tricks with DLL loader - which in C/C++ usually means "abusing implementation-not-really-defined behavior". int/float union is evil trick. Loading DLLs on demand don't need such trickery - only well-formed code using well-documented API. Ugly as hell API with signal-to-noise-ratio approaching 0, but still well-documented.

    You still haven't said why Java way is better.

    @dkf said:

    The bigger the project, the more likely this is to be troublesome. Why? Because the bigger the project, the more likely it is that there'll be a file called eval in it (with some extension, so eval.c or eval.cpp or …) and subprojects evolve to be their own project-within-a-project. Why? “Because.”

    That's two WTFs right here (multiple files with same name in the project and subprojects not having separate build process). If you don't have such WTFery in your codebase, VS doesn't behave WTFy either. I'm not saying it's better to dump all files into a single folder than to reproduce hierarchy (because it isn't) - I'm saying it's not a bad way to do things, and it works fine if you don't do WTFy things.



  • @Gaska said:

    That's whole different story. I can have my own implementation of vec2f, my physics library can have its own, my graphics library can have its own etc.

    I find this to be quite amusing when it comes to String classes. In my project, I have to deal with:

    • std::string
    • Ogre::String
    • CEGUI::String
    • RakNet::RakString
    • ...and of course, const char *

    Thankfully, they all convert to/from std::string or const char *.


  • Discourse touched me in a no-no place

    @dkf said:

    Indeed they are, but having problems because two source files in different directories have the same local name? That's “special”.

    True, although you could make an argument that the files should have been in separate projects. (I don't know if it makes sense in the context of this solution, admittedly.)


  • Winner of the 2016 Presidential Election

    @FrostCat said:

    I don't know if it makes sense in the context of this solution, admittedly.

    Not at the moment. As soon as the basic functionality is complete, I'll probably turn a part of the project into a library, though, and the two files will end up in separate projects.



  • @asdf said:

    That default configuration is completely insane. Who thought there'd never be two files with the same name in different folders?

    Been there. The problem cured itself when we switched to generating the project with CMake as it automatically reconfigures the conflicting files to make things work.

    To be honest, the sources are by default in one directory as well. Or rather were before VS2010 (I still use VS2008, because the newer ones don't have WinCE/WEC target).

    The “folders” (actually called “filters”) in the project did always match file patterns. So there was a “headers” “folder” and “sources” “folder” and “resources” “folder” and something else “folder”. I always considered that totally idiotic and always pushed laying out the files by namespaces both in the project and in the filesystem. But it is not how you are supposed to do it, or is it @CodingHorrorBot?

    Now in C# and VB.NET projects there is normally only one type of files, so they didn't put in the “filters” thing and instead made the project layout correspond to the filesystem layout.

    Finally in VS2010 (we actually use VS2012 too, but only the build server and one developer responsible for the port have it) they converted C++ projects to the build system they developed for .Нет, so the layout started to match the filesystem there too. But much structure in one project is still not really supported.

    @asdf said:

    Why on earth did my "fix" work? (It wasn't the simple fact that I edited the file. I tried a few times, and every time I removed the second "public:" it'd stop working.)

    IIRC while you are in the GUI the thing tries to ignore edits that don't change meaning of the file. So if you just press "Save", no cookie for you, it won't rebuild. If you chang some whitespace or added a comment // huh, this is weird, no cookie for you, it won't rebuild. Pretty silly. Pretty fragile, too.


  • 🔀

    @Bulb Is Doing It Wrong™

    <!-- Posted by SockBot 0.13.0 "Devious Daine" on Fri Nov 28 2014 23:22:37 GMT+0000 (UTC)-->

  • Winner of the 2016 Presidential Election

    VS2013 is the first version I've ever used, but it still distinguishes folders from filters and if I right-click on a FolderFilter™ to add a new file, it will create that file in the root folder anyway.


  • Discourse touched me in a no-no place

    @Bulb said:

    I always considered that totally idiotic and always pushed laying out the files by namespaces both in the project and in the filesystem.

    It generally works up to a point, and it's simple, and everyone can understand it, so it's not really idiotic.

    If your project is complicated enough that it doesn't work, then yeah, it's time to break it up a different way. Frequently you'll create a bunch of sub-projects that are referenced by the main one. If you do it that way I think each sub-project, even under the default system, gets its own directories, but it's been a long time since I looked at a project like that.


  • Discourse touched me in a no-no place

    @Gaska said:

    You said it requires evil tricks with DLL loader - which in C/C++ usually means "abusing implementation-not-really-defined behavior".

    TIL that RTLD_LOCAL is “implementation-not-really-defined”. (It's not evil when you're doing it a little bit BTW, but extend it out to the entire application and use it to power a plugin system to allow hot-replacement of virtually all code and it's very evil indeed. And uses documented APIs throughout without nasty type puns.)

    @Gaska said:

    You still haven't said why Java way is better.

    For some application areas, it is better. YMMV.

    Specifically, the isolation makes it easier to trust that the impact of failures will be limited and recoverable. You don't get 100% of the way there, but it's a heck of a lot closer than you can usually attain in C++. The more complex the application, the more this becomes important.

    The loader stuff is part of that. You can't access outside contexts that aren't yours because you can't construct the full name of the code in question. (Class loaders are not easy to look up in general; there's no global registry of them.)



  • @dkf said:

    Specifically, the isolation makes it easier to trust that the impact of failures will be limited and recoverable.

    try {
       callExternalCodeThatMightBeBuggyAsShitButImNotQuiteSure();
    } catch (Throwable t) {
       logShittyExternalCodeException(t);
       // keep on trucking
    }
    
    Logged external exception: java.lang.VerifyError: Method com.company.mycode.Secret#secretStuff(IIIZ) is private and not accessible from me.external.shitty.Code#<clinit>

  • Discourse touched me in a no-no place

    Web application servers do something very much like that, yes.

    What's more fun is when you get a failure to cast a com.example.WeirdAssSubclass to a com.example.WeirdAssSuperclass because they're defined by different classloaders. The first time you see it, you think that you ate something decidedly odd at lunch because it appears that reality has just ceased to make sense. It is sane though; it's just that classloaders aren't normally named in the exception messages (because you virtually never need them and they'd clutter things up a lot).

    Maybe I need a new definition of “fun”. :smile:


Log in to reply
 

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