Undefined OOP Techniques


  • Banned

    At my university, I have to attend a course named "Advanced OOP Techniques". In this course, we learn all about C++: constructors, destructors, order of initialization/destruction, virtual vs. non-virtual methods, manual memory management, pointers, references, operator overloading... In short - literally nothing about things that aren't specific to just C++.

    But that, I can (kinda, sorta, not really) understand - many people, especially in academia, don't know shit what OOP actually is, and it's very common for C++ programmers to develop borderline C++ bias. These aren't nice things, but at least we still learn something that's somewhat useful and technically correct.

    But today, we had a quick test. Three questions. Two of them were basic C++ knowledge (as in, completely unrelated to OOP in general), but the last one... Well...

    Program A:

    int array[3];
    int i = 0;
    array[i++] = i;
    array[i++] = i;
    array[i++] = i;
    

    Program B:

    int array[3];
    int i = 0;
    array[i] = ++i;
    array[i] = ++i;
    array[i] = ++i;
    

    What is the final state of array in each program? Would there be any error? Justify your answer.

    The correct answer? Well, it depends on whether you like GCC[1], [2] or MSVC[1], [2] more, or if you are more of a specification[1], [2] guy. The correct answer according to our lecturer who is going to grade our tests, and will ultimately decide if we are worthy of continuing our education? Well, let's just say he's Microsoft fan.


  • FoxDev

    @Gąska The answer to question three is "What the fuck are you doing you utter moron?"

    Seriously, anyone who writes C++ code like that should have their developer license revoked.


  • I survived the hour long Uno hand

    @Gąska said in Undefined OOP Techniques:

    Would there be any error?

    What are the requirements?


  • Winner of the 2016 Presidential Election

    @Yamikuronue said in Undefined OOP Techniques:

    @Gąska said in Undefined OOP Techniques:

    Would there be any error?

    What are the requirements?

    Are there any possible requirements that can make undefined behavior not an error?


  • I survived the hour long Uno hand

    @Dreikin

    Requirement: All entries must exhibit undefined behavior.



  • @Gąska said in Undefined OOP Techniques:

    there is an explicit ban on using smart pointers, and an implicit ban on STL containers

    I hate this so much. All it does is require unlearning later in life. And so many different colleges do this that it's almost as if they are cooperating in pumping out idiot programmers.


  • Winner of the 2016 Presidential Election

    @Yamikuronue said in Undefined OOP Techniques:

    @Dreikin

    Requirement: All entries must exhibit undefined behavior.

    Yep, shoulda seen that coming...


  • Discourse touched me in a no-no place

    @RaceProUK said in Undefined OOP Techniques:

    should have their developer license revoked.

    Maybe developing without a license is why we have so many open source developers


  • :belt_onion:

    @Gąska said in Undefined OOP Techniques:

    Would there be any error?

    Yes, the programmer is in error.

    Justified with the line from the spec indicating such.

    Yes, I fail questions like that on purpose...



  • @sloosecannon any answer to a question about undefined behavior is true because the person responding to that question could write a compiler with that behavior and still conform to the spec.


  • Discourse touched me in a no-no place

    @Gąska I like how Program B has the option to write off the end of the array (since there's no sequence point between the increment of i and the use of it as an index). That's an opportunity for chaos FUN

    Why can't the C++ committee stop with this pretence and define an evaluation order (and let the compiler handle the non-breaking reorderings)? Lots of other languages do this, and it avoids a whole bunch of stupidity and inconsistency between implementations.



  • @Gąska So did you
    a) point this out to the instructor, maybe by asking a socratic question about the lack of sequence points ...
    b) go and whine about it anonymously on the internet like a spineless millenial



  • @Gąska said in Undefined OOP Techniques:

    Well, it depends on whether you like GCC[1], [2] or MSVC[1], [2] more, or if you are more of a specification[1], [2] guy.

    It's even more interesting than that. The first case produces the same result both optimized and unoptimized, but the second one differs. And clang differs from gcc.

    $ g++ -O0 t1.cpp && ./a.out
    123%
    $ g++ -O3 t1.cpp && ./a.out
    123%
    $ g++ -O0 t2.cpp && ./a.out
    419635212%
    $ g++ -O3 t2.cpp && ./a.out
    012%
    $ clang++ -O0 t1.cpp && ./a.out
    t1.cpp:6:10: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i++] = i;
             ^     ~
    t1.cpp:7:10: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i++] = i;
             ^     ~
    t1.cpp:8:10: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i++] = i;
             ^     ~
    3 warnings generated.
    012%
    $ clang++ -O3 t1.cpp && ./a.out
    t1.cpp:6:10: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i++] = i;
             ^     ~
    t1.cpp:7:10: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i++] = i;
             ^     ~
    t1.cpp:8:10: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i++] = i;
             ^     ~
    3 warnings generated.
    012%
    $ clang++ -O0 t2.cpp && ./a.out
    t2.cpp:6:14: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i] = ++i;
            ~    ^
    t2.cpp:7:14: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i] = ++i;
            ~    ^
    t2.cpp:8:14: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i] = ++i;
            ~    ^
    3 warnings generated.
    3276712%
    $ clang++ -O3 t2.cpp && ./a.out
    t2.cpp:6:14: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i] = ++i;
            ~    ^
    t2.cpp:7:14: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i] = ++i;
            ~    ^
    t2.cpp:8:14: warning: unsequenced modification and access to 'i' [-Wunsequenced]
      array[i] = ++i;
            ~    ^
    3 warnings generated.
    124109480812%
    

    Also clang produces warnings on the code. Well, gcc does too if given you turn them on, they just aren't on by default there:

    $ g++ -O3 -Wall t1.cpp && ./a.out
    t1.cpp: In function ‘int main()’:
    t1.cpp:6:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
       array[i++] = i;
                     ^
    t1.cpp:7:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
       array[i++] = i;
                     ^
    t1.cpp:8:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
       array[i++] = i;
                     ^
    123%
    $ g++ -O3 -Wall t2.cpp && ./a.out
    t2.cpp: In function ‘int main()’:
    t2.cpp:6:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
       array[i] = ++i;
                     ^
    t2.cpp:7:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
       array[i] = ++i;
                     ^
    t2.cpp:8:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
       array[i] = ++i;
                     ^
    t2.cpp:9:23: warning: ‘array[0]’ is used uninitialized in this function [-Wuninitialized]
       std::cout << array[0] << array[1] << array[2];
                           ^
    012%
    

  • Discourse touched me in a no-no place

    @Bulb said in Undefined OOP Techniques:

    124109480812

    Hah! It's written off the end. Thought that was a possible interpretation. Better hope that it didn't smash anything important, as you're directly in nasal-demon land! 😀


  • Java Dev

    @dkf said in Undefined OOP Techniques:

    Thought that was a possible interpretation.

    I think you're not quite aware of the full extend of the meaning of the phrase "nasal demons".


  • Discourse touched me in a no-no place

    @PleegWat Since I include a smash of the function return address in the actions that could be reasonably generated from possible implementations and I know what can happen when that occurs, I'm more aware than you are. (Stack smashing can really stuff things over.) Compilers that detect UB and deliberately inject code to do something malicious are where compiler makers get lynched. They might claim that they're just following the standard, but that won't stop them from being strung up by the neck.

    However, it's also possible that the compiler might see the UB and decide that that means that the code is unreachable. That can have far-reaching consequences.



  • @dkf said in Undefined OOP Techniques:

    Compilers that detect UB and deliberately inject code to do something malicious

    Fortunately I haven't seen that. But the results of UB triggering UB in the optimizer, especially the GCC one, is sometimes not far from that.

    However, it's also possible that the compiler might see the UB and decide that that means that the code is unreachable. That can have far-reaching consequences.

    It can be worse. It can simply come up with inconsistent dependency analysis and then write out the instructions in some strange order (it is not really wrong, because there is no correct order, of course). Gcc often does this and then the bug can have really weird symptoms.


  • Discourse touched me in a no-no place

    @Bulb said in Undefined OOP Techniques:

    Gcc often does this and then the bug can have really weird symptoms.

    Clang's saner; it converts the code to LLVM IR before optimizing and that doesn't have these ambiguities. I've seen UB do fun things like producing core dumps that would make the debugger itself dump core. Debugging that was… interesting…



  • @dkf well, gcc also converts to intermediate representation before optimizing. Every compiler does. The gcc intermediate representation, RTL, is, however, rather flexible. Maybe too much for its own good.



  • @dkf said in Undefined OOP Techniques:

    Thought that was a possible interpretation.

    When you talk UB, all interpretations are possible, and all interpretations are equally correct.

    *bp++ = array[*bp >> 4] | (array[*bp & 0x0F] << 4);

    All compilers except one that the company used produced code that did what was intended, calculate the result, store it, increment the pointer. And of course when I put this code onto our actual embedded platform, I discovered that its compiler was the "except one", and it did it differently: note the destination address, increment the pointer, use the incremented pointer to calculate the result, store it to the noted address.

    But "format the main file system" would be equally correct, as would "retarget the missiles toward Denver, launch them".


  • Discourse touched me in a no-no place

    @Steve_The_Cynic said in Undefined OOP Techniques:

    But "format the main file system" would be equally correct, as would "retarget the missiles toward Denver, launch them".

    I suggest not using compilers that do that sort of thing deliberately as soon as you get some sort of even slightly UB.

    Just sayin' ;)


  • Discourse touched me in a no-no place

    @dkf said in Undefined OOP Techniques:

    However, it's also possible that the compiler might see the UB and decide that that means that the code is unreachable. That can have far-reaching consequences.



  • @dkf said in Undefined OOP Techniques:

    @Steve_The_Cynic said in Undefined OOP Techniques:

    But "format the main file system" would be equally correct, as would "retarget the missiles toward Denver, launch them".

    I suggest not using compilers that do that sort of thing deliberately as soon as you get some sort of even slightly UB.

    Just sayin' ;)

    I agree, but the compiler has the right to do it. Just sayin' ;)


  • Discourse touched me in a no-no place

    @Steve_The_Cynic said in Undefined OOP Techniques:

    the compiler has the right to do it.

    There's rights, and then there's malice. We don't want malice.

    Now, if the compiler just refused to actually compile any code that it didn't think had unambiguous behaviour, that would be OK (provided it also gave a helpful diagnostic message, perhaps including a quick SPANK SPANK COMPLAIN for good measure). It'd be frustrating as heck to a lot of crappy programmers, but they'd be better for it. In the end.


  • Winner of the 2016 Presidential Election

    @dkf said in Undefined OOP Techniques:

    Now, if the compiler just refused to actually compile any code that it didn't think had unambiguous behaviour, that would be OK

    That compiler exists, it's called rustc. ;)


  • FoxDev

    @Gąska said in Undefined OOP Techniques:

    array[i++] = i;

    undefined behavior.

    @Gąska said in Undefined OOP Techniques:

    array[i] = ++i;

    also undefined behavior....

    it doesn't matter if the compiler issues an error or not this code is wrong and in error.


  • Winner of the 2016 Presidential Election

    @Gąska said in Undefined OOP Techniques:

    In short - literally nothing about things that aren't specific to just C++.

    TR:wtf:, they should have called the course "advanced C++" then. Although that would have been wrong as well, since you got taught not to use smart pointers.

    I had a course with the same name, and although C++ was frequently used as an example, we also discussed type theory, using rapid type analysis to eliminate dynamic dispatch and also some concepts (like multimethods and family polymorphism) which C++ doesn't even support.


  • Discourse touched me in a no-no place

    @accalia said in Undefined OOP Techniques:

    this code is wrong

    I don't think anyone's disputing that. But it's fun to play guess-what-happens anyway, at least until something hits the stack in the wrong way and it all ends in tears…


  • Winner of the 2016 Presidential Election

    @asdf said in Undefined OOP Techniques:

    That compiler exists, it's called rustc.

    Also, GNAT. Both can be a pain in the arse, but they have to be to ensure you don't write shitty programs.



  • @asdf said in Undefined OOP Techniques:

    TR:wtf:, they should have called the course "advanced C++" then. Although that would have been wrong as well, since you got taught not to use smart pointers.

    Agreed.

    Especially since C++ is a language in which object-oriented approach is not particularly common.



  • @dkf said in Undefined OOP Techniques:

    Why can't the C++ committee stop with this pretence and define an evaluation order (and let the compiler handle the non-breaking reorderings)?

    Performance in the presence of aliasing.

    auto f(int (&array)[3], int& i, int& j) { array[i++] = j; }
    

    If you define an evaluation order then the compiler has to serialize the reads and writes, which could result in an underfilled pipeline. If it can assume that i and j don't alias each other nor array, it can issue the reads and writes overlapped.


  • Discourse touched me in a no-no place

    @scatters But in that case, you'd want the compiler to inline the function anyway, and that will enable reorderings that don't have a semantically-observable difference…


  • area_pol

    @Gąska Which polish university is that?



  • @dkf said in Undefined OOP Techniques:

    Why can't the C++ committee stop with this pretence and define an evaluation order (and let the compiler handle the non-breaking reorderings)? Lots of other languages do this, and it avoids a whole bunch of stupidity and inconsistency between implementations.

    Not defining operation order is the right decision. If you standardize it, people will rely on it. Then ridiculous code like this would be "correct", which benefits no one. When you call a function, the order of the parameters should not matter. If it did, refactoring would be an even bigger pain as you would also have to preserve the order in which things were called, even if there's no obvious link between them.

    Do you really want to live in a world where:

    auto c = fun(a(), b());
    

    and

    auto b = b();
    auto c = fun(a(), b);
    

    do different things? Standardizing nonsense doesn't make it not be nonsense.



  • @Gąska The whole "we're supposedly teaching OOP but since the class is in C++ we only spend time talking about shit specific to C++" bugged the fuck out of me too, when I was in school.

    The difference was, I was there in 1998 when Java was brand-spanking-new (they actually moved to Java the year after I left), and .net didn't exist yet, and nothing else was cross-platform. (I guess maybe Python would have worked, had anybody heard of it back in 1998. It technically existed then.) There literally were no better choices!

    But in 2016, why the fuck would they use C++ to teach OOP? When they could be using Java, or C#, or VB.Net (yes, seriously), or Python or Ruby or... well I guess JS would be out if you had to teach inheritance. But still. There's a myriad of choices now.

    You should seriously write this school some letters about how they haven't rethought their teaching languages in 20 years. Because that's ridiculous.



  • @LB_ said in Undefined OOP Techniques:

    I hate this so much. All it does is require unlearning later in life. And so many different colleges do this that it's almost as if they are cooperating in pumping out idiot programmers.

    The bigger problem is, why would anybody use C++ to teach OOP in the first place? While it technically has the requirements for the class, I can't imagine a worse language to teach OOP in.



  • @dkf said in Undefined OOP Techniques:

    @scatters But in that case, you'd want the compiler to inline the function anyway, and that will enable reorderings that don't have a semantically-observable difference…

    Especially in C you often don't, e.g. because it is a library function that you actually want to be linked dynamically.

    Also often the inputs come from far enough that inlining is not practical and no static information can be practically propagated. This is especially true of pointer aliasing. Without the aliasing rules, every function that does something with arrays and returns something by pointer would have to assume the output pointer might actually be in the middle of the array, where it never is in practice.


  • I survived the hour long Uno hand

    @blakeyrat said in Undefined OOP Techniques:

    I can't imagine a worse language to teach OOP in.

    Javascript.


  • Winner of the 2016 Presidential Election

    @blakeyrat said in Undefined OOP Techniques:

    But in 2016, why the fuck would they use C++ to teach OOP?

    This is not a beginners class and it's probably supposed to teach advanced topics like multiple inheritance and how the compiler actually implements inheritance. With this in mind, using C++ as the primary example is a defensible choice. Not mentioning Java/.Net and other object-oriented languages at all, however, isn't.


  • Winner of the 2016 Presidential Election

    @blakeyrat said in Undefined OOP Techniques:

    The bigger problem is, why would anybody use C++ to teach OOP in the first place?

    I assume this class is less about introducing people to OOP and more about the nitty-gritty details of how you implement it.



  • @asdf No class using C++ as the instructional language is going to end up teaching anything other than C++. Which is fine, if the name of the class were "OOP In C++" or "Advanced C++ Inheritance" or something like that.

    Either the name of the class is wrong, or the language is wrong.

    EDIT: right now it's like, say the class is called "Foundation Design for Mid-Sized Towers", but you spend the whole class sitting in a Caterpillar bulldozer and for every 10 seconds you spend talking about where to put your drainage lines, you spend 50 seconds talking about how to check the hydraulic pressure in the Cat. Sure you might learn a tiny bit about designing a foundation, but probably what you'll mostly learn is how to operate a Caterpillar bulldozer. And, again, that would be perfectly fine if the name of the class were, "The Caterpillar Bulldozer, your construction friend" and not "Foundation Design for Mid-Sized Towers".



  • Does your University have any process for removing incompetent professors from teaching duties? I assume that this bozo is tenured, which probably means there's nothing to be done, and even if that isn't the case you'd have to explain the problem to faculty who are unlikely to know how to turn a computer on (aren't they always on? I mean, my phone is on even when I am charging it, right?) never mind program one, but still, this is just insulting.

    Could be worse, though. Who here has encountered flowcharts in modern programming? How about fill-in-the-blanks coding sheets? Well, in 2007 I had a professor who gave us fill-in-the-blank flowcharts. The class was a data structures course using... well, nominally it was C++, but he required us to use VC++ 6 (which IMAO was by then just one step above all the universities that still use Turbo C++ 1.0 in 2016), and would fail a program if it used anything not found in C, so yeah, it was really all in C.

    That was the same year that, when I asked the SE professor why he was teaching Waterfall, he replied, "All software engineering is based on Waterfall, no other approach exists and Agile is just another name for the same thing." Imbecile...



  • @Yamikuronue said in Undefined OOP Techniques:

    Javascript.

    I'm imagining an entire semester of "Here's the right way to do this, but it's only supported in one major browser, so you can't do this client-side. Here's the work-around.".


  • Winner of the 2016 Presidential Election

    @blakeyrat said in Undefined OOP Techniques:

    No class using C++ as the instructional language is going to end up teaching anything other than C++.

    I said "primary example", since it supports multiple inheritance and both dynamic and static dispatch, which makes it interesting from an academic POV. Of course, you should show examples in other languages as well and point out the subtle differences (for example, how interfaces work in Java/C#). You might also want to mention techniques which most mainstream languages do not support to widen people's horizons. This is an advanced class, after all.

    What Gaska's university does is definitely stupid, I'm not arguing against that.


  • Discourse touched me in a no-no place

    @ScholRLEA said in Undefined OOP Techniques:

    I assume that this bozo is tenured, which probably means there's nothing to be done

    Having tenure doesn't guarantee that they teach. In fact, those who have tenure mostly prefer to not teach, or at least to not teach undergraduates.


  • Winner of the 2016 Presidential Election

    @ScholRLEA

    Ouch, that sounds awful. Fortunately, I only ever encountered one extremely incompetent professor at my former uni. I wrote about him elsewhere, CBA to search for the post on mobile.

    Long story short: He couldn't even answer simple questions about his own slides.


  • Discourse touched me in a no-no place

    @asdf said in Undefined OOP Techniques:

    search for the post

    :aintnobodygottimeforthat:


  • Winner of the 2016 Presidential Election

    @dkf said in Undefined OOP Techniques:

    :aintnobodygottimeforthat:

    The only correct way of using this meme: Being too lazy to actually search for the picture.



  • @dkf No, but it does mean getting them ejected from the classroom is next to impossible short of assassination or an extended smear campaign, neither of which I would recommend to Gąska.


  • Discourse touched me in a no-no place

    @ScholRLEA A punch to the face would work followed by picking them up and literally throwing them out. If he is truly incompetent, that would likely garner applause from his colleagues as well as any students who are bothering to pay attention at all…


Log in to reply