Thread: Do you ever feel you want OOP done with the C way of doing things?

  1. #1
    Registered User
    Join Date
    Apr 2020
    Posts
    18

    Do you ever feel you want OOP done with the C way of doing things?

    Disclaimer: Please don't take this as an anti-C++ rant. It is not. I also beg you read my words with this caution as well: this is not about saying what language is best, but about how to do something within the C paradigm.

    I've been writing both C and C++ code for about 25 years now. However, in these last years, I often find myself having this weird feeling: I need object oriented programming, and C++ fits it, but I feel I need OOP done in the way C does things.

    Yes, I'm aware of this SO thread about OOP in C, and I'm aware of the book by Axel Shreiner.

    There some things in C++ that deviate from my preferences when programming (yes, I admit this is subjective). Some examples are templates, excessive calls to constructors and destructors in arithmetic expressions unless you explicitly take care, having the C++ standard library written from scratch rather than on top of the C runtime, having std::vector as the recommended approach for dynamically sized arrays (and then realizing you miss the C speed), lack of reflection (whenever I want automatic serialization, I want to retrieve all members in a class, so I want reflection --and then you find lots of preprocessor-based libs for emulating it), and some more that I don't remember now... anyway I think it's not a matter of a list of things, but a broader issue: I believe it's about the mindset used for designing the C++ language, that's the thing, because I believe you can have an OOP mindset together with the C design mindset.

    Then I look at the book by Axel Shreiner or to other similar efforts, and I exclaim "this is what I want!"... but using a clean and pure syntax rather than preprocessor and code transformation techniques that require a not so clean syntax.

    And of course, some very needed features, like redefining the arithmetic operators for your structs/classes, cannot be done with these techniques (well, you can of course implement an addition operator as a function, but you cannot assign the `+` character to it unless you write Cfront again).

    And I feel myself wanting to write a new Cfront. But, first, I'm not a compiler expert, and second, I think I should focus in other projects I'm working in (projects that are written in C++ but that I'd prefer to write in my OOP-ready C, so I'm finding myself in the usual "I need the tools I don't have yet" scenario).

    Don't you feel like me sometimes? If you do, were you able to find a good solution for OOP in C? (BTW, yes, I know many languages have been created in the last years, but, they tend to deviate from C far more than C++ does... I want pointers, I want the degree of control you have in C).
    Last edited by ccafe; 04-13-2020 at 07:03 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,128
    Moved.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Apr 2020
    Posts
    18
    I'm afraid that by moving this to the General Discussion board (non programming topics), it's not going to get much feedback from experienced C programmers (or at least it's going to be much reduced). I joined this forum because I wanted to discuss this with as many C programmers as possible in an environment with lots of them and outside from the limiting policies in S.O. that tend to make good questions be closed prematurely. The General Discussion board is mostly empty

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,128
    Fine - moved to the tech board instead.
    And no, it's not going back to either of the programming boards - those are for actual questions about programs.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Apr 2020
    Posts
    18
    Quote Originally Posted by Salem View Post
    Fine - moved to the tech board instead.
    ...which has even less threads (in fact my post is the only thread)
    Quote Originally Posted by Salem View Post
    And no, it's not going back to either of the programming boards - those are for actual questions about programs.
    Maybe there was a change in policy then, because the C programming board has quite a few threads that discussed abstract topics. In fact, even several of them are about OOP in C. Like this one, from last summer, and which wasn't moved.

    Anyway, don't worry. Writing the post helped me to order my ideas, so it wasn't a waste of time. I'll try to find some other place in the internet more suitable for this kind of question. I'll keep my account here for discussing just source code.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,128
    > Some examples are templates,
    No one is holding a gun to your head to use them.

    > excessive calls to constructors and destructors in arithmetic expressions unless you explicitly take care,
    Huh?
    Why would such things even be used, outside of a say a bignum class which had overloaded the usual arithmetic?

    > having the C++ standard library written from scratch rather than on top of the C runtime,
    Yeah, getting a much larger square peg to fit into a smaller round hole is kinda tricky...

    > having std::vector as the recommended approach for dynamically sized arrays (and then realizing you miss the C speed)
    Observe.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    
    int cmp(const void *pa, const void *pb) {
      const int *a = pa;
      const int *b = pb;
      if ( *a < *b ) return -1;
      if ( *a > *b ) return +1;
      return 0;
    }
    
    int *filler(const size_t num) {
      int *result = malloc(num*sizeof(*result));
      for( int i = 0 ; i < num ; i++) {
        result[i] = rand() % 10000;
      }
      return result;
    }
    
    void sorter(int *p, const size_t num) {
      qsort(p, num, sizeof(*p), cmp);
    }
    
    int main( ) {
      size_t  n = 50000000;
      int *p = filler(n);
    
      struct timeval start = { 0 }, end = { 0 };
      int a = gettimeofday(&start, NULL);
      sorter(p,n);
      int b = gettimeofday(&end, NULL);
    
      if ( end.tv_usec < start.tv_usec ) {
        end.tv_usec+= (1000000-start.tv_usec);
        end.tv_sec -= start.tv_sec + 1;
      } else {
        end.tv_usec-= start.tv_usec;
        end.tv_sec -= start.tv_sec;
      }
    
      printf("%d:%d Elapsed=%lu:%06lu\n", a, b, end.tv_sec, end.tv_usec);
      free(p);
      return 0;
    }
    
    $ gcc -g foo.c
    $ ./a.out 
    0:0 Elapsed=8:695925
    $ gcc -O2 -g foo.c
    $ ./a.out 
    0:0 Elapsed=6:201410
    Code:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstdlib>
    #include <cstdio>
    #include <sys/time.h>
    using namespace std;
    
    vector<int> filler(const size_t num) {
      vector<int> result(num);
      for( int i = 0 ; i < num ; i++) {
        result[i] = rand() % 10000;
      }
      return result;
    }
    
    bool cmp(int i,int j) {
      return (i<j);
    }
    
    void sorter(vector<int> &v) {
      sort(v.begin(), v.end(), cmp);
    }
    
    int main( ) {
      size_t  n = 50000000;
      vector<int> p = filler(n);
    
      struct timeval start = { 0 }, end = { 0 };
      int a = gettimeofday(&start, NULL);
      sorter(p);
      int b = gettimeofday(&end, NULL);
    
      if ( end.tv_usec < start.tv_usec ) {
        end.tv_usec+= (1000000-start.tv_usec);
        end.tv_sec -= start.tv_sec + 1;
      } else {
        end.tv_usec-= start.tv_usec;
        end.tv_sec -= start.tv_sec;
      }
    
      printf("%d:%d Elapsed=%lu:%06lu\n", a, b, end.tv_sec, end.tv_usec);
      return 0;
    }
    
    $ g++ -g foo.cpp && ./a.out
    0:0 Elapsed=18:932466
    $ g++ -g -O2 foo.cpp && ./a.out
    0:0 Elapsed=3:704583
    > Don't you feel like me sometimes?
    No.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    149
    Quote Originally Posted by ccafe View Post
    Disclaimer: Please don't take this as an anti-C++ rant. It is not. I also beg you read my words with this caution as well: this is not about saying what language is best, but about how to do something within the C paradigm.

    I've been writing both C and C++ code for about 25 years now. However, in these last years, I often find myself having this weird feeling: I need object oriented programming, and C++ fits it, but I feel I need OOP done in the way C does things.

    Yes, I'm aware of this SO thread about OOP in C, and I'm aware of the book by Axel Shreiner.

    There some things in C++ that deviate from my preferences when programming (yes, I admit this is subjective). Some examples are templates, excessive calls to constructors and destructors in arithmetic expressions unless you explicitly take care, having the C++ standard library written from scratch rather than on top of the C runtime, having std::vector as the recommended approach for dynamically sized arrays (and then realizing you miss the C speed), lack of reflection (whenever I want automatic serialization, I want to retrieve all members in a class, so I want reflection --and then you find lots of preprocessor-based libs for emulating it), and some more that I don't remember now... anyway I think it's not a matter of a list of things, but a broader issue: I believe it's about the mindset used for designing the C++ language, that's the thing, because I believe you can have an OOP mindset together with the C design mindset.

    Then I look at the book by Axel Shreiner or to other similar efforts, and I exclaim "this is what I want!"... but using a clean and pure syntax rather than preprocessor and code transformation techniques that require a not so clean syntax.

    And of course, some very needed features, like redefining the arithmetic operators for your structs/classes, cannot be done with these techniques (well, you can of course implement an addition operator as a function, but you cannot assign the `+` character to it unless you write Cfront again).

    And I feel myself wanting to write a new Cfront. But, first, I'm not a compiler expert, and second, I think I should focus in other projects I'm working in (projects that are written in C++ but that I'd prefer to write in my OOP-ready C, so I'm finding myself in the usual "I need the tools I don't have yet" scenario).

    Don't you feel like me sometimes? If you do, were you able to find a good solution for OOP in C? (BTW, yes, I know many languages have been created in the last years, but, they tend to deviate from C far more than C++ does... I want pointers, I want the degree of control you have in C).

    A better alternative would be nice, but I guess I'm just content enough with what's available. Most popular languages can be used even on the most exotic embedded systems these days.

    Have you taken a look at Lisp? It doesn't have things like proper pointers, but it is very customizable, which does make writing cleaner code a lot easier.
    The power of null.

  8. #8
    Registered User
    Join Date
    Aug 2019
    Location
    inside a singularity
    Posts
    302
    I don't know if I sound stupid but isn't qsort() what makes the C implementation slower? I know QuickSort is fast but from qsort, qsort_s - cppreference.com:
    Despite the name, neither C nor POSIX standards require this function to be implemented using quicksort or make any complexity or stability guarantees.
    I also know that std::sort() is some kinda hybrid mix of two or more different sorting algorithms, and from what I've come to know by looking at its code. It's guaranteed O(N*log(N)) in worst case too, as you already know. So, my question is, are your examples actually fit for comparison against one another?
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning." - Rick Cook, The Wizardry Compiled

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,863
    Quote Originally Posted by Zeus_
    I also know that std::sort() is some kinda hybrid mix of two or more different sorting algorithms, and from what I've come to know by looking at its code.
    The C++ standard does not make any requirements on the algorithm used to implement std::sort other than for it to be a comparison-based sort with the given time complexity. For qsort, while it is true that there technically isn't even a time complexity guarantee, if C standard library implementations are so poor that they would not implement qsort with an O(n log n) algorithm, then that suggests that in general C is not a good language to use where speed is desired... which I think you would agree is a rather strange conclusion.

    Quote Originally Posted by ccafe
    anyway I think it's not a matter of a list of things, but a broader issue: I believe it's about the mindset used for designing the C++ language, that's the thing, because I believe you can have an OOP mindset together with the C design mindset.
    Considering that C++ is a multi-paradigm programming language, what do you mean by that? What exactly is "the C design mindset"? Consider that quite a great deal of C++ code does not follow "proper" OO design of the kind that architects according to the open-closed principle etc with inheritance and polymorphism, but rather uses objects as simpler abstractions in a fashion common to C: in such cases the classes are more like typical C structs, but with access control. Yet, these may be done in conjunction with OO design for other parts of the program.
    Last edited by laserlight; 04-13-2020 at 01:54 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    149
    Quote Originally Posted by laserlight View Post
    The C++ standard does not make any requirements on the algorithm used to implement std::sort other than for it to be a comparison-based sort with the given time complexity. For qsort, while it is true that there technically isn't even a time complexity guarantee, if C standard library implementations are so poor that they would not implement qsort with an O(n log n) algorithm, then that suggests that in general C is not a good language to use where speed is desired... which I think you would agree is a rather strange conclusion.
    The C version also has to do all of that pointer dereferencing, whereas with C++ much of that code can be inlined. So that's going to impact performance too.
    The power of null.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,863
    Quote Originally Posted by Sir Galahad View Post
    The C version also has to do all of that pointer dereferencing, whereas with C++ much of that code can be inlined. So that's going to impact performance too.
    I believe that's Salem's point, that "C speed" isn't a given.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    149
    Quote Originally Posted by laserlight View Post
    I believe that's Salem's point, that "C speed" isn't a given.
    Well a lot of people might just assume that it's strictly an algorithmic issue. It helps to understand just how powerful C++ is in that respect.
    The power of null.

  13. #13
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,875
    Have you seen "Patterns in C" by Adam Petersen?

    And no, I've never had the desire to use C++.

    I have 2 things that I code:
    1) Small 8-bit microcontrollers that have no OS (bare metal programming)
    2) Windows 10

    When it comes to (1) I use C. Most programs are very simple, and a state machine that reacts to inputs is the best approach.

    When it comes to (2) I use C# and XAML.

    These programs are much larger in complexity, and interact with the .NET framework. This is (of course) OOP; however what is more important is the design pattern that is implemented. I would never use C for this, because what would take me weeks to write and debug takes less than a minute with C#.

    Both programs require them to have a good Architecture, and an appropriate design pattern for the solution.
    Last edited by Click_here; 04-13-2020 at 10:48 PM.
    Fact - Beethoven wrote his first symphony in C

  14. #14
    Registered User
    Join Date
    Apr 2020
    Posts
    18
    Quote Originally Posted by Salem View Post
    [...]
    Observe.
    [...]
    Your timing example is very interesting. Regarding your other comments, I could reply them, but then we would be in a C vs C++ war, and that wasn't the point, as I wrote at the top of my post. It's not a matter of which of them is better, but wishing to have OOP done with the C style.

    Quote Originally Posted by laserlight View Post
    [...]
    Considering that C++ is a multi-paradigm programming language, what do you mean by that? What exactly is "the C design mindset"?[...]
    I do notice a big difference in mindset behind the design of C and the design of C++, and no, it's not about OOP. In this moment proper words don't come to my mind, but I feel templates and the STL can be good examples of this different mindset: I mean, you would never implement arrays using templates (std::vector) if you had to design a new OOP language with the "C mindset". The same goes to strings (no, you wouldn't dare to move from arrays to templates). Another point is perhaps constructors... every binary operator needs to create at least a temporary object, so if you were designing OOP with a "C mindset" you would "forbid" constructors, and force all constructors to be just initialization lists (then maybe some workaround for doing more flexible constructors, but with a longer syntax, so that it's harder to write code that will generate slow constructors)... really the proper words don't come to my mind, but I see a different mindset behind both languages.

    Quote Originally Posted by Click_here View Post
    Have you seen "Patterns in C" by Adam Petersen?
    I didn't know about it, but I checked it now, and he seems not to like OOP... I do need OOP.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,863
    Quote Originally Posted by ccafe
    I feel templates and the STL can be good examples of this different mindset: I mean, you would never implement arrays using templates (std::vector) if you had to design a new OOP language with the "C mindset".
    How would you implement generic arrays if you had to design a new OOP language with the "C mindset"?

    Also, I note that generic programming with templates in C++ is another programming paradigm, not OOP. So if you're saying that generic programming in C++ differs significantly from both the "OOP mindset" and the "C mindset" in terms of programming paradigm, of course that is true, but it has nothing to do with "OOP done with the C way of doing things" because it is not OOP.

    Quote Originally Posted by ccafe
    Another point is perhaps constructors... every binary operator needs to create at least a temporary object, so if you were designing OOP with a "C mindset" you would "forbid" constructors, and force all constructors to be just initialization lists (then maybe some workaround for doing more flexible constructors, but with a longer syntax, so that it's harder to write code that will generate slow constructors)
    Are you aware of move semantics in C++? To some extent it can address your concerns about such temporaries when chaining binary operators (i.e., instead of doing expensive construction to create yet more temporaries, just "steal" the resources from the existing temporary). If you're not chaining them but are concerned about the expensive creation of a temporary in the first place, then I'd argue that that just a fault of the design: you will have the exact same issue in C if you design it in the same way, and if you must design it that way to be expensive to create new objects, then it would be the fault of the user for not calling a function that operates on the current object, be it a named function in C or the assignment version of the binary operator in C++.

    Consequently, I don't quite understand how is this a "C mindset". In C, init functions don't necessarily only set the initial values for a struct in the library: they might be more expensive as you suggest with "more flexible constructors", e.g., by performing dynamic memory allocation or accessing other resources like files as in fopen: is this then not the "C mindset"? Furthermore, excluding assignment operators and overloading the bit shifting operators for I/O (which do not have the issue of temporaries), overloading binary operators in C++ isn't all that common, yet it sounds like you're saying that because classes with binary operators that result in temporaries could be poorly designed, it would be better language design to "force all constructors to be just initialization lists".
    Last edited by laserlight; 04-14-2020 at 03:37 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. how do you feel...
    By ILoveVectors in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 08-16-2005, 05:47 AM
  2. I feel.....clean....
    By jdinger in forum A Brief History of Cprogramming.com
    Replies: 4
    Last Post: 04-11-2003, 06:46 PM
  3. win xp look&feel
    By aym_7 in forum Windows Programming
    Replies: 9
    Last Post: 05-11-2002, 08:28 PM
  4. I feel sorry for...
    By Betazep in forum A Brief History of Cprogramming.com
    Replies: 43
    Last Post: 11-25-2001, 03:50 AM
  5. I feel sorry for
    By Betazep in forum A Brief History of Cprogramming.com
    Replies: 10
    Last Post: 10-28-2001, 11:23 PM

Tags for this Thread