New release of the Dynace OO extension to C

20 views
Skip to first unread message

Blake McBride

unread,
Jul 13, 2009, 4:10:05 PM7/13/09
to

A new release of Dynace is available at: http://blake.mcbride.name

This release has a new port to the Mac and updated support for Wine.

Dynace is an open source, OO extension to C that gives C (or C++), a
full meta-object protocol, and multiple inheritance. Dynace is designed
to solve many of the problems associated with C++ while being easier to
learn and containing more flexible object oriented facilities. Dynace is
able to add facilities previously only available in languages such as
Smalltalk and CLOS without all the overhead normally associated with
those environments.

The Dynace system also includes a GUI development system that runs under
Win32 or Wine (Linux, etc.).

Dynace runs on:
Windows
Apple Mac
Linux
FreeBSD
OpenSolaris


Blake McBride

Juha Nieminen

unread,
Jul 13, 2009, 6:23:03 PM7/13/09
to
Blake McBride wrote:
> Dynace is an open source, OO extension to C that gives C (or C++), a
> full meta-object protocol, and multiple inheritance. Dynace is designed
> to solve many of the problems associated with C++ while being easier to
> learn and containing more flexible object oriented facilities. Dynace is
> able to add facilities previously only available in languages such as
> Smalltalk and CLOS without all the overhead normally associated with
> those environments.

It would be interesting to know what are the differences between
Dynace and Objective-C. If someone would not want to use C++ and instead
use a C with OO extensions, why would he choose Dynace instead of
Objective-C? What does the former have to offer that the latter doesn't?

I also think that the "Dynace vs. C++" is quite misleading at parts.
Skipping your bullshit about C++ creating unmaintainable code (compared
to C), I would like to note that this:

"Dynace is not an interpretive language. Dynace programs are compiled
with a standard C compiler. The majority of the code is just standard
compiled C code with no performance penalty. The only place Dynace
incurs a runtime cost is at the point of method dispatch. Since C++ also
incurs a runtime cost when using virtual functions, there is not much of
a difference between the performance of Dynace programs when compared to
C++."

is misleading. From what I can gather, in Dynace, like in Objective-C,
*all* method calls are dynamically bound, so they always incur a
penalty. You conveniently chose to compare them only to C++ virtual
functions and skipped commenting on non-virtual functions. Someone who
doesn't know C++ might get the wrong impression that in C++ all method
calls are also always dynamically bound.

Also this:

"Dynace comes with a complete set of fundamental classes including
classes to represent all the basic C types, a variety of container
classes (sets, dictionaries, linked lists, associations, etc.),
multi-dimensional dynamic arrays, threads, pipes and semaphores."

falsely gives the impression that C++ does not come with container
classes such as sets, dictionaries (ie. maps), linked lists,
multi-dimensional dynamic arrays, etc. This is deceiving.

Miles Bader

unread,
Jul 14, 2009, 4:28:36 AM7/14/09
to
Juha Nieminen <nos...@thanks.invalid> writes:
> "Dynace is not an interpretive language. Dynace programs are compiled
> with a standard C compiler. The majority of the code is just standard
> compiled C code with no performance penalty. The only place Dynace
> incurs a runtime cost is at the point of method dispatch. Since C++ also
> incurs a runtime cost when using virtual functions, there is not much of
> a difference between the performance of Dynace programs when compared to
> C++."
>
> is misleading. From what I can gather, in Dynace, like in Objective-C,
> *all* method calls are dynamically bound, so they always incur a
> penalty. You conveniently chose to compare them only to C++ virtual
> functions and skipped commenting on non-virtual functions. Someone who
> doesn't know C++ might get the wrong impression that in C++ all method
> calls are also always dynamically bound.

It also seems to be weasel-worded about the actual costs: "C++ also
incurs a runtime cost" ... but how much, specifically?! C++'s method
dispatch mechanism, of course, is particularly simple and fast (though
of course that involves various tradeoffs).

One does get the impression that website was written by marketing...

-Miles

--
Carefully crafted initial estimates reward you not only with
reduced computational effort, but also with understanding and
increased self-esteem. -- Numerical methods in C,
Chapter 9. "Root Finding and Nonlinear Sets of Equations"

Blake McBride

unread,
Jul 14, 2009, 10:37:37 AM7/14/09
to
Juha Nieminen wrote:
> Blake McBride wrote:
>> Dynace is an open source, OO extension to C that gives C (or C++), a
>> full meta-object protocol, and multiple inheritance. Dynace is designed
>> to solve many of the problems associated with C++ while being easier to
>> learn and containing more flexible object oriented facilities. Dynace is
>> able to add facilities previously only available in languages such as
>> Smalltalk and CLOS without all the overhead normally associated with
>> those environments.
>
> It would be interesting to know what are the differences between
> Dynace and Objective-C. If someone would not want to use C++ and instead
> use a C with OO extensions, why would he choose Dynace instead of
> Objective-C? What does the former have to offer that the latter doesn't?

Dynace - full meta-object protocol. Every object, including classes, are
just objects treated the same. Even base classes such as Object or
Class are just instances of other classes - like Smalltalk & CLOS.

Objective-C - classes are largely compile-time objects that are treated
differently from instances of those objects. This is a much more
restrictive model.

Dynace - C syntax - no new syntax to learn

Objective-C - adds Smalltalk syntax. Increases learning curve adding no
additional expressiveness.

Dynace - written in standard C - very, very portable

Objective-C - in most cases the platform has to have an Objective-C compiler

Dynace supports true multiple inheritance

Objective-C has only single inheritance


>
> I also think that the "Dynace vs. C++" is quite misleading at parts.
> Skipping your bullshit about C++ creating unmaintainable code (compared
> to C), I would like to note that this:
>
> "Dynace is not an interpretive language. Dynace programs are compiled
> with a standard C compiler. The majority of the code is just standard
> compiled C code with no performance penalty. The only place Dynace
> incurs a runtime cost is at the point of method dispatch. Since C++ also
> incurs a runtime cost when using virtual functions, there is not much of
> a difference between the performance of Dynace programs when compared to
> C++."
>
> is misleading. From what I can gather, in Dynace, like in Objective-C,
> *all* method calls are dynamically bound, so they always incur a
> penalty. You conveniently chose to compare them only to C++ virtual
> functions and skipped commenting on non-virtual functions. Someone who
> doesn't know C++ might get the wrong impression that in C++ all method
> calls are also always dynamically bound.

I think I was clear "WHEN USING virtual functions". If they don't
understand that then they probably don't understand the point of that
whole section.

>
> Also this:
>
> "Dynace comes with a complete set of fundamental classes including
> classes to represent all the basic C types, a variety of container
> classes (sets, dictionaries, linked lists, associations, etc.),
> multi-dimensional dynamic arrays, threads, pipes and semaphores."
>
> falsely gives the impression that C++ does not come with container
> classes such as sets, dictionaries (ie. maps), linked lists,
> multi-dimensional dynamic arrays, etc. This is deceiving.

Imply what you like, and I can't account for everything others will
impute into my factual statements.

Look, you seem to be hostile to Dynace. Don't use it. There is room
for all of us. In spite of your comments, Dynace does offer solutions
to some C++ issues. All languages have trade offs. Dyance solves many
issues commonly known in the C++ world at the expense of, essentially,
causing all method calls to be virtual.

Blake McBride

Blake McBride

unread,
Jul 14, 2009, 10:44:22 AM7/14/09
to Miles Bader
Miles Bader wrote:
> Juha Nieminen <nos...@thanks.invalid> writes:
>> "Dynace is not an interpretive language. Dynace programs are compiled
>> with a standard C compiler. The majority of the code is just standard
>> compiled C code with no performance penalty. The only place Dynace
>> incurs a runtime cost is at the point of method dispatch. Since C++ also
>> incurs a runtime cost when using virtual functions, there is not much of
>> a difference between the performance of Dynace programs when compared to
>> C++."
>>
>> is misleading. From what I can gather, in Dynace, like in Objective-C,
>> *all* method calls are dynamically bound, so they always incur a
>> penalty. You conveniently chose to compare them only to C++ virtual
>> functions and skipped commenting on non-virtual functions. Someone who
>> doesn't know C++ might get the wrong impression that in C++ all method
>> calls are also always dynamically bound.
>
> It also seems to be weasel-worded about the actual costs: "C++ also
> incurs a runtime cost" ... but how much, specifically?! C++'s method
> dispatch mechanism, of course, is particularly simple and fast (though
> of course that involves various tradeoffs).

In C++, if you use all virtual functions, the dispatch tables grow
geometrically. Dynace uses the same dispatching method augmented with a
method cache. You can control the tradeoff between the two. If you
grow the dispatch tables geometrically, like C++, Dynace is exactly as
fast as C++ (using virtual functions). If you fix the size of the
dispatch tables Dynace uses a method cache avoiding any dispatch table
growth but at the cost of a cache lookup.

Dynace also supports statically linked methods with no overhead, like
C++. It's just not the default. So really there is not much of a
difference.


>
> One does get the impression that website was written by marketing...

Dynace, all the code, and all the documentation were done by one person
- me. No big company.

>
> -Miles
>

Blake McBride

unread,
Jul 14, 2009, 10:48:57 AM7/14/09
to
Miles Bader wrote:
> Juha Nieminen <nos...@thanks.invalid> writes:
>> "Dynace is not an interpretive language. Dynace programs are compiled
>> with a standard C compiler. The majority of the code is just standard
>> compiled C code with no performance penalty. The only place Dynace
>> incurs a runtime cost is at the point of method dispatch. Since C++ also
>> incurs a runtime cost when using virtual functions, there is not much of
>> a difference between the performance of Dynace programs when compared to
>> C++."
>>
>> is misleading. From what I can gather, in Dynace, like in Objective-C,
>> *all* method calls are dynamically bound, so they always incur a
>> penalty. You conveniently chose to compare them only to C++ virtual
>> functions and skipped commenting on non-virtual functions. Someone who
>> doesn't know C++ might get the wrong impression that in C++ all method
>> calls are also always dynamically bound.

In C++, if you use all virtual functions, the dispatch tables grow
geometrically. Dynace uses the same dispatching method augmented with a
method cache. You can control the tradeoff between the two. If you
grow the dispatch tables geometrically, like C++, Dynace is exactly as
fast as C++ (using virtual functions). If you fix the size of the
dispatch tables Dynace uses a method cache avoiding any dispatch table
growth but at the cost of a cache lookup.

Dynace also supports statically linked methods with no overhead, like

C++. It's just not the default. So really there is not much of a
difference.


>
> It also seems to be weasel-worded about the actual costs: "C++ also
> incurs a runtime cost" ... but how much, specifically?! C++'s method
> dispatch mechanism, of course, is particularly simple and fast (though
> of course that involves various tradeoffs).
>
> One does get the impression that website was written by marketing...

Dynace, all the code, and all the documentation were done by one person

- me. No big company, and I've never had a marketing position or class.

>
> -Miles
>

Alf P. Steinbach

unread,
Jul 14, 2009, 11:12:39 AM7/14/09
to
* Blake McBride:

> Miles Bader wrote:
>>
>> It also seems to be weasel-worded about the actual costs: "C++ also
>> incurs a runtime cost" ... but how much, specifically?! C++'s method
>> dispatch mechanism, of course, is particularly simple and fast (though
>> of course that involves various tradeoffs).
>
> In C++, if you use all virtual functions, the dispatch tables grow
> geometrically.

Perhaps you mean that the size of all vtables for all classes, for the
never-occurring-in-practice case of all classes being in the same single
inheritance chain, grows as the square number of classes.

Most classes have at most some tens of methods, so even for that case it's about
hundreds of *bytes* per class -- not per instance, but maximum per class.

A typical desktop system has between one and four billion bytes of RAM.

Cheers & hth.,

- Alf

Blake McBride

unread,
Jul 14, 2009, 11:42:39 AM7/14/09
to

Your description of the vtables is as I understand them. I have seen
production system where the vtables grew to 1 MB.

Alf P. Steinbach

unread,
Jul 14, 2009, 12:14:05 PM7/14/09
to
* Blake McBride:

It's easy to abuse any language feature, e.g. via code generation (which might
mean recursive templates).

That doesn't say anything about the language.

It's not a practical problem, rather, the opposite: something so "free" that you
should ordinarily not think about it.

If you think otherwise then someone's misinformed you, and/or you've
misunderstood something basic.

This kind of thing is easy to test, by the way.

ld

unread,
Jul 14, 2009, 12:21:50 PM7/14/09
to

This is probably because:

- class hierarchies are somehow monolithic (large hierarchy)
- class hierarchies abuse of multiple inheritance (of abstract
classes)
- class hierarchies abuse virtual inheritance
- template classes do not share enough generic implementation

Regards,

ld.

Juha Nieminen

unread,
Jul 14, 2009, 2:42:08 PM7/14/09
to
Blake McBride wrote:
> Look, you seem to be hostile to Dynace. Don't use it.

I'm not hostile to Dynace. I'm hostile to your arguments in your
webpage badmouthing C++ for false reasons.

Exactly what do you expect when you come to a C++ group and promote
your own C extension and in your webpage you basically say that "C++
sucks, C rules, and Dynace rules even more"? Your views about C vs. C++
may be shared among prejudiced C hackers, but they are not shared by me
(and many other C++ programmers, I'm sure).

> All languages have trade offs. Dyance solves many
> issues commonly known in the C++ world at the expense of, essentially,
> causing all method calls to be virtual.

And, I assume, forcing each object to be allocated dynamically, making
the creation of objects slower and making them consume more memory.

Imagine you have something like this in C++:

class Pixel
{
unsigned char red, green, blue, alpha;

public:
// public methods here, none of which are virtual
};

Then you do something like this: std::vector<Pixel> image(10000000);
(and maybe initialize with some image data, or whatever).

In C++ that vector will consume about 40 megabytes of memory. How much
would the equivalent code in Dynace consume (using the same level of
abstraction, ie. no cheating by using a C struct as the Pixel type)?

Also, even with virtual methods, I don't see how you can have them as
fast as the ones in C++ given that, if I understood correctly, all
object pointers are completely opaque (as your webpage prominently
advertises, the entire class declaration is in the .c file rather than
in a header file, which would mean that object pointers must be
completely opaque, ie. the compiler does not see the class structure
when it makes a method call using that pointer).

In C++, since the compiler sees the entire class structure, making a
virtual function call is basically reading a function address from a
fixed offset in the virtual table, and jumping to that address. If,
however, the compiler would not see the class structure, it has no way
of knowing from the opaque pointer what this offset might be, without
doing more elaborate operations to resolve it.

ld

unread,
Jul 14, 2009, 3:45:35 PM7/14/09
to
On 14 juil, 20:42, Juha Nieminen <nos...@thanks.invalid> wrote:
>   In C++, since the compiler sees the entire class structure, making a
> virtual function call is basically reading a function address from a
> fixed offset in the virtual table, and jumping to that address. If,
> however, the compiler would not see the class structure, it has no way
> of knowing from the opaque pointer what this offset might be, without
> doing more elaborate operations to resolve it.

But these operations could be as fast as you mentioned, specially on
modern architectures. In fact, as soon as you consider single
inheritance, what you say is true: it's almost impossible to beat C++
virtual call. But in real programs, your concrete classes will derive
from more than one abstract class (interfaces) to ensure better
flexibility, and multiple inheritance requires offsets adjustment
which is mainly sequential even on modern arch:

obj->vtable->fun( obj + obj->vtable->offset )

Moreover, if you use virtual inheritance (as you should for
interfaces), more than one offset adjustment will occur. In the end,
compared to a well designed dispatcher, you will get something running
more or less at the same speed as C++ virtual call (on modern arch).

I did some measurements for COS (C Object System) vs C++ vs Objective-
C. The results are described in the following papers in page 9 for

http://cos.cvs.sourceforge.net/viewvc/cos/doc/cos_draft-dls09.pdf.gz

and in page 14 for

http://cos.cvs.sourceforge.net/viewvc/cos/doc/cos_draft-oopsla09.pdf.gz

The conclusion is that dynamic dispatch (lookup) can be as fast as
late dispatch (vtable) because most of the operations can be
parallelized on modern cpu (thanks to the compiler, no special code is
required). And the special design of COS dispatcher allows it to be
x2-3 faster than the one of Dynace and x1.6 faster than the one of
Objective-C.

Now, all these remarks does not invalidate your other remark about
boxing / unboxing primitive types. It's true that it's more
complicated to implement abstractions like your Pixel class and it
will consume more memory (x3 more for your example in COS, unless you
write an Image class). So in principle, you will have to implement a
higher-level Image class to reach the same efficiency.

To conclude, there is a tradeoff in both approach, since the COS/
Objective-C/Dynace way do not allow efficient low-level abstraction
like your Pixel class, but they do allow (in particular COS) to design
powerful components quite hard (or impossible) to implement in C++.
It's up to the developer to choose the right tools.

a+, ld.

Flash Gordon

unread,
Jul 14, 2009, 3:57:21 PM7/14/09
to
Juha Nieminen wrote:
> Blake McBride wrote:

<snip>

> sucks, C rules, and Dynace rules even more"? Your views about C vs. C++
> may be shared among prejudiced C hackers, but they are not shared by me
> (and many other C++ programmers, I'm sure).

<snip>

Please take your prejudice against C programmers to an advocacy group
somewhere. I doubt that the attitudes and opinions of Blake are any more
representative of C programmers than they are of C++ programmers. In
fact, many of us who program in C program in many other languages as
well, so we are no more C programmers than we are Java, Perl, XSLT or
anything else programmers.
--
Flash Gordon

Victor Bazarov

unread,
Jul 14, 2009, 4:31:24 PM7/14/09
to
Flash Gordon wrote:
> Juha Nieminen wrote:
>> Blake McBride wrote:
>
> <snip>
>
>> sucks, C rules, and Dynace rules even more"? Your views about C vs. C++
>> may be shared among prejudiced C hackers, but they are not shared by me
>> (and many other C++ programmers, I'm sure).
>
> <snip>
>
> Please take your prejudice against C programmers

There is no prejudice against "C programmers" in Juha's comments.
Please don't confuse the expressions "C programmers" and "prejudiced C
hackers".

> to an advocacy group
> somewhere. I doubt that the attitudes and opinions of Blake are any more
> representative of C programmers than they are of C++ programmers. In
> fact, many of us who program in C program in many other languages as
> well, so we are no more C programmers than we are Java, Perl, XSLT or
> anything else programmers.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

BGB / cr88192

unread,
Jul 15, 2009, 1:42:33 AM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:4k47m.94$_02...@read4.inet.fi...

> Blake McBride wrote:
>> Look, you seem to be hostile to Dynace. Don't use it.
>
> I'm not hostile to Dynace. I'm hostile to your arguments in your
> webpage badmouthing C++ for false reasons.
>
> Exactly what do you expect when you come to a C++ group and promote
> your own C extension and in your webpage you basically say that "C++
> sucks, C rules, and Dynace rules even more"? Your views about C vs. C++
> may be shared among prejudiced C hackers, but they are not shared by me
> (and many other C++ programmers, I'm sure).
>

not all C programmers hold these kinds of views.

granted, I have some of my own reasons for not using C++ so much over C, but
performance is not one of them...

a simple explanation (for my case) is that C++ is much more difficult to
"tool" than C, and that the compiler output is very much more complicated
than the equivalent C-compiler output (however, this is inherent with nearly
any attempt to move beyond the core C feature-set).

granted, most devs probably don't care so much about mechanically processing
their source or mucking around at the level of assembler and machine code,
so it is not such a big deal.


>> All languages have trade offs. Dyance solves many
>> issues commonly known in the C++ world at the expense of, essentially,
>> causing all method calls to be virtual.
>
> And, I assume, forcing each object to be allocated dynamically, making
> the creation of objects slower and making them consume more memory.
>
> Imagine you have something like this in C++:
>
> class Pixel
> {
> unsigned char red, green, blue, alpha;
>
> public:
> // public methods here, none of which are virtual
> };
>
> Then you do something like this: std::vector<Pixel> image(10000000);
> (and maybe initialize with some image data, or whatever).
>

partial solution: don't do this...


> In C++ that vector will consume about 40 megabytes of memory. How much
> would the equivalent code in Dynace consume (using the same level of
> abstraction, ie. no cheating by using a C struct as the Pixel type)?
>

can't answer for dynace, but in my framework, on x86, approx 480MB would be
used, and on x86-64, about 640MB (this ignores additional overheads, such as
linear heap inflation, ...).

so, maybe 800MB-1GB?...

there is also a risk (in my case), that doing this would cause the framework
to blow up (yeah...).

thus the answer: don't do this... (or, in my case, at least use "unmanaged
classes" and maybe an option like "__nortti"...).


as for C++:
I would have thought it would have been 80MB or more (or 160MB on x86-64),
unless one were to disable RTTI (allowing the VTable to be omitted)?...


> Also, even with virtual methods, I don't see how you can have them as
> fast as the ones in C++ given that, if I understood correctly, all
> object pointers are completely opaque (as your webpage prominently
> advertises, the entire class declaration is in the .c file rather than
> in a header file, which would mean that object pointers must be
> completely opaque, ie. the compiler does not see the class structure
> when it makes a method call using that pointer).
>
> In C++, since the compiler sees the entire class structure, making a
> virtual function call is basically reading a function address from a
> fixed offset in the virtual table, and jumping to that address. If,
> however, the compiler would not see the class structure, it has no way
> of knowing from the opaque pointer what this offset might be, without
> doing more elaborate operations to resolve it.

granted, yes...

can't say about dynace (I haven't looked into it...).

but, in my case, virtual calls are handle-based, and involve a bunch of
other internal machinery (and overheads), but thus far I have kept it
"tolerable" on benchmarks (could be optimized further later though).

on x86, some stages in the process involve "shortcuts" generally involving
automatically generated thunks.


in my framework, I split classes into 2 major camps:
managed classes;
and unmanaged classes.

managed classes are basically heap-allocated, and behave more or less like
the Java/C# model.
they are also C-accessible via APIs.


unmanaged classes are more or less hacked-over structs, and are a
simplification of the C++ model. as-is, virtual inheritence is not, and
likely may not be, supported (MI is likely to be bad enough already...).

however, they may allow generating faster code, as many of the internal
overheads can be avoided (errm... there are a few...).


likewise for accessing methods via the ASM-level ABI, where a good deal of
the machinery "could" be handled at link-time (granted, as-is, this part of
the ABI mostly just defers to the C-based API).


I may have a C++ frontend (it is "in development", along with my Java and C#
frontends), but very possibly what it would accept would only be a subset.

note that as an "arbitrary" restriction, managed and unmanaged classes may
not inherit from each other, ... (however, both may implement interfaces,
which in my case, would be transparent to the class, as "RTTI" would be used
instead, and the iface calls would be handled similarly to managed iface
calls in my case, AKA, dispatch via a big-ass hash table...).


in any case, interface calls (worst case) are about 1200ns in my case, which
I estimate as somewhere around 2940 clock-cycles on my computer (in my
Win64-based tests, it was faster on x86...).


or such...

fft1976

unread,
Jul 15, 2009, 3:46:47 AM7/15/09
to
On Jul 13, 1:10 pm, Blake McBride <bl...@mcbride.name> wrote:

(...)

But OOP can be done in C. Generic programming on the other hand ...

Good luck using macros for that! It's "possible", but my many
inquiries into whether there is a macros-based STL analog in the C
world turned up nothing.

Miles Bader

unread,
Jul 15, 2009, 6:17:19 AM7/15/09
to
Blake McBride <bl...@mcbride.name> writes:
>> One does get the impression that website was written by marketing...
>
> Dynace, all the code, and all the documentation were done by one person
> - me. No big company.

Hmm, I guess that makes _you_ marketing (amongst other things)... :)

-Miles

--
Faith, n. Belief without evidence in what is told by one who speaks without
knowledge, of things without parallel.

BartC

unread,
Jul 15, 2009, 6:19:49 AM7/15/09
to

"BGB / cr88192" <cr8...@hotmail.com> wrote in message
news:h3jq87$oqj$1...@news.albasani.net...

>
> "Juha Nieminen" <nos...@thanks.invalid> wrote in message
> news:4k47m.94$_02...@read4.inet.fi...

>> Imagine you have something like this in C++:


>>
>> class Pixel
>> {
>> unsigned char red, green, blue, alpha;
>>
>> public:
>> // public methods here, none of which are virtual
>> };
>>
>> Then you do something like this: std::vector<Pixel> image(10000000);
>> (and maybe initialize with some image data, or whatever).
>>
>
> partial solution: don't do this...
>
>> In C++ that vector will consume about 40 megabytes of memory. How much
>> would the equivalent code in Dynace consume (using the same level of
>> abstraction, ie. no cheating by using a C struct as the Pixel type)?
>>
>
> can't answer for dynace, but in my framework, on x86, approx 480MB would
> be used, and on x86-64, about 640MB (this ignores additional overheads,
> such as linear heap inflation, ...).
>
> so, maybe 800MB-1GB?...

I admit I know nothing about vtables and whatever, but why would it be
necessary to store any extra data in each /instance/ of the class?

--
Bart

Juha Nieminen

unread,
Jul 15, 2009, 10:53:50 AM7/15/09
to
BartC wrote:
> I admit I know nothing about vtables and whatever, but why would it be
> necessary to store any extra data in each /instance/ of the class?

The problem with languages like Objective-C (and, I assume, Dynace) is
that every object must be allocated dynamically (with whatever function
the language offers for this purpose, but which is basically completely
equivalent to malloc() + initialization), and consequently each object
has at least one pointer pointing to it.

Allocating an object dynamically always has some space overhead to it
for the simple reason that the memory allocator used by the compiler has
to store some ancillary data on each allocated block of memory. For
example the C-lib memory allocator in Linux (in a 32-bit system)
requires 4-12 bytes of ancillary data per allocated block of memory (the
minimum allocation size is 16 bytes, and everything bigger than that is
aligned to an 8-byte boundary, with the size of the allocated block
being the requested size + 4 bytes).

If the object has a vtable pointer in it (in the cases where the
language needs it), that adds the size of one pointer to the object size
behind the scenes.

In this particular example (ie. the "Pixel" class consisting of 4
bytes) the object itself, when allocated dynamically, would require 16
bytes of memory in a (32-bit) Linux system, plus the pointer used to
handle it. Thus each 'Pixel' object requires 20 bytes of memory. And
this assuming the vtable pointer is not needed. If that is needed by the
language, then each object requires 24 bytes of memory.

In C++, in the optimal case (as the one I gave as example, ie. no
dynamic binding needed, a std::vector<Pixel> as data container), each
object requires only 4 bytes of memory. (And this is so even in 64-bit
systems.)

Of course lesser memory usage is not the only advantage: Allocating 10
million objects dynamically, one at a time, is very expensive, even when
using some optimized memory allocator. C++ classes allow allocating all
the 10 million objects as one single memory block (which is what the
std::vector in the example does), in other words, there is only one
allocation rather than 10 million. This is a HUGE time saver.

Juha Nieminen

unread,
Jul 15, 2009, 10:56:04 AM7/15/09
to
BGB / cr88192 wrote:
> as for C++:
> I would have thought it would have been 80MB or more (or 160MB on x86-64),
> unless one were to disable RTTI (allowing the VTable to be omitted)?...

As I commented in the example, no virtual functions in the 'Pixel'
class. That means that no vtable nor vtable pointer is generated for
that class. Thus instances of that class (when in an array) require only
4 bytes of memory.

I like C++ because it gives you the option of not including RTTI in a
class. In many cases this can be a significant memory saving.

Juha Nieminen

unread,
Jul 15, 2009, 11:06:36 AM7/15/09
to
fft1976 wrote:
> But OOP can be done in C.

I think that's debatable.

You can simulate object-oriented programming in C to an extent, but
since the language has basically no support, it will inevitably be
rather "hacky" and complicated.

The gtk+ library for C is a good example of a C library which
extensively uses OO techniques. However, the resulting code is
necessarily uglier and less efficient than the equivalent C++ code would
be. (For example, when using gtk+, every single pointer cast from one
type to another, even when it's from a derived object type to a base
object type, is done dynamically at runtime, with runtime checks.)

> Generic programming on the other hand ...
>
> Good luck using macros for that! It's "possible", but my many
> inquiries into whether there is a macros-based STL analog in the C
> world turned up nothing.

There are many things doable with templates which are impossible to do
in C with precompiler macros. A very trivial example:

//--------------------------------------------------------------
template<typename T>
void foo(T value)
{
std::cout << "The value is: " << T << std::endl;
}
//--------------------------------------------------------------

A slightly more complicated example:

//--------------------------------------------------------------
template<typename T>
void foo()
{
std::cout << "The specified type is"
<< (std::numeric_limits<T>::is_integer ? "" : " not")
<< " an integral type.\nThe maximum value which can "
<< "be represented by it is: "
<< std::numeric_limit<T>::max() << std::endl;
}
//--------------------------------------------------------------

BartC

unread,
Jul 15, 2009, 11:37:55 AM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:0gm7m.90$w%5....@read4.inet.fi...

> fft1976 wrote:
>> But OOP can be done in C.
>
> I think that's debatable.
>
> You can simulate object-oriented programming in C to an extent, but
> since the language has basically no support, it will inevitably be
> rather "hacky" and complicated.
>
> The gtk+ library for C is a good example of a C library which
> extensively uses OO techniques. However, the resulting code is
> necessarily uglier and less efficient than the equivalent C++ code would
> be. (For example, when using gtk+, every single pointer cast from one
> type to another, even when it's from a derived object type to a base
> object type, is done dynamically at runtime, with runtime checks.)
>
>> Generic programming on the other hand ...
>>
>> Good luck using macros for that! It's "possible", but my many
>> inquiries into whether there is a macros-based STL analog in the C
>> world turned up nothing.
>
> There are many things doable with templates which are impossible to do
> in C with precompiler macros. A very trivial example:
>
> //--------------------------------------------------------------
> template<typename T>
> void foo(T value)
> {
> std::cout << "The value is: " << T << std::endl;
> }

You mean << value << here?

--
bart

ld

unread,
Jul 15, 2009, 12:08:37 PM7/15/09
to
On 15 juil, 16:53, Juha Nieminen <nos...@thanks.invalid> wrote:
>   In this particular example (ie. the "Pixel" class consisting of 4
> bytes) the object itself, when allocated dynamically, would require 16
> bytes of memory in a (32-bit) Linux system, plus the pointer used to
> handle it. Thus each 'Pixel' object requires 20 bytes of memory. And
> this assuming the vtable pointer is not needed. If that is needed by the
> language, then each object requires 24 bytes of memory.

As I mentioned earlier, there is alternatives. In COS, your Pixel
class would take 12 bytes on 32-bit and 64-bit arch and it could use
automatic storage as well. This is even recommended for local objects
with value semantic (like Pixel).

>   Of course lesser memory usage is not the only advantage: Allocating 10
> million objects dynamically, one at a time, is very expensive, even when
> using some optimized memory allocator. C++ classes allow allocating all
> the 10 million objects as one single memory block (which is what the
> std::vector in the example does), in other words, there is only one
> allocation rather than 10 million. This is a HUGE time saver.

Why do you think that alternatives cannot do the same? Or use
automatic objects as you do C++?

a+, ld.

Lorenzo Villari

unread,
Jul 15, 2009, 12:07:38 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> ha scritto nel messaggio
news:0gm7m.90$w%5....@read4.inet.fi...

>
> The gtk+ library for C is a good example of a C library which
> extensively uses OO techniques. However, the resulting code is
> necessarily uglier and less efficient than the equivalent C++ code would
> be. (For example, when using gtk+, every single pointer cast from one
> type to another, even when it's from a derived object type to a base
> object type, is done dynamically at runtime, with runtime checks.)
>

"uglier" is debatable but... what's the problem with casts?


ld

unread,
Jul 15, 2009, 12:18:37 PM7/15/09
to
On 15 juil, 17:06, Juha Nieminen <nos...@thanks.invalid> wrote:
> fft1976 wrote:
> > But OOP can be done in C.
>
>   I think that's debatable.
>
>   You can simulate object-oriented programming in C to an extent, but
> since the language has basically no support, it will inevitably be
> rather "hacky" and complicated.

Wrong.

>   The gtk+ library for C is a good example of a C library which
> extensively uses OO techniques.

This is the worst example I know. Heavy, slow, odd.

> However, the resulting code is
> necessarily uglier and less efficient than the equivalent C++ code would
> be. (For example, when using gtk+, every single pointer cast from one
> type to another, even when it's from a derived object type to a base
> object type, is done dynamically at runtime, with runtime checks.)

This is related to gtk+, not OOP in C.

> > Generic programming on the other hand ...
>
> > Good luck using macros for that! It's "possible", but my many
> > inquiries into whether there is a macros-based STL analog in the C
> > world turned up nothing.
>
>   There are many things doable with templates which are impossible to do
> in C with precompiler macros.

Do you _really_ know what is doable with C macros?

> A very trivial example:
>
> //--------------------------------------------------------------
> template<typename T>
> void foo(T value)
> {
>     std::cout << "The value is: " << T << std::endl;}
>
> //--------------------------------------------------------------
>
>   A slightly more complicated example:
>
> //--------------------------------------------------------------
> template<typename T>
> void foo()
> {
>     std::cout << "The specified type is"
>               << (std::numeric_limits<T>::is_integer ? "" : " not")
>               << " an integral type.\nThe maximum value which can "
>               << "be represented by it is: "
>               << std::numeric_limit<T>::max() << std::endl;}
>
> //--------------------------------------------------------------

Polymorphism can replace template here and hence be done in C. A C++
MTP example would be better to show something not possible in C at
compile time. But this not OOP.

a+, ld.

BGB / cr88192

unread,
Jul 15, 2009, 12:41:14 PM7/15/09
to

"BartC" <ba...@freeuk.com> wrote in message
news:93i7m.56561$OO7....@text.news.virginmedia.com...

most of this overhead would be due to 2 major things:
memory allocation overhead;
object headers.

for example, we can first note that my GC allocates memory in 16-byte
chunks.
secondly, the MM/GC uses an 8 byte header.
thirdly, the C/I-OO system uses another 16-byte header (x86, 32-bytes
x86-64).

basically, the object header holds:
2 pointers: one to the current class, and to the current class-version.
a pointer to the payload;
a pointer to an (optional) auxilary header (used mostly for P-OO features).

it is worth noting that these headers could be reduced some, and the payload
stored inline, but at a likely cost to performance (and, also requiring some
alteration to the current OO machinery).

note that the main reason the payload goes in its own allocation is so that
it can be reallocated as-needed (this being an issue both with dynamic
class-layout modification, as well as with Prototype-OO, which may
dynamically add more slots to an object...). note that the "class-version"
holds both the VTable, as well as the field-offset-table.


so, 8+16=24, which pads to 32-bytes.
my C/I-OO system then uses another allocation for the payload, so there goes
another 16 bytes.

the result is each object taking 48 bytes (which is a crapload bigger when
multiplied with 10000000).

it is worse on x86-64, as each object would take 64 bytes (in the current
MM/GC, its header remains fixed at 8 bytes).


this overhead is much lower (in relation) for objects which are not
trivially small...


> --
> Bart


BGB / cr88192

unread,
Jul 15, 2009, 12:53:49 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:86m7m.89$w%5....@read4.inet.fi...

oh, ok.

I had thought RTTI was on by default... (unless disabled by a command-line
option or otherwise...).

this would mean an object would still contain a vtable pointer, where the
vtable itself would contain a pointer to the RTTI_Info (or whatever it is
called, I forget) structure (this being emmitted by the compiler).

checking online:
oh... it seems RTTI is only used in cases where one also has virtual
methods...


but, yes, no RTTI means smaller object.


my personal preference though is to just not use classes in these cases...

Chris M. Thomasson

unread,
Jul 15, 2009, 11:11:07 AM7/15/09
to
"fft1976" <fft...@gmail.com> wrote in message
news:1f0252c3-4d4b-4715...@b14g2000yqd.googlegroups.com...

On Jul 13, 1:10 pm, Blake McBride <bl...@mcbride.name> wrote:

> (...)

> But OOP can be done in C. Generic programming on the other hand ...

Well, you can definitely create highly minimalist generic interfaces fairly
easily in C:

http://clc.pastebin.com/f52a443b1


> Good luck using macros for that! It's "possible", but my many
> inquiries into whether there is a macros-based STL analog in the C
> world turned up nothing.

Well, you can also do something crazy like:

http://h30097.www3.hp.com/cplus/6026pro_genr.html

http://www.softwarepreservation.org/projects/c_plus_plus/cfront/release_3.0.3/source/incl-master/const-headers/generic.h/view


funny:
______________________________________________________________________
#define CONCAT_RAW(mp_token1, mp_token2) \
mp_token1 ## mp_token2

#define CONCAT(mp_token1, mp_token2) \
CONCAT_RAW(mp_token1, mp_token2)


#define DECLARE_STACK(mp_name, mp_type) \
void CONCAT(mp_name, _stack_push) ( \
mp_type* const self, \
mp_type const node \
);\
mp_type \
CONCAT(mp_name, _stack_pop) ( \
mp_type* const self \
);


#define DEFINE_STACK(mp_name, mp_type, mp_pname) \
void CONCAT(mp_name, _stack_push) ( \
mp_type* const self, \
mp_type const node \
) { \
node->mp_pname = *self; \
*self = node; \
} \
mp_type \
CONCAT(mp_name, _stack_pop) ( \
mp_type* const self \
) { \
mp_type node = *self; \
if (node) *self = node->mp_pname; \
return NULL; \
}


#include <stdlib.h>


DECLARE_STACK(foo, struct foo*)


struct foo {
struct foo* next;
};


DEFINE_STACK(foo, struct foo*, next)


static struct foo* g_stack = NULL;


int main(void) {
foo_stack_push(&g_stack, malloc(sizeof(*g_stack)));
foo_stack_push(&g_stack, malloc(sizeof(*g_stack)));
foo_stack_push(&g_stack, malloc(sizeof(*g_stack)));
foo_stack_push(&g_stack, malloc(sizeof(*g_stack)));
free(foo_stack_pop(&g_stack));
free(foo_stack_pop(&g_stack));
free(foo_stack_pop(&g_stack));
free(foo_stack_pop(&g_stack));
return 0;
}
______________________________________________________________________

Generic type-safe intrusive stack? lol.

BGB / cr88192

unread,
Jul 15, 2009, 1:40:14 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:0gm7m.90$w%5....@read4.inet.fi...

> fft1976 wrote:
>> But OOP can be done in C.
>
> I think that's debatable.
>
> You can simulate object-oriented programming in C to an extent, but
> since the language has basically no support, it will inevitably be
> rather "hacky" and complicated.
>

it depends on how one does it...

"some" options get hacky and complicated...
very often though, things just get terribly verbose...

usually the "hacky and complicated" results from people trying in a
misguided attempt for "maximum performance" and thus implementing their
whole damn object system in terms of nested structs and casting, ...

the other alternative is to force an opaque API, which can largely avoid
much of the horror, but does not have the same air of "maximum performance"
about it (typically because accessing a field typically involves a function
call, a switch, and maybe a few pointer-ops...).

the switch can be eliminated if one is willing to sacrifice features, or
require a separate API function for each type of field.


> The gtk+ library for C is a good example of a C library which
> extensively uses OO techniques. However, the resulting code is
> necessarily uglier and less efficient than the equivalent C++ code would
> be. (For example, when using gtk+, every single pointer cast from one
> type to another, even when it's from a derived object type to a base
> object type, is done dynamically at runtime, with runtime checks.)
>

the GTK+ library is a good example of almost pure horror...

then again, in GPL land there are much worse offenders in the land of "pure
horror"...


as for the common horror and hackiness seen when people attempt things like
this:
often, this is the result of people trying to move directly from an OOPL to
C, and just trying to (directly) force their existing practices onto C,
rather than adapting to a more "C-appropriate" approach to problems...

for example, if we take OO in the more abstract sense (AKA, in the more
'philosophical' sense promoted by 'H.S. Lahman' and friends over in
comp.object), then the problem need not turn into an ugly mess (since, hell,
there is no real reason that OOP should look anything like the approaches we
usually see in OOPL's...).


for example, see the Linux kernel, which would seem to be applying some
amount of 'OOP' as well, but has generally refrained from the obtuse
hackiness of GTK and friends, mostly because problems are abstracted and
modularized, and not because of large amounts of hacky "struct-ninjitsu"...


granted, in general the code-quality in most of open-source land is not
exactly to the highest standards...


>> Generic programming on the other hand ...
>>
>> Good luck using macros for that! It's "possible", but my many
>> inquiries into whether there is a macros-based STL analog in the C
>> world turned up nothing.
>
> There are many things doable with templates which are impossible to do
> in C with precompiler macros.

the bigger issue (in your examples) is not the lack of templates, but the
lack of iostream...

but, on the same token, I can note that there are many things one can do is
LISP macros which are impossible to do with C++ templates... (due to, for
example, LISP macros being turing complete and having full access to the
language...).

as well, although the C-preprocessor is limited, it does not rule out the
possibility of custom preprocessors (but, then one can debate that by the
time such a tool includes certain features, such as a full parser, it is no
longer a preprocessor, rather it is a compiler...).

BartC

unread,
Jul 15, 2009, 1:45:36 PM7/15/09
to

"BGB / cr88192" <cr8...@hotmail.com> wrote in message
news:h3l0r8$jc4$1...@news.albasani.net...

>
> "BartC" <ba...@freeuk.com> wrote in message
> news:93i7m.56561$OO7....@text.news.virginmedia.com...
>>
>> "BGB / cr88192" <cr8...@hotmail.com> wrote in message
>> news:h3jq87$oqj$1...@news.albasani.net...
>>>
>>> "Juha Nieminen" <nos...@thanks.invalid> wrote in message
>>> news:4k47m.94$_02...@read4.inet.fi...

>>>> class Pixel

Ok, so mostly to do with allocation then, rather than vtables and such.

My current project would use 16+16 bytes per item (320million bytes), mainly
because each element would be a variant. I could squeeze that down to 16,
but in practice such an array would just be a linear, homogeneous list of
4-byte pixel types, total size 40million bytes in a single allocated block.
Plus 16 bytes for the variant owner array.

That doesn't stop the pixel type/class having it's own methods, although I
haven't gone too far along the oop route so not sure what other requirements
there might be.

However anything that would inflate a data structure by up to 25x (whoever
mentioned 1GB) without an easy, more efficient alternative would need
serious investigation.

--
Bart

Brian Wood

unread,
Jul 15, 2009, 2:19:30 PM7/15/09
to
On Jul 15, 7:53 am, Juha Nieminen <nos...@thanks.invalid> wrote:
> BartC wrote:
> > I admit I know nothing about vtables and whatever, but why would it be
> > necessary to store any extra data in each /instance/ of the class?
>
>   The problem with languages like Objective-C (and, I assume, Dynace) is
> that every object must be allocated dynamically (with whatever function
> the language offers for this purpose, but which is basically completely
> equivalent to malloc() + initialization), and consequently each object
> has at least one pointer pointing to it.
>

The part about each object having at least one pointer
pointing to it is not correct at least for the way I
use the Boost Intrusive containers. The objects stored
in the containers are deleted by taking their addresses.

I agree with most of the rest of your post and advocate
using vector and deque and the Boost Intrusive
containers rather than list, (multi)set or (multi)map.


Brian Wood
Ebenezer Enterprises
www.webEbenezer.net

Brian Wood

unread,
Jul 15, 2009, 2:31:06 PM7/15/09
to

Me too. And for about the same reason I like the Boost Intrusive
containers as they give the option of not having a data member
that is incremented/decremented every time elements are added or
removed.

Juha Nieminen

unread,
Jul 15, 2009, 2:40:39 PM7/15/09
to
ld wrote:
> Why do you think that alternatives cannot do the same? Or use
> automatic objects as you do C++?

Because alternatives usually want to use a more "pure" object-oriented
paradigm, where *all* objects are always dynamically bound, and thus
*any* reference to an object can also be a reference to any other object
in the same class hierarchy (and with all methods being virtual, of course).

You can't achieve this with value semantics like the ones used so
extensively in C++ because you would end up with, among others, the
problem of slicing.

In other words, since all objects (or, more precisely, all references
to objects, as you don't have the object itself per se, only a reference
to it) are dynamic, you can't have eg. an array of objects, only an
array of references to objects (which themselves are dynamically
allocated, one by one).

Well, it's not like alternatives couldn't do the same. It's just that
in my experience no alternative does. I don't know of any other
programming language supporting objects where they are treated with
value semantics rather than reference semantics.

Juha Nieminen

unread,
Jul 15, 2009, 2:43:50 PM7/15/09
to
Brian Wood wrote:
> The part about each object having at least one pointer
> pointing to it is not correct at least for the way I
> use the Boost Intrusive containers. The objects stored
> in the containers are deleted by taking their addresses.

You need *some* pointer to the object if you want to destroy it. If
you have dropped all pointers to it, then it's an orphan object which
you can't access anymore from anywhere (the only mechanism which can
still access it is a garbage collection engine).

Even if you use an intrusive container, you are using pointers to the
objects, and they naturally take space.

REH

unread,
Jul 15, 2009, 2:56:05 PM7/15/09
to
On Jul 15, 12:53 pm, "BGB / cr88192" <cr88...@hotmail.com> wrote:
> my personal preference though is to just not use classes in these cases...

What would you use instead, a struct? In C++, that is still a class.

REH

Juha Nieminen

unread,
Jul 15, 2009, 2:57:51 PM7/15/09
to
BGB / cr88192 wrote:
> my personal preference though is to just not use classes in these cases...

I'm honestly a bit puzzled by that opinion.

First you learn that RTTI is not mandatory in C++, which makes
instances of the class spacewise optimal (very similar to a struct
containing the same member variables), but then you still say that you
prefer not to use a class in these cases. Why not?

The advantage of a C++ class (with no RTTI) over a C struct is that
you can have a public and a private interface, which increases
abstraction and modularity. You can ever *inherit* from such a class
(and still have no RTTI overhead), which gives some design advantages.

You could achieve almost the same result by using a plain C struct and
a bunch of functions taking instances of it as parameter (as a
substitute for member functions), but in that case you are lessening the
modularity and abstraction of that construct. (C structs also lack other
beneficial properties of C++ classes/structs, such as constructors and
destructors, which make them a lot easier to use eg. in arrays, not to
talk about safety if the struct has eg. pointers to dynamically
allocated memory or such.)

A C++ class, even without RTTI, is a very powerful tool. You could
have, for example, a string class which automatically allocates and
deallocates itself (when it goes out of scope), automatically copies
itself when passed by value (using any of a number of techniques, eg.
the copy-on-write mechanism), checks for access boundaries, etc. All
this without any space overhead from RTTI. Thus the space taken by one
of these string objects can be the same as a char* (which is what you
would usually use in C).

I honestly don't understand why so many C programmers are so
prejudiced against C++. C++ is a wonderful expansion to C.

Juha Nieminen

unread,
Jul 15, 2009, 2:58:28 PM7/15/09
to
Brian Wood wrote:
> Me too. And for about the same reason I like the Boost Intrusive
> containers as they give the option of not having a data member
> that is incremented/decremented every time elements are added or
> removed.

As if one data member was that much of overhead...

Juha Nieminen

unread,
Jul 15, 2009, 2:59:06 PM7/15/09
to
BartC wrote:
>> template<typename T>
>> void foo(T value)
>> {
>> std::cout << "The value is: " << T << std::endl;
>> }
>
> You mean << value << here?

Yes. Braino.

Juha Nieminen

unread,
Jul 15, 2009, 3:04:40 PM7/15/09
to
ld wrote:
>> You can simulate object-oriented programming in C to an extent, but
>> since the language has basically no support, it will inevitably be
>> rather "hacky" and complicated.
>
> Wrong.

I have yet to see a clean solution.

> Do you _really_ know what is doable with C macros?

I'm pretty sure you cannot resolve the proper format string to use
with printf() to print something you got as a macro parameter
(especially if that something is eg. a struct instantiation). I'm also
pretty sure you cannot eg. resolve whether a parameter is of an integral
or a non-integral type.

> But this not OOP.

So?

Juha Nieminen

unread,
Jul 15, 2009, 3:10:26 PM7/15/09
to
BGB / cr88192 wrote:
> but, on the same token, I can note that there are many things one can do is
> LISP macros which are impossible to do with C++ templates... (due to, for
> example, LISP macros being turing complete and having full access to the
> language...).

Btw, AFAIK it has been proven that the C++ template metalanguage is
turing-complete as well... :)

You can do surprising things with template metaprogramming (all at
compile time), such as linked lists (with many operations familiar from
lisp, such as getting the first element and the list tail, etc), binary
trees, resolving whether a given integer is prime or not... I once even
wrote an ascii mandelbrot set generator using template metaprogramming,
which the compiler calculated at compile-time (the resulting program
just printed the resulting string and nothing more).

ld

unread,
Jul 15, 2009, 3:15:20 PM7/15/09
to
On 15 juil, 20:40, Juha Nieminen <nos...@thanks.invalid> wrote:
> ld wrote:
> > Why do you think that alternatives cannot do the same? Or use
> > automatic objects as you do C++?
>
>   Because alternatives usually want to use a more "pure" object-oriented
> paradigm, where *all* objects are always dynamically bound, and thus
> *any* reference to an object can also be a reference to any other object
> in the same class hierarchy (and with all methods being virtual, of course).

right, but this does not prevent value semantic.

>   You can't achieve this with value semantics like the ones used so
> extensively in C++ because you would end up with, among others, the
> problem of slicing.

In many languages, value semantic means also monomorphic type for well
formed classes so slicing is generally not an issue. COS allows more
complex constructions to allow mixing value and polymorphic semantic.

>   In other words, since all objects (or, more precisely, all references
> to objects, as you don't have the object itself per se, only a reference
> to it) are dynamic, you can't have eg. an array of objects, only an
> array of references to objects (which themselves are dynamically
> allocated, one by one).

You can have an array of objects allocated in one chunk as soon as all
objects have the same type.

>   Well, it's not like alternatives couldn't do the same. It's just that
> in my experience no alternative does. I don't know of any other
> programming language supporting objects where they are treated with
> value semantics rather than reference semantics.

COS mixes the two semantic, all objects are dynamically bound, but
those with value semantic can also use automatic storage. In fact,
value semantic is a requirement to have automatic storage in COS
because it does not call automatically the destructor whenever
appropriate.

a+, ld.

BGB / cr88192

unread,
Jul 15, 2009, 3:17:05 PM7/15/09
to

"BartC" <ba...@freeuk.com> wrote in message
news:4Bo7m.56741$OO7....@text.news.virginmedia.com...

this inflation risk is due to how the MM/GC is itself implemented.

there is a constant 6.25% linear overhead for small objects, as well as a
"chunking" overhead (the entire cell-heap is managed in terms of larger 1MB
chunks, each of which has their own headers and management structures, ...).

all of these costs add up...


so, as noted, it IS better to just allocate data of this sort as a single
larger memory object (a single 40MB object), rather than as a huge number of
tiny objects...


> --
> Bart


BGB / cr88192

unread,
Jul 15, 2009, 3:20:39 PM7/15/09
to

"REH" <spam...@stny.rr.com> wrote in message
news:06c1ff36-2f7b-4e11...@h30g2000vbr.googlegroups.com...

in C++ yes...

but, there is another overlooked possibility:
a flat linear array of bytes...

as another has noted:
we can have an "image" class, not a "pixel" class...

Ben Pfaff

unread,
Jul 15, 2009, 3:21:38 PM7/15/09
to
Juha Nieminen <nos...@thanks.invalid> writes:

> You can do surprising things with template metaprogramming (all at
> compile time), such as linked lists (with many operations familiar from
> lisp, such as getting the first element and the list tail, etc), binary
> trees, resolving whether a given integer is prime or not...

I think you've put your finger on the problem with template
metaprogramming: people tend to do surprising things with it.
Programming should not be surprising.
--
Ben Pfaff
http://benpfaff.org

Juha Nieminen

unread,
Jul 15, 2009, 3:24:21 PM7/15/09
to
BGB / cr88192 wrote:
> but, there is another overlooked possibility:
> a flat linear array of bytes...
>
> as another has noted:
> we can have an "image" class, not a "pixel" class...

Then you diminish the reusability of the "pixel" class for other
purposes than a 2D bitmap image.

ld

unread,
Jul 15, 2009, 3:25:22 PM7/15/09
to
On 15 juil, 21:04, Juha Nieminen <nos...@thanks.invalid> wrote:
> ld wrote:
> >>   You can simulate object-oriented programming in C to an extent, but
> >> since the language has basically no support, it will inevitably be
> >> rather "hacky" and complicated.
>
> > Wrong.
>
>   I have yet to see a clean solution.

Did you read the paper I mentioned?

http://cos.cvs.sourceforge.net/viewvc/cos/doc/cos_draft-dls09.pdf.gz

> > Do you _really_ know what is doable with C macros?
>
>   I'm pretty sure you cannot resolve the proper format string to use
> with printf() to print something you got as a macro parameter
> (especially if that something is eg. a struct instantiation). I'm also
> pretty sure you cannot eg. resolve whether a parameter is of an integral
> or a non-integral type.
>
> > But this not OOP.
>
>   So?

this thread is about OOP in/for C in the way of Dynace, not about C++
non-OOP features like generic (generative) programming. I have never
said that C macros can do the same as C++ template. My statement is
that they can do enough to implement clean _OOP_ in C.

a+, ld.

Brian Wood

unread,
Jul 15, 2009, 3:40:08 PM7/15/09
to

Sure, but there is the run time aspect as well. If an
application adds a billion elements to a container and
then goes through them and eliminates all but 200,000
and you don't need to know the size of the container,
that's a lot of incrementing and decrementing that adds
nothing of value to the application. The point is that
if you don't need to know the size, having the option
to not have a member yields a slightly better application.
I use quite a few containers so as they say, "Every little
bit helps."

Juha Nieminen

unread,
Jul 15, 2009, 3:51:48 PM7/15/09
to
Brian Wood wrote:
> Sure, but there is the run time aspect as well. If an
> application adds a billion elements to a container and
> then goes through them and eliminates all but 200,000
> and you don't need to know the size of the container,
> that's a lot of incrementing and decrementing that adds
> nothing of value to the application. The point is that
> if you don't need to know the size, having the option
> to not have a member yields a slightly better application.
> I use quite a few containers so as they say, "Every little
> bit helps."

Have you actually tested it in practice whether that counter makes any
significant difference? There are much heavier operations involved in
creating and destroying objects dynamically than some individual counter
integral.

Juha Nieminen

unread,
Jul 15, 2009, 3:53:24 PM7/15/09
to

I think you are playing with words.

Squeamizh

unread,
Jul 15, 2009, 4:04:09 PM7/15/09
to

That was not your original statement, and you waste everyone's time by
being dishonest.

Here is the original context:
JUHA: There are many things doable with templates which are impossible


to do in C with precompiler macros.

YOU: Do you _really_ know what is doable with C macros?

BGB / cr88192

unread,
Jul 15, 2009, 4:09:08 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:PEp7m.138$w%5....@read4.inet.fi...

> BGB / cr88192 wrote:
>> my personal preference though is to just not use classes in these
>> cases...
>
> I'm honestly a bit puzzled by that opinion.
>
> First you learn that RTTI is not mandatory in C++, which makes
> instances of the class spacewise optimal (very similar to a struct
> containing the same member variables), but then you still say that you
> prefer not to use a class in these cases. Why not?
>

it is also the "concept" of a class.

as we can see, in languages like Java and C#, classes are used purely for
heap-managed behavioral objects (and C# uses 'struct' for linear
pass-by-value objects, whereas Java lacks this concept).

the simple solution then is to not use class in this way, if anything, for
the simple reason of conceptual cleanliness...

similarly, things like pixels, ... are IMO better represented as a single
large flat array anyways, AKA: no classes or 'Vector' template, just a
single big flat glob of memory...


> The advantage of a C++ class (with no RTTI) over a C struct is that
> you can have a public and a private interface, which increases
> abstraction and modularity. You can ever *inherit* from such a class
> (and still have no RTTI overhead), which gives some design advantages.
>

or, in these cases, one can forsake even using a struct, as mentioned above,
which may have other advantages.

for one thing, a "pixel" may not be regarded as a distinct entity in the
first place, and as such, having a unique object for it, may make no real
sense.

for another thing, for many tasks the "linear flat array" approach may allow
a faster implementation (and cleaner code), mostly because the code is not
filled with bunches of individual "per-object" manipulations.

consider one is implementing something like DCT, FFT, or the DWT, does the
"class" offer any real advantage?... how about an LPC-based compressor (for
audio/video)?...

I would say no...

likewise for many types of geometric code, ...

if one writes a 3D modeller or animator, one may suddenly find that dividing
things into discrete objects is not to ones' advantage, even though a
3D-modeled object may "seem" this way. given the wide variety and types of
operations performed, it is generally better to build the model from an
essentially "relational" structure (read, lots of parallel and
interconnected arrays), rather than in an object-based manner.

this greatly simplifies the implementation of operations, such as:
different view modes;
selection; deletion; translate / rotate / scale; surface subdivision;
extrusion; ...

as well as things like weighted matrix transforms / interpolation / ...
drawing the model as it is when weighted according to a set of weighted
bones and a given set of position-matrices.

...

likewise goes for many tasks in real-time physics simulation, ...


there ARE cases where, IMO, where a class or struct is an ill-advised
strategy.

attempting to do these tasks using an object-based strategy is horrible, and
the code comes out scary and absurdly complicated...

even things like scene rendering are not ideal, as with a non-trivial
renderer one may soon find that an object-based approach does not scale well
(as it can lead to combinational complexity issues, ...).

> You could achieve almost the same result by using a plain C struct and
> a bunch of functions taking instances of it as parameter (as a
> substitute for member functions), but in that case you are lessening the
> modularity and abstraction of that construct. (C structs also lack other
> beneficial properties of C++ classes/structs, such as constructors and
> destructors, which make them a lot easier to use eg. in arrays, not to
> talk about safety if the struct has eg. pointers to dynamically
> allocated memory or such.)
>

these are more about design, not so much about language features...

as I see it though, one generally modularizes systems and operations, not
discrete objects...
(AKA: objects may be "synthetic", as in there is no singular in-memory
representation of an object, rather it exists more as a systematic
inference...).


> A C++ class, even without RTTI, is a very powerful tool. You could
> have, for example, a string class which automatically allocates and
> deallocates itself (when it goes out of scope), automatically copies
> itself when passed by value (using any of a number of techniques, eg.
> the copy-on-write mechanism), checks for access boundaries, etc. All
> this without any space overhead from RTTI. Thus the space taken by one
> of these string objects can be the same as a char* (which is what you
> would usually use in C).
>
> I honestly don't understand why so many C programmers are so
> prejudiced against C++. C++ is a wonderful expansion to C.


well, I am not opposing C++ here, rather, I am opposing that what you are
promoting doing with it here actually makes any sense...


but, it is worth noting that I typically don't individually manage strings
either...

the "object" most people regard as a string, in my case, is actually
conceptually split into several different sorts of entity ("string" is then
more a term to describe these sorts of entiries, rather than a singular
concept).

for example:
string as a stream of characters;
string as an atomic/immutable datum;
...

regarding character-streams and atomic datums as distinct, rather than
insisting that both cases be handled via a "string object" actually works a
lot better in getting things done.

similarly, most "string object" implementations tend to like regarding
strings as "pass-by-reference mutable arrays", which is, as I see it, one of
the least useful strategies, vs, say:
atomic value;
character-input stream;
character-output stream.


an "output stream" object could exist, which could then be converted into a
string, which is, as I see it, best regarded as an atomic value...

I guess, LISP-style "symbols" best reflects how I usually regard strings in
this case...

BGB / cr88192

unread,
Jul 15, 2009, 4:30:43 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:F1q7m.163$w%5....@read4.inet.fi...

I say, the "pixel" class does not need to exist in the first place.


for most typical uses of "images", as I see it, it offers no real
advantage...

similarly, how one might use a "pixel" individually, will typically have no
real relation to the image it is contained within (and, in this case,
another representation, such as a float-vector) may make more sense.

for any DSP-type operations, it does not make much sense to operate on
"pixel objects", rather, most operations work on groups of pixels, typically
regarding them as parallel numerical data.


FWIW, typically we don't even need or care about discrete pixel values,
where for many tasks it may be the case that we identify a location on an
image via an ST coord or similar (namely, a floating-point coordinate), and
the value of the "pixel" at this location is synthesized via interpolation
or similar...

likewise goes for audio processing, ...

(all this is particularly true if one is structuring their tasks to be done
via the GPU and the use of shadering...).

Juha Nieminen

unread,
Jul 15, 2009, 4:38:22 PM7/15/09
to
BGB / cr88192 wrote:
> I say, the "pixel" class does not need to exist in the first place.

I don't want to sound rude, but it just sounds to me that you are
basing your design on the limitations of the programming language and
then rationalizing that it's "better" that way.

I disagree with your statement. A "pixel" is a concept, and in OOP a
class is precisely what is used to describe a concept. You usually want
to abstract away the concept of "pixel" (because you don't want to eg.
fix the amount of color channels, bits-per-pixel, color channel
ordering, and so on, and instead you usually want to use an abstract
"pixel" concept where those details are hidden so that the outside code
won't depend on any single representation). There's certainly no harm in
defining a "pixel" as a class (well, not in C++ at least).

Besides, the "pixel" class was just a simple example. I'm sure that
you can think of other similar examples where humongous amounts of small
objects are needed. Things like rational or complex numbers in some
math-heavy application comes to mind as another example.

ld

unread,
Jul 15, 2009, 4:42:16 PM7/15/09
to

Why do you remove 70% of the context? I have myself suggested in this
thread to give more advanced MTP examples to show something not
possible in C and doable with C++ template. Many examples exist like
gcd, factorial or fft compile time computation or (advanced)
dimensional analysis. So my statement is relative to what template
brings to OOP comparing to C macros, not to the all possibilities of C+
+ template. Both have pros and cons and despite that C++ template is
Turing complete, it cannot replace the preprocessor. And AFAIK, the
printf example aforementioned relies on variadic templates which is
not (yet) part of C++.

> JUHA: There are many things doable with templates which are impossible
> to do in C with precompiler macros.

The opposite is also true. Does it bring something? I don't think so.
So I took this statement as part of the discussion.

> YOU: Do you _really_ know what is doable with C macros?

Yes, so what? Most of C/C++ programmer sees the preprocessor as a
primitive tool for string substitution. My remark was just there to
ensure that JUHA does not and see if I need to reevaluate its
position.

If you want to contribute, be positive and less arrogant. No need for
noise here.

a+, ld.


BGB / cr88192

unread,
Jul 15, 2009, 4:46:05 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:CQp7m.155$w%5....@read4.inet.fi...

odd...

well, then again, I have not done a whole lot with templates...

REH

unread,
Jul 15, 2009, 4:49:49 PM7/15/09
to

In this case, I get his point. I've done DSP programming before, and
usually you have specialize libraries of highly-optimized vector math
routines that take advantage of the DSP's special architecture. This
routines usually only operate on arrays, and you almost always need to
speed boost that they give you. In my case, using the vector library
increase the number of signals we could concurrently process by a
factor of 12.

REH

BGB / cr88192

unread,
Jul 15, 2009, 5:08:16 PM7/15/09
to

"Juha Nieminen" <nos...@thanks.invalid> wrote in message
news:27r7m.190$w%5....@read4.inet.fi...

> BGB / cr88192 wrote:
>> I say, the "pixel" class does not need to exist in the first place.
>
> I don't want to sound rude, but it just sounds to me that you are
> basing your design on the limitations of the programming language and
> then rationalizing that it's "better" that way.
>

no, I would do it the same in C++...

and, C has structs, which FWIW would do the same as a class in this case.

a simple reason is this:

Pixel *p;

p->r, p->g, p->b, p->a

ok...

now, what if I want to write a filter which filters the pixels...

if the same filter is to be used on EACH component, I either have to:
A, make the filter be specialized to "pixel" values;
B, use a switch to be able to use an integer to select "which" component I
want;
C, make a specialized copy of the filter loop for each component.

or, using a class, one would potentially need a method for damn near any
kind of per-pixel filtering operation, ...


> I disagree with your statement. A "pixel" is a concept, and in OOP a
> class is precisely what is used to describe a concept. You usually want
> to abstract away the concept of "pixel" (because you don't want to eg.
> fix the amount of color channels, bits-per-pixel, color channel
> ordering, and so on, and instead you usually want to use an abstract
> "pixel" concept where those details are hidden so that the outside code
> won't depend on any single representation). There's certainly no harm in
> defining a "pixel" as a class (well, not in C++ at least).
>

these are properties of the "image", not of individual pixels.
a pixel is simply a value point...

a pixel is, IMO, the wrong level of abstraction on which to use a class...


> Besides, the "pixel" class was just a simple example. I'm sure that
> you can think of other similar examples where humongous amounts of small
> objects are needed. Things like rational or complex numbers in some
> math-heavy application comes to mind as another example.


these don't really need "classes", but yes, they do need "some sort of
atomic unit" (such as a struct, or compiler built-in type).

however, this does not mean they need any of the "extended semantics"
classes offer, since for example, inheriting from a complex, ... makes
little real sense. in effect, associating a complex with a class shows an
issue of C++ (and certain mindsets of OOP), not of anything inherent in the
type itself.


well, I do know of an example:
CONS cells...

these have a bad habit of eating up ones' heap if one is not careful...

and, of the things listed, these might actually make sense as a class...
even then, not really, because the operations are typically external.

more recently, my usual implementation strategy has been to have a custom
heap for CONS cells...

Brian Wood

unread,
Jul 15, 2009, 5:25:48 PM7/15/09
to
On Jul 15, 11:43 am, Juha Nieminen <nos...@thanks.invalid> wrote:
> Brian Wood wrote:
> > The part about each object having at least one pointer
> > pointing to it is not correct at least for the way I
> > use the Boost Intrusive containers.  The objects stored
> > in the containers are deleted by taking their addresses.
>
>   You need *some* pointer to the object if you want to destroy it. If
> you have dropped all pointers to it, then it's an orphan object which
> you can't access anymore from anywhere (the only mechanism which can
> still access it is a garbage collection engine).
>

I'm disagreeing with your statement that "each object
has at least one pointer pointing to it." Initially there
is a pointer pointing to the object, but then that pointer
is reused for another object. The objects are stored in
intrusive containers. So for the most part (except
initially) there aren't any pointers to the object around.
When you're ready to delete the object, you take the
address of it.

>   Even if you use an intrusive container, you are using pointers to the
> objects, and they naturally take space.

Not pointers, but one pointer that points to each of the objects
for a little while.

Juha Nieminen

unread,
Jul 15, 2009, 5:43:08 PM7/15/09
to
Brian Wood wrote:
> I'm disagreeing with your statement that "each object
> has at least one pointer pointing to it." Initially there
> is a pointer pointing to the object, but then that pointer
> is reused for another object. The objects are stored in
> intrusive containers. So for the most part (except
> initially) there aren't any pointers to the object around.
> When you're ready to delete the object, you take the
> address of it.

Exactly how do you take the address of a dynamically allocated object
you don't have a pointer to? Care to show some code?

Rather obviously the intrusive container needs to store a pointer to
the object *somewhere*. It can't just drop the pointer and expect later
to be able to re-retrieve it by magic. That's just impossible.

>> Even if you use an intrusive container, you are using pointers to the
>> objects, and they naturally take space.
>
> Not pointers, but one pointer that points to each of the objects
> for a little while.

As long as the object lives, at least one pointer must point to it. If
no pointer pointed to the object, the object becomes unretrievable and
thus has been leaked (except by some garbage collection mechanism).

Keith Thompson

unread,
Jul 15, 2009, 5:55:53 PM7/15/09
to
Juha Nieminen <nos...@thanks.invalid> writes:
> Brian Wood wrote:
>> I'm disagreeing with your statement that "each object
>> has at least one pointer pointing to it." Initially there
>> is a pointer pointing to the object, but then that pointer
>> is reused for another object. The objects are stored in
>> intrusive containers. So for the most part (except
>> initially) there aren't any pointers to the object around.
>> When you're ready to delete the object, you take the
>> address of it.
>
> Exactly how do you take the address of a dynami