Hacker News new | past | comments | ask | show | jobs | submit login
The C Object System (2010) (arxiv.org)
68 points by signa11 87 days ago | hide | past | web | favorite | 24 comments



This has been done before many times in many ways for many different purposes, some worse than others, as object systems for C (Xtk intrinsics widgets, GTK's GObjects), object systems written in C for other languages (ScriptX's "Objects in C", TCL/Tk widgets, Lua objects), cross-language object systems (Microsoft COM, IBM SOM, OpenDoc), distributed object proxy systems (CORBA, DCOM, DSOM), and object oriented C language dialects (Objective C, C++, Java).

Not that it's not worth doing again for fun or to explore different techniques and purposes. But the ones that are in use in the real world are incredibly clumsy and complex, require a lot of boilerplate and yak shaving, and you have to buy into a big toolchain and religion.

"The guy who invented the wheel was an idiot. The real genius was the guy who invented the other three." -Sid Caesar


Marcel's corollary to Greenspun's tenth rule: any sufficiently large C/C++ contains an ad-hoc, informally-specified, bug-ridden, slow implementation of most of Objective-C.

¯\_(ツ)_/¯


Just say no, that path leads to madness. C is not the right language for fancy abstractions, it will come back and bite your head off when you least expect it. It can be done, but that doesn't mean worth doing. GObject suffers from some of the same delusions.

The whole point of writing C is to keep it simple and only build exactly what's needed. No other language I've tried comes close to supporting the same level of custom fitting. This is also the reason it's potentially really fast; more because it encourages simple, direct solutions than anything else.

Virtual dispatch is a function pointer, either embedded directly in the value or together with others in a shared vtable. A type id may be added to the vtable if needed. Avoid inheritance tricks, composition is mostly the right answer in C. Downcasting is a solved [0] problem [1].

[0] https://gitlab.com/sifoo/snigl/blob/master/src/snigl/type.c#...

[1] https://gitlab.com/sifoo/snigl/blob/master/src/snigl/util.h#...


Not just that, I also just don't understand the point.

" a small C library which implements high-level concepts available in Clos, Objc"

Well, Objective-C is "a small C library" which implements the high-level concepts available in Objective-C. Mostly. At some point, the creators found out that they needed a "compiler" to gather up and unique selectors, and at that point adding a small amount of syntactic sugar was easy and useful.

An object is a struct with pointer to a class as its firs element. (A class is another struct, it is also an object) And 'id' is a pointer to such an object.

A selector (SEL) is a uniqued C-String.

A method is a C function that takes an object and a selector as its first arguments:

    -hi:there {
    }
is roughly the same as

    id hi( id self, SEL _cmd, id there ) {

    }
(The naming is slightly different)

Sending a message is calling the function objc_msgSend(). And if you don't like the syntactic additions, just call objc_msgSend() yourself.

Those who don't understand Objective-C are doomed to reinvent it?


Yes, it seemed strange to me as well. "We really, really like Objective-C and decided to poorly implement it in C". Just use Objective-C! It's perfectly compatible with C, it has better syntax and better compilers with better error messages. This is just crazyness.


[1] is #define[d] as sgl_baseof(type, field, ptr) that appears to used to return a pointer to a "type", which is a value stored in memory at run-time, of a field in an object (ptr)? I and many others would not consider a run-time type system to be "the" solution to downcasting in C. Regarding the use of C for "fancy abstractions" such as classes and objects, the derivatives of Cfront (Corneau C/C++), which is an implementation of C++ using C, are not just alive, but have been chosen to implement many production systems (https://en.wikipedia.org/wiki/Edison_Design_Group) used by millions today, although they too "inherit" the issues with the C standard. It is true that the GObject system has many problems one of which is the reference counting (sink/sunk) process as requiring a certain memory (de)allocation mechanics as a requirement of the object system is not the most applicable in certain situations.


You have it backward, Comeau is a compiler implemented with the EDG front end not the other way around. Also I'm not sure there is any shared history between Comeau and Cfront.

Finally, as far as I understand Cfront was a proper C++ compiler that simply targeted C instead of ASM (like many compilers for other languages do ), not some sort of C preprocessor (Cfront was initially bootstrapped with a c-with-classes preprocessor though).


Comeau is a compiler implemented with the EDG front end. If the other way around was some how implied, then it was not the intention. As for Comeau and Cfront, Comeau Computing's CEO, Greg Comeau, provided one of the early ports of cfront to the PC: https://en.wikipedia.org/wiki/Comeau_C/C%2B%2B. Cfront is not just a preprocessor and if the comparison is limited to only C library implementations of objects such as COS, then CPre / C with Classes would be the applicable choice and not Cfront. But, the original point was not meant to exclude "trans"pilers or compilers that output to C such as Genie, Vala, etc.


The type in question is the containing C struct type. Think of sgl_baseof as the opposite of offsetof. I didn't come up with it myself of course, it's probably older than I am; I borrowed it from the Linux kernel. The other link is an example of how it's used.


sql_baseof as shown is defined in the header using offsetof. offsetof is an implementation-specific macro. Whatever it does is specific to the compiler that provides it. You cannot generalize from its definition for one or many compilers to a language requirement. https://stackoverflow.com/questions/26906621/does-struct-nam...


I fail to see your point here.

sgl_baseof uses offsetof with a valid struct type and a valid field name, so where is the UB? Unless you feed it an invalid pointer, but then all bets are off.


Sorry, still not getting it.

If an implementation provides offsetof and it doesn't work, that implementation would go out of fashion in a heart beat.

Where is the practical use of this information?

How is this even an argument?


The use of the Offsetof macro in a program will cause undefined behavior when compiled with GCC or Clang and they are still "in fashion" as far as I am aware. The practical use of this information is to prevent the occurrence of undefined behavior by knowing not to use offsetof for example with GCC and instead use __builtin_offsetof in the specific case of GCC. The argument appears to be that you are claiming that what sgl_baseof does is not undefined behavior and I am claiming that it is not possible to infer that without specifying the implementation of the offsetof macro.


https://en.wikipedia.org/wiki/Offsetof repeats what is said the SO link and might be helpful? The occurrence of the UB is not dependent on the parameters that sgl_baseof is called with. The UB may occur solely based on the compiler and standard library implementation. If the UB does occur based on those two and offsetof is not redefined somewhere, then the UB occurs anywhere offsetof is used.


>requiring a certain memory (de)allocation mechanics as a requirement of the object system is not the most applicable in certain situations

To destruct -- to collect.

To collect -- perchance to tenure: ay there's the rub!

For in that collection of destruction what cycles may come

When we have shuffled off this mortal core,

Must give us callbacks.


Why not just write object oriented shell scripts and classes in the file system? ;)

The patent's expired (I like to think of this as a Mercy Patent, that benefits society by keeping people from doing this for 20 years):

Method for apparatus for implementing a class hierarchy of objects in a hierarchical file system

https://patents.google.com/patent/US5187786

Abstract

A method and apparatus for implementing a class hierarchy of objects in a hierarchical file system is disclosed, which does not require the support of additional file attributes by the hierarchical file system, and has particular application to object oriented programming in window-based computer systems. The class hierarchy comprises a root class, a plurality of classes and a plurality of class instances. The root class is implemented with a hierarchy of root class directory and root class files. Each class is implemented with a hierarchy of class directories and class files comprising the class methods, and the initial values of the class instance variables. Each class instance is implemented with a hierarchy of class instance directory and class instance files comprising the class instance variables. Each hierarchy of directories and files also comprises a path file. The content of these path files are logically related to each other, based on their class' relationships. By controlling the invocation of class methods, using these path files, inheritance is achieved. By accessing the class instance variables through the class methods, data abstraction is also achieved. Additionally, the method and apparatus also supports the pseudo class instance/class "Self" and "Super" when invoking another class method by a class method.


This is cute, albeit a terrible idea in practice. It's also misleading to compare it favorably to CLOS and come up with statements like "a framework that brings C to the level of other high level programming languages and beyond". It's a bad idea to examine CLOS in isolation and try to replicate its features, without understanding - or ignoring - how it fits in with the rest of Common Lisp and how the whole is greater than the sum of its parts. CLOS is extremely powerful because there is tremendous synergy with the interactive, image-based development style that CL is designed around.

You focus on CLOS in isolation and you not only end up missing the point completely but also end up with a frankenstein monstrosity that can be very destructive. This also reminds me of Alan Kay talking about how most OO languages completely missed the point unlike Lisp that got it: Late binding.


The Alan Kay talk sounds interesting; do you have a link to it?


It is his OOPSLA 97 keynote. I am sure you can find it online.


Is there anything similar for Go?


[flagged]


Please don't do programming language flamewar here. We're trying to avoid that kind of thing.

https://news.ycombinator.com/newsguidelines.html


Still better than Swiss cheese security exploit friendly C.


And nowhere near as good as D.


Unfortunely D lacks Google level social sponsoring.




Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: