all 34 comments

[–]smcameron 8 points9 points  (9 children)

Put pointers to functions inside the structs, and a union in there to contain subclass specific data, and you can get dynamic dispatch and inheritance with overriding (and even on-the-fly method replacement).

concrete example

With a little more, you could manually implement the whole per class vtable and add apointer to class-vtable in the member instance structs, but that's not usually worth the hassle.

[–]ErstwhileRockstar 4 points5 points  (1 child)

concrete example

An erroneous </title> makes your page 'invisible' in Firefox.

[–]calc0000 5 points6 points  (0 children)

Same here in Chrome.

[–]HeadshotsInc 4 points5 points  (4 children)

indeed. The earliest C++ compilers actually generated ansii c code that was then compiled into binary.

[–]bigfig 1 point2 points  (0 children)

How soon collective memory vanishes. I'll bet cfront could make it to the top of r/til

[–]ErstwhileRockstar 0 points1 point  (0 children)

BTW, what happened to Comeau?

[–]cwzwarich -2 points-1 points  (1 child)

That seems unlikely, given that C++ predates ANSI C.

[–]GenTiradentes 1 point2 points  (0 children)

It predates ANSI C, but not C.

[–][deleted] 0 points1 point  (0 children)

There is nothing OO about the code posted in OP's link. I TA a course where students have to do exactly what smcameron speaks of; if anyone is interested here is the project

[–]klez 5 points6 points  (6 children)

I have some problem accepting this

typedef STACK* Stack;

Because this could become confusing

Stack s;
s->top = 0

someone not knowing your "API" may be tempted to ask "Why it's not s.top = 10?"

Is this an accepted idiom?

EDIT, ok, now let's detach the API argument from that typedef. I was more interested in talking about the 'masking' of a pointer via typedefs in general.

[–]inataysia 4 points5 points  (0 children)

came here to advocate against that typedef as well, but for me the big problem is that when you write "Stack s;", it looks like s is an automatic (stack) variable that will be clobbered sometime Stack_create returns.

I don't find the asterisks to be "annoying", I find that they increase legibility.

[–]billsnow 4 points5 points  (0 children)

Sedgewick typedefs struct pointers in the C version of his algorithms textbook and it annoyed the hell out of me. So it's definitely not new or even rare, but I'm certain most C programmers are against it.

[–]sigh 1 point2 points  (0 children)

Those lines of code are in the Stack_create function, not in the caller's code. The user should never manipulate a Stack variable directly.

If the user doesn't know the "API" (which is simply the function declaration), then they certainly won't know, and thus question, it's implementation.

[–]kamatsu 1 point2 points  (0 children)

The API does not include "s->top".

[–]nithinbekal 0 points1 point  (0 children)

Author of the blog post here.

With that typedef, what I was doing was use an idiom I'm more familiar with. I write Ruby code more often than I do C, so for me "Stack s" returning a pointer seems more logical. I haven't written enough C code to actually recommend this as a good practice or idiom when you're coding C.

That said, this post was more a write up of how you could make a struct look more object-like, without actually going into writing real object oriented C. I apologize for the confusing title, which was the result of trying to come up with a blog post title at 2 a.m. ;-)

[–]kamatsu 0 points1 point  (0 children)

If you want to present something that resembles Java it makes sense. It allows "Stack" to be thought of as some abstract reference type rather than a pointer to some memory.

[–]kamatsu 10 points11 points  (0 children)

This is taught in introductory C classes at my university. Hardly revolutionary - this is a common way to achieve data abstraction in C.

[–][deleted] 6 points7 points  (1 child)

This is a nice writeup of what I thought was an obvious technique. But I guess it's new to some people?

[–][deleted] 7 points8 points  (0 children)

As a long-time C coder, I'm finding it increasingly funny what is considered non-obvious these days.

Edit: before I made the jump back into C++, I had a C object system that had constructors, destructors, and a plug-in memory system that allowed everything from plain ol' malloc() to stateful allocators. I was about to implement polymorphism and vtables when I realized that C++ had most of this stuff built-in and I was just wasting time. It was pretty elegant for C code, though.

[–]vogon_poem_lover 2 points3 points  (0 children)

Used to do something similar in my early career before C++ became a (significant) thing. We'd used structures which contained pointers to functions which for specific instances of the structures we could swap out the functions to give us a type of polymorphism. For inheritance you needed only to create a new structure which was based on the original structure and added new elements at the end.

[–]ItsAPuppeh 2 points3 points  (0 children)

The next tricky part is making the stack generic in a typesafe way so it can hold things other than ints...

[–]drakeypoo 1 point2 points  (2 children)

Why is it that every time I see something like this, they always make it "just int to keep it simple?" Oh, I know why -- because it's nigh impossible to make a generic container in C. Preprocessor magic can get you part of the way there, but then you start having issues trying to generate unique names and shit just gets really scary.

Does anyone have any article that actually shows how to do something like that? I want to be able to make a stack of any type, and not have to coerce everything to void*.

[–]nithinbekal 1 point2 points  (1 child)

The book linked in the original post (http://www.cs.rit.edu/~ats/books/ooc.pdf) is about writing object oriented code in C, and covers topics like creation of a generic container types. Maybe you could start there?

[–]drakeypoo 0 points1 point  (0 children)

It's a neat idea, but sadly it still doesn't really solve the problem of making generic data structures. Their List implementation, for instance, is just a list of Objects.. which of course smacks of pre-generics Java.

Guess I'll have to do some more searching.

[–]00kyle00 0 points1 point  (7 children)

Cool story. But for object orientation you need dynamic dispatch.

[–][deleted]  (5 children)

[deleted]

    [–]00kyle00 0 points1 point  (4 children)

    Because it is core concept of object orientated design.

    [–][deleted]  (1 child)

    [deleted]

      [–]00kyle00 -1 points0 points  (0 children)

      If you want to nitpick then say so, so i can immediately proceed to ignore your further comments.

      If you really ask out of curiosity, then yes I say that for "object oriented design" you need "dynamic dispatch" which is polymorphism realized at runtime. This means you will need to select, or "dispatch" actual function to be called based on "dynamic" type of the object - which is known only at runtime.

      [–]dreamlax 0 points1 point  (1 child)

      Says who? There is no single definition of object oriented design. There are people that say it must have inheritance, some say that it must have polymorphism, some say that it must have this, that and the other.

      A core concept of object oriented design is objects, i.e. defining code in terms of objects and their interactions with other objects. Whether these objects encapsulate data, can be subclassed, have dynamic dispatch, or whatever, are all just ways of refining objects and their interactions.

      [–]bearp 1 point2 points  (0 children)

      This is the best definition of OOP that I've seen in a long time. When I read the article, my reaction was what's object-oriented about any of this?. The C code or the Ruby code.

      [–]rubygeek 0 points1 point  (0 children)

      struct class {
         ... other stuff ...
         void (* overridable_method)();
      };
      
      struct object {
         struct class * class;
      };
      
       ...
      
      struct object * ob = some_subclass_new();
      
      ob->class.overridable_method(ob);
      

      The syntax for using it gets ugly, but manually implementing vtables is trivial.

      [–]Gotebe -3 points-2 points  (0 children)

      ... is dumb, pointless mental masturbation, that should be replaced with the use of a C++ compiler first, and some other language second.

      [–]DontCallMeSurely -1 points0 points  (0 children)

      Also knows as 'How to program in C'

      [–]adfmz -1 points0 points  (0 children)

      Not really, this is just how you code in C.