Hacker News new | ask | show | jobs
by badsectoracula 1544 days ago
> Making Scheme object-oriented is a sophomore homework assignment. On the other hand, adding object orientation to C requires the programming chops of Bjarne Stroustrup.

C++ added a ton of additional stuff to C. The original Objective-C is a much simpler approach on adding object orientation to C and at its core it'd all be about finding expressions like

    [foo bar:baz boo:hoo]
and replacing them with something like

    obj_send(foo, msg_foobarboo, baz, hoo);
and linking with an underlying runtime that handles message passing of course.

An alternative would be Turbo Pascal 5.5-style OOP where

    struct foo : base {
        foo();
        ~foo();
        void blah();
    }
    foo::foo(){ base(); }
    foo::~foo(){ ~base(); }
    void foo::blah(){}
would be accepted but aside from the C++-like syntax for constructors, destructors (which handle the hidden VMT field) and methods nothing is done automatically and instead you are expected to explicitly construct and destroy the objects (if needed), e.g.

   struct foo foo;
   foo.foo(); /* call constructor chain */
   foo.~foo(); /* call destructor chain */
or

   struct foo* foo = malloc(sizeof(struct foo));
   foo->foo(); /* call constructor chain */
   foo->~foo(); /* call destructor chain */
   free(foo);
Note that Objective-C handles (or handled at the past, not sure how things changed nowadays) allocation and construction in separate steps too.

Of course unlike a language with Lisp-like macros you'd need to modify a compiler or write a preprocessor to do the above, which makes it a bit harder, but in any case adding object orientation to C does not mean you have to make it as complex as C++.

2 comments

Yeah, I agree. If you're willing to use a garbage collection library [0], you can even have a pleasant syntax for ObjectiveC style OOP in C:

    var result = call(foo, "bar: %s boo: %f", baz, hoo);
The garbage collector will pick up the stray memory and release other resources (files) as needed, and all the standard compilers will check the varargs format string for you.

Dynamic typing, arbitrary messages, and no memory leaks. Just like Lisp. It's not perfect (string message could have typos, and might use %p for objects), but it's not too bad.

[0] https://en.wikipedia.org/wiki/Boehm_garbage_collector

Why do you need GC to support this syntax? The syntax has nothing to do with whether or not the semantics of the language permit memory leaks.
You don't need the GC of course, but manually tracking and releasing the memory takes all the fun out of this kind of high level programming, particularly when you start to nest expressions. As a hypothetical example:

    call(
        window, "draw: %d %d %p", x, y, 
        alloc("Circle radius: %d color: %u", r, 0xFF0000)
    );
That ignores the return value and loses track of the temporary argument.

This is all in response to the article claiming you "need to be Bjarne Stroustrup to add OOP to C, but it's a sophomore assignment to add it to Lisp". If I hadn't mentioned the GC, someone else would've jumped on the example for how unpleasant manual memory management is in comparison to Lisp.

I was responding to this:

> If you're willing to use a garbage collection library [0], you can even have a pleasant syntax for ObjectiveC style OOP in C:

That sounded to me as if you were claiming that GC is a pre-requisite for having a particular syntax. But I gather that's not what you meant. I'm still a little unclear about what you actually meant. You can have memory leaks like the one in your example above in vanilla C without any OOP features at all. GC is completely orthogonal to OOP, and both are completely orthogonal to syntax.

Yeah, I got your point. I don't think we're in disagreement about anything, and I probably shouldn't have conflated multiple topics. It's not really _syntax_, but this would be uglier to me:

    var temp = alloc("Circle radius: %d color: %u", r, 0xFF0000);
    var ignored = call(window, "draw: %d %d %p", x, y, temp);
    drop(ignored);
    drop(temp);
What's a good word for the overall/high level result being less attractive while the low level syntax isn't really the problem? Having a GC does tidy up the code and make it feel high level like Lisp/SmallTalk.
I don't know of a word for it. It's just a fact: GC simplifies code because it liberates the programmer from having to figure out when memory can be safely reused and transfers that responsibility to the runtime. It has next to nothing to do with any other aspect of language design, except insofar as if you have GC then your language can get by without any mechanism to allow the programmer to free allocated memory. This observation has some pretty significant practical impact, but you can't say much more about it than that.
What’s the point of a constructor that isn’t called immediately? Couldn’t you just use any arbitrary function at that point?
If a constructor is called automatically then it also needs the destructor to be called automatically and both introduce a bunch of additional complexity, especially for stack allocated functions, the need to take into account the concept of a default constructor (not necessarily requiring it but still needing to consider it), etc so that someone doing...

    while (something) {
        foo foos[42];
        /* use foos here */
    }
...will still have their 42 foo constructors and destructors called at the appropriate times.

Meanwhile by doing it manually you just bypass all that complexity at the language level and it becomes the programmer's responsibility to do it (or not) properly.

Also while you often want the above, this isn't something you always want, e.g. when you need to differentiate between where the memory of "foo" comes from and its lifecycle as an object (e.g. custom memory allocators, reusing objects without allocating/releasing their memory, etc).

Of course all the above could be done with functions too, after all there are a bunch of C programs and libraries doing OOP without the language itself providing any support for it.