C++ desired features

12 views
Skip to first unread message

Michael Pryhodko

unread,
Jan 4, 2005, 4:35:28 AM1/4/05
to
Hello

I started reading this newsgroup quite recently (~2 month) -- please,
do not upset if something wrong. In my C++ practice I developed some
ideas and tricks I'd like to share and discuss... So I decided to start
with this:

Here is the list of features that comes to my mind whenever someone
mention C++ 'desired features':

1. 'typeof' support -- quite obvious. Does anybody knows if it will be
included in the next C++ standard?

2. fix 'forward declaration problem' for type aliases:
// type alias declaration
typedef foo<int> FooAlias;
...
// forward declaration in another translation unit
class FooAlias; // will not work :(

Since type alias is intended for convenient way to reference real type
it is a shame you can not use it in forward declarations.

3. 'template typedef' -- almost everybody want it :). Here is how it
could be implemented:

// some templates
template<class T> class type {};
template<class T, class U> class ptr {};

// convenient shortcut
templatedef<class T, class U> ptr< T, type<U> > TmplAlias;

Rules are pretty the same as for 'typedef':
- just like typedef does not create new type 'templatedef' does not
create new template -- it is only convenient shortcut to given
'template-name + params' entity.
- it has similar syntax
- templatedef for template functions could be built to look similar to
typedef for usual functions.

I'd like to outline some advantages of this 'templatedef':
a) you can create fine-looking and human-readable complex template
specializations, e.g.:

template<class U> class TmplAlias<U, U> {};
is equivalent to:
template<class U> class ptr<U, type<U> > {};

b) you can change number of template parameters in order to pass
template as template template argument, e.g.:

template<class U, class T> class foo;
template<template<class A> class T> class B;

templatedef<class U> foo< U*, foo2<U> > TmplAlias;
B<TmplAlias> foo_var; // cannot be done without templatedef

c) consequently you can get around that nasty 'default template
parameters' problem, e.g.:

template<template<class A> class T> class B;
template<class T, class U = A> class Foo;

templatedef<class T> Foo<T> Foo_without_def_params;
// now Foo_without_def_params can be used whenever
// template with one parameter required, e.g.:

B<Foo_without_def_params> foo_var;


Well... I suppose this is quite enough for one posting. What do you
think about this?

Bye.
Sincerely yours, Michael.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

ntrif...@hotmail.com

unread,
Jan 4, 2005, 1:20:43 PM1/4/05
to
Take a look at this article:
http://www.artima.com/cppsource/wishlist.html

Francis Glassborow

unread,
Jan 4, 2005, 1:19:03 PM1/4/05
to
In article <1104811678.9...@f14g2000cwb.googlegroups.com>,
Michael Pryhodko <mpry...@westpac.com.au> writes

>Hello
>
>I started reading this newsgroup quite recently (~2 month) -- please,
>do not upset if something wrong. In my C++ practice I developed some
>ideas and tricks I'd like to share and discuss... So I decided to start
>with this:

You need to spend some time looking at what is already being worked on
by those responsible for the future of C++. Try

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/

But be warned that you have a lot of homework to do.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

Victor Bazarov

unread,
Jan 4, 2005, 1:28:04 PM1/4/05
to
Michael Pryhodko wrote:
> Here is the list of features that comes to my mind whenever someone
> mention C++ 'desired features':
>
> 1. 'typeof' support -- quite obvious. Does anybody knows if it will be
> included in the next C++ standard?

See new suggested keyword 'decltype'.

> 2. fix 'forward declaration problem' for type aliases:
> // type alias declaration
> typedef foo<int> FooAlias;
> ...
> // forward declaration in another translation unit
> class FooAlias; // will not work :(
>
> Since type alias is intended for convenient way to reference real type
> it is a shame you can not use it in forward declarations.

Not sure about that.

> 3. 'template typedef' -- almost everybody want it :). Here is how it
> could be implemented:

I think n1489 is the document you want to read.

Visit and browse http://www.open-std.org/jtc1/sc22/wg21/

Victor

Michael Pryhodko

unread,
Jan 6, 2005, 10:32:14 AM1/6/05
to
>> Since type alias is intended for convenient way to reference real
type
>> it is a shame you can not use it in forward declarations.

> Not sure about that.

Why?


> I think n1489 is the document you want to read.

Thanks -- it was helpful. But:
1. I think that:
templatedef<class T> foo<T, U> t_alias;
looks more 'natural' than
template<class T> using t_alias = foo<T, U>;
because it more closely reflects 'typedef' syntax with respect to
templates (IMHO).

2. I disagree that (partial) template specialization using t-aliases
should be banned:
a) it looks natural to me
b) since t-alias is just substitution to more complex t-name it should
not create any problem in any existing template specialization logic
c) I was not convinced by the reasons described in n1489 :))

3. well... that paper introduces extensions to 'using' keyword more
than introducing 'template typedef' :)

Bye.
Sincerely yours, Michael.

Victor Bazarov

unread,
Jan 6, 2005, 2:09:42 PM1/6/05
to
Michael Pryhodko wrote:
>>>Since type alias is intended for convenient way to reference real
>
> type
>
>>>it is a shame you can not use it in forward declarations.
>
>
>>Not sure about that.
>
>
> Why?

Because I don't follow the upcoming changes to the language closely.

I still think you'll find that comp.std.c++ is a better place to discuss
that stuff. And do follow other's advice and study the proposals (and
see the discussions involving them in the archives of comp.std.c++).

V

ka...@gabi-soft.fr

unread,
Jan 11, 2005, 3:54:27 PM1/11/05
to
Michael Pryhodko wrote:

> I started reading this newsgroup quite recently (~2 month) --
> please, do not upset if something wrong. In my C++ practice I
> developed some ideas and tricks I'd like to share and
> discuss... So I decided to start with this:

> Here is the list of features that comes to my mind whenever
> someone mention C++ 'desired features':

I think that many of your features are already under discussion.
But you don't mention the feature that most desire: a compiler
which actually implements the standard. As long as compiler
vendors don't even give us what the current standard requires,
it seems futile to ask for more.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Michael Pryhodko

unread,
Jan 12, 2005, 3:54:39 PM1/12/05
to
> I think that many of your features are already under discussion. But
> you don't mention the feature that most desire: a compiler which
> actually implements the standard.

:) well, VC7.1 so is ok for me in terms of "implementing standard". I
do not need features it does not implement (at least yet :) ). But
things I mentioned is what I REALLY need in my everyday practice -- and
they are missing from standard!


> As long as compiler vendors don't even give us what the current
> standard requires, it seems futile to ask for more.

If we stop demanding from compiler vendor -- sometimes they will
implement averything and C++ evolution will stop. It is just like
multi-stage pipeline with demands on input and compiler on output.
Demand needs to move some "turns" in pipeline, until it ends up as a
feature in the compiler. Stopping providing demands will end up in some
"turns" without any compiler evolution. :))
Bye.
Sincerely yours, Michael.

Alberto Barbati

unread,
Jan 12, 2005, 4:08:42 PM1/12/05
to
Michael Pryhodko wrote:
>
>>I think n1489 is the document you want to read.
>
>
> Thanks -- it was helpful. But:
> 1. I think that:
> templatedef<class T> foo<T, U> t_alias;
> looks more 'natural' than
> template<class T> using t_alias = foo<T, U>;
> because it more closely reflects 'typedef' syntax with respect to
> templates (IMHO).
>
> 2. I disagree that (partial) template specialization using t-aliases
> should be banned:
> a) it looks natural to me
> b) since t-alias is just substitution to more complex t-name it should
> not create any problem in any existing template specialization logic
> c) I was not convinced by the reasons described in n1489 :))
>
> 3. well... that paper introduces extensions to 'using' keyword more
> than introducing 'template typedef' :)
>

All these objections have been made and discussed several times on
comp.std.c++. I suggest you have a good read there.

What you fail to understand (I agree that is not too clear from n1489,
you may also want to read the previous proposal n1449) is that template
aliases and template typedefs are two completely different concepts. A
template is a parametrized family of types, right? Well,
over-simplifying: a template alias is *one* parametrized alias that
refers to a template, while a template typedef is a parametrized
*family* of aliases that refer to types. That explains a lot of things,
in particular:
1) the different choice of keywords ("using" vs. "typedef")
2) why specialization for template aliases is not allowed (you can
specialize a family of things, but you can't specialize one thing)
3) why template aliases works well in deduced contexts while template
typedefs have problems there

Number 3 is the key strenght of the template alias proposal, IMHO. My
impression (I'm not a compiler maker, so I'm just guessing) is that
number 2 makes template aliases much easier to implement than template
typedefs. That's why the C++ community seems more inclined to consider
the template alias proposal.

About which of the two concept "looks more natural", you'll agree that
it's a matter of opinion... ;-)

Alberto

Michael Pryhodko

unread,
Jan 13, 2005, 7:11:31 AM1/13/05
to
> What you fail to understand (I agree that is not too clear from
> n1489, you may also want to read the previous proposal n1449) is that
> template aliases and template typedefs are two completely different
> concepts.

No, I understand that. Unfortunately since I posted 'dried' version of
my thoughts and missed very important entry:
. with proposed templatedef you cannot do like this:
. templatedef<T> foo<T, smth<T> >* const& SmthMixedAndStrange;

My reasong where to 'mirror' 'typedef' behavior to templates world. So
speaking your language I want 'template alias'. I am somewhat surprised
to your reaction since I alway thought that 'typedef' is just a way to
declare 'type alias'. Is there any hidden features in 'typedef' that
makes impossible to mirror its functionality to templates world by
replacing word 'type' with 'template'?


> That explains a lot of things, in particular:
> 1) the different choice of keywords ("using" vs. "typedef")

I will support it with only if you ban 'typedef' keyword (obviously not
good naming) and introduce generic type/template aliasing (for example
like proposed in n1489). But I doubt that because of backward
compatibility. So since 'typedef' will stay, I propose to use similar
looking syntax for template aliases, i.e. 'templatedef' (that means
introducing new reserved keyword, however :( ) instead of introducing
new syntax features in C++.

> 2) why specialization for template aliases is not allowed (you can
> specialize a family of things, but you can't specialize one thing)

Agreed, however that does not forbid *template specialization using
template aliases*. Hmm... I hope you understand me, it looks like
playing with words. I'll try with example:

template<class T, class U> class foo;
templatedef<class T> foo<T, T*> t_name;

template<class T> t_name<T*> { ... };
should be equivalent to:
template<class T> class foo<T*, T**> { ... };

I do not see any problems here, usual rules of template specializations
apply here.


> 3) why template aliases works well in deduced contexts while template
> typedefs have problems there

> Number 3 is the key strenght of the template alias proposal, IMHO. My
> impression (I'm not a compiler maker, so I'm just guessing) is that
> number 2 makes template aliases much easier to implement than
> template typedefs. That's why the C++ community seems more inclined
> to consider the template alias proposal.

Agreed with every word.


> About which of the two concept "looks more natural", you'll agree
> that it's a matter of opinion... ;-)

Certainly! Every word I say (until I am quoting somebody) is my IMHO.
Bye.
Sincerely yours, Michael.

jd

unread,
Jan 13, 2005, 7:18:48 AM1/13/05
to
Le Tue, 04 Jan 2005 04:35:28 -0500, Michael Pryhodko a écrit :

> Hello
>
> I started reading this newsgroup quite recently (~2 month) -- please,
> do not upset if something wrong. In my C++ practice I developed some
> ideas and tricks I'd like to share and discuss... So I decided to start
> with this:
>
> Here is the list of features that comes to my mind whenever someone
> mention C++ 'desired features':

Sorry to came so late on this discussion.

>
> 1. 'typeof' support -- quite obvious. Does anybody knows if it will be
> included in the next C++ standard?

I think C++ should have a similar functionality. But I don't think it
will be easy. Where do you use typeof ?
Just imagine that:

template <class T>
T*
MakeT()
{
return new T;
}

// will the using code looks like:
typeof MakeT<SomeType>& var = *MakeT<SomeType>() ?

It looks quiete rubbish for me. However, I might mis-know how you would
like to realize it and how you think it will be useable. I need more
information about that in order to understand better.

>
> 2. fix 'forward declaration problem' for type aliases:
> // type alias declaration
> typedef foo<int> FooAlias;
> ...
> // forward declaration in another translation unit
> class FooAlias; // will not work :(
>
> Since type alias is intended for convenient way to reference real type
> it is a shame you can not use it in forward declarations.

I, sometimes, have the bad tendency to mis-understand (I'm french), but I
think this is not a problem. If you really want to do that, just use
different name scopes.

Does for you foo<int> can be a new class FooAlias ?

well:

typedef int Int;
class Int
{...};

Huh ? What the compiler is expecting to think about such a code ? What is
the type of Int: int or Int ?

To my logic, this is simply a bad idea.

>
> 3. 'template typedef' -- almost everybody want it :). Here is how it
> could be implemented:
>
> // some templates
> template<class T> class type {};
> template<class T, class U> class ptr {};
>
> // convenient shortcut
> templatedef<class T, class U> ptr< T, type<U> > TmplAlias;

Should we be able to do such code ?

TmpAlias<int,long> tmpalias_instance;

to produce this concrete type : ptr<int, type<long> ?

C++ already offers such possibilities directly threw templates,
but as you mentioned it creates new types.

ka...@gabi-soft.fr

unread,
Jan 13, 2005, 5:00:01 PM1/13/05
to
Michael Pryhodko wrote:
> > I think that many of your features are already under
> > discussion. But you don't mention the feature that most
> > desire: a compiler which actually implements the standard.

> :) well, VC7.1 so is ok for me in terms of "implementing
> standard".

It's missing at least one major feature, export. Possibly
others, like template templates -- I don't know exactly.

> I do not need features it does not implement (at least yet :)
> ).

Maybe, but that's not the point, the point is...

> But things I mentioned is what I REALLY need in my everyday
> practice -- and they are missing from standard!

What does getting them into the standard buy you, if the
compiler vendors don't bother implementing what's in the
standard ? (That's what I meant by "futile" in the following
sentence.)

> > As long as compiler vendors don't even give us what the
> > current standard requires, it seems futile to ask for more.

> If we stop demanding from compiler vendor -- sometimes they
> will implement averything and C++ evolution will stop. It is
> just like multi-stage pipeline with demands on input and
> compiler on output. Demand needs to move some "turns" in
> pipeline, until it ends up as a feature in the
> compiler. Stopping providing demands will end up in some
> "turns" without any compiler evolution. :))

Except maybe for improved optimization and less errors:-). Time
compiler implementers spend in implementing new features is time
they don't spend in improving quality.

But that really wasn't my point -- there is an equilibrium which
has to be found, and we should be able to get both quality and
at least some new features. My point was rather that getting
something adopted in the standard doesn't seem to be a sure
fired way of getting compilers which implement it. Unless
something can be done to "push" compiler vendors to full
conformance (and not just implementing the features they feel
like), adding features to the standard is just adding words to a
paper that no one adhers to.

I'm actually in favor of a number of the proposed features
(garbage collection, threads, "lambda", dynamic linking...).
But unless compiler vendors actually implement them, putting
them into the standard doesn't buy me anything. And the respect
the current standard has gotten doesn't bide well for the
future.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Michael Pryhodko

unread,
Jan 13, 2005, 6:47:35 PM1/13/05
to
> Where do you use typeof ?

Mostly in generic code. There was a big discussions about this feature
all the time, I believe. This feature is VERY handy here.


> typedef int Int;
> class Int {...};
>
> Huh ? What the compiler is expecting to think about such a code ?
> What is the type of Int: int or Int ?

Hmm... I do not completely understand your idea. But I'll try to giuess
and answer:
I want to declare incomplete type using name of any his 'alias' (i.e.
name created by typedef). It seems rather convent to me and should not
put any unbearable burden on compiler vendor. (on the other hand I may
be missing something)


> Should we be able to do such code ?
>
> TmpAlias<int,long> tmpalias_instance;
> to produce this concrete type : ptr<int, type<long> ?

Right.


> C++ already offers such possibilities directly threw templates, but
> as you mentioned it creates new types.

Hmm... let me demonstrate:

template<template<class T> > class Cont;
template<class T, class U> class Elem;

Could you pass 'Elem' as a template parameter to 'Cont' using today's
C++? You can not, you need to do rather ugly 'rebinding', wich is pain
in the neck when things bump into 'undeduced context' problem. With
'templatedef' it is easy:

templatedef<class T> Elem<T, T> t_alias;
Cont<t_alias> v;

Here is another example:
template<template<class T, class U> > class Cont;
template<class T> class Elem;

you need to increase template parameters count:
templatedef<class T, class U> Elem<T> t_alias;
Cont<t_alias> v;


Bye.
Sincerely oyurs, Michael.

Michael Pryhodko

unread,
Jan 13, 2005, 6:53:46 PM1/13/05
to
> I'm actually in favor of a number of the proposed features (garbage
collection, threads, "lambda", dynamic linking...). But unless compiler
vendors actually implement them, putting them into the standard doesn't
buy me anything. And the respect the current standard has gotten
doesn't bide well for the future.

1. About features -- I'd like to express my opinion (in order to
influence ever-changing equilibrium). Everything I say here is my IMHO:

garbage collection -- ultimate testament of average developer's
inability(disability :) ); pushing it into standard is just a sign that
people gave up idea to teach 'average developer' to develop. It could
be fine addition to standard library, but changing language... I am
really against it. What is really annoying me that GC does not solve
ANYTHING -- memory is just only one of the resources used by
application.

threads -- only as library extension. C++ was designed from the ground
ignoring this issue. And since there is no common model for
multithreading -- it is very dangerous to enforce any to underlying
platform.

lambda -- quite interesting idea, but not without flaws.

2. Pushing anything into standard DO buy smth for you: without it
compiler vendors will not implement that feature for sure.
We are going 'off topic'...

Bye.
Sincerely yours, Michael.

ka...@gabi-soft.fr

unread,
Jan 14, 2005, 11:12:13 PM1/14/05
to
Michael Pryhodko wrote:
> > I'm actually in favor of a number of the proposed features
> > (garbage collection, threads, "lambda", dynamic
> > linking...). But unless compiler vendors actually implement
> > them, putting them into the standard doesn't buy me
> > anything. And the respect the current standard has gotten
> > doesn't bide well for the future.

> 1. About features -- I'd like to express my opinion (in order
> to influence ever-changing equilibrium). Everything I say here
> is my IMHO:

> garbage collection -- ultimate testament of average
> developer's inability(disability :) ); pushing it into
> standard is just a sign that people gave up idea to teach
> 'average developer' to develop. It could be fine addition to
> standard library, but changing language... I am really against
> it. What is really annoying me that GC does not solve ANYTHING
> -- memory is just only one of the resources used by
> application.

That's sort of true. In the same way that using a high-level
language instead of assembler is a testament of the average
programmers inability.

In fact, it's not really a question of ability or not -- IMHO,
if your development process is incapable of producing correct
code without garbage collection, then it will be incapable of
producing it with. The only difference is one of cost -- it's
usually cheaper if the machine or the system does it, rather
than the programmers, provided the machine or the system can do
it correctly (where correctly, of course, also means meeting any
response time constraints on the application). The time garbage
collection saves me is time available to improve other parts of
the program.

And of course, need a few small tweaks of the language for
garbage collection to be possible.

> threads -- only as library extension. C++ was designed from
> the ground ignoring this issue. And since there is no common
> model for multithreading -- it is very dangerous to enforce
> any to underlying platform.

Threading is simply impossible at the library level. The major
issues aren't library issues, but questions concerning memory
visibility and sequencing.

> lambda -- quite interesting idea, but not without flaws.

Nothings without flaws.

> 2. Pushing anything into standard DO buy smth for you: without
> it compiler vendors will not implement that feature for sure.
> We are going 'off topic'...

It depends. About half of the features I use in any given
program are not part of the C++ standard. The compiler vendors
provided them anyway.

My impression today is that the compiler vendors pretty much
pick and choose what they want to implement. All of them
implement a lot more than that standard. But very few of them
implement all of the standard.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Herb Sutter

unread,
Jan 16, 2005, 6:20:48 AM1/16/05
to
On 14 Jan 2005 23:12:13 -0500, ka...@gabi-soft.fr wrote:

>Michael Pryhodko wrote:
>> garbage collection -- ultimate testament of average
>> developer's inability(disability :) ); pushing it into
>> standard is just a sign that people gave up idea to teach
>> 'average developer' to develop. It could be fine addition to
>> standard library, but changing language... I am really against
>> it. What is really annoying me that GC does not solve ANYTHING
>> -- memory is just only one of the resources used by
>> application.
>
>That's sort of true. In the same way that using a high-level
>language instead of assembler is a testament of the average
>programmers inability.

It's sort of true in that memory is just one resource, but it is a very
special resource. Specifically, GC is essential (or nearly so) for:

a) guaranteeing type safety and memory safety (because you have to
guarantee that the memory that held an object stays around for as long as
there are any pointers to it, even if the object has already been
destroyed); and

b) lock-free programming (see Andrei Alexandrescu's recent articles and
talks; you can do it yourself without GC but it's like working with knives
that are sharp on both edges and don't have handles).

It's true that many programmers misuse GC as a crutch. It's also true that
GC is technically compelling (or essential) as a fundamental building
block for a still-growing list of reasons.


>> threads -- only as library extension. C++ was designed from
>> the ground ignoring this issue. And since there is no common
>> model for multithreading -- it is very dangerous to enforce
>> any to underlying platform.
>
>Threading is simply impossible at the library level. The major
>issues aren't library issues, but questions concerning memory
>visibility and sequencing.

James' first part is exactly right; threading can't be done purely as a
library, period. (That includes pthreads.)

When it comes to language guarantees you need to have, the usual suspects
include guarantees about the memory model, (re)ordering of operations (by
the compiler's optimizer, the system cache manager, the processor core
itself, or any other level), atomicity, and semantics for shared objects.
I'd be inclined to also throw in a couple of guarantees about the
scheduler (e.g., FIFO unblocking, fairness) just to avoid some
pathological starvation cases and confusing execution orderings.

But in fact there's more: Not only does threading require basic language
support to be possible to do correctly at all, but we need also need
still-to-be-designed higher-level language abstractions for concurrency
that we don't yet have in any language on any platform. Lock-based
programming is our status quo and it ain't enough; as semaphores are to
assembler, locks are to C (they're just as low-level and probably more
dangerous), and we need an "OO" level of abstraction for concurrency.
There's work like Ada95 and Comega that begin raising the abstraction
level, but we need more. I'm writing further about this problem (but not
any solution) this weekend as one part of my March CUJ column. Deadlines,
love 'em and hate 'em...


>> lambda -- quite interesting idea, but not without flaws.
>
>Nothings without flaws.

Something that has surprised me is that the more completely separate
language design problems I work on, the more lambdas/closures turn out to
be a key language abstraction that adds substantial elegance and power.
Boost Lambda is a great approximation, but even if it were perfect (and
unfortunately it's not although it's very impressive) you really need this
to be in the language, not just to get reasonable diagnostics and
debugger/tool support, but because some features and semantics that turn
out to be desirable are impossible to achieve exactly the way you want
them to be if lambdas are a library-only solution. I'll have more to say
about this over the coming year or two; it's an interesting area.

Herb

---
Herb Sutter (www.gotw.ca) (www.pluralsight.com/blogs/hsutter)

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)

Michael Pryhodko

unread,
Jan 17, 2005, 4:05:55 AM1/17/05
to
> It's sort of true in that memory is just one resource, but it is a
> very special resource.

Only special thing about memory is the binding between object lifetime
and its memory. And this is a pain for containers, since they need to
handle memory separately to be reasonably efficient. And as a side
effect there is no 'move' semantic support in C++ (which is containers
pain also).


> Specifically, GC is essential (or nearly so) for:
>
> a) guaranteeing type safety and memory safety (because you have to
> guarantee that the memory that held an object stays around for as
> long as there are any pointers to it, even if the object has
> already been destroyed); and

why? I do not see any point for it. If object is already destroyed, who
needs that memory? (let's not touch case when container itself handles
memory) -- this sentence looks like misspoken to me.
And I do not see how GC guarantees type safety?


> b) lock-free programming (see Andrei Alexandrescu's recent articles
> and talks; you can do it yourself without GC but it's like working
> with knives that are sharp on both edges and don't have handles).

Hmm... didn't read it yet. Can't say anything. Looks impossible to me,
since we will always have a LOCK :) prefix (on x86). And what about
others achitectures where processors caches are not synchronized?


> It's true that many programmers misuse GC as a crutch. It's also
> true that GC is technically compelling (or essential) as a
> fundamental building block for a still-growing list of reasons.

I am not sure about its "fundamentality". Indeed it is handy for RAD,
but if you need RAD -- just use C# or Java, since they were designed
with this in mind. GC alone solves so little, that it is unworthy
(imho) to complicate language with it.


>> Threading is simply impossible at the library level. The major
>> issues aren't library issues, but questions concerning memory
>> visibility and sequencing.

> James' first part is exactly right; threading can't be done purely
> as a library, period. (That includes pthreads.)

I need to read proposal before arguing with you here.
Bye.
Sincerely yours, Michael.

Michael Pryhodko

unread,
Jan 17, 2005, 4:07:20 AM1/17/05
to
> That's sort of true. In the same way that using a high-level language
instead of assembler is a testament of the average programmers
inability.

No, it is not. There are too many reasons why this sentence is wrong.
Most obvious is platform independence. Basically every 'language level'
is an 'abstraction layer' for developer. GC in C++ is just a 'plug this
damn hole' thing.


> The only difference is one of cost -- it's usually cheaper if the
machine or the system does it, rather than the programmers, provided
the machine or the system can do it correctly (where correctly, of
course, also means meeting any response time constraints on the
application).

You must be joking :). Maybe it is cheaper in terms of dollars spent on
project? And I doubt it as well -- if your development group in order
to produce reliable enough product needs GC you will pay twice in later
product support and extension.
In my experience good approach (e.g. usage of smart pointers and local
objects) was always enough to handle leaks. And by the way -- C++
classes + stack unwinding was designed for the purpose of seamless
semi-automatic resource handling!


> And of course, need a few small tweaks of the language for garbage
collection to be possible.

Yeah-yeah.... And will make it more complicated. Thus making C++
developers a bit more expensive. :))


> Threading is simply impossible at the library level. The major issues
aren't library issues, but questions concerning memory visibility and
sequencing.

Hmm... I am on slippery ground here, since I never used MT on other
than x86 platforms. But:
1. It IS implemented for x86 (VC + Boost.Treads works for me along with
some guarantees provided by compiler)
2. Could you:
a) tell me about these issues or
b) direct me to corresponding resources about this problem (I will
read corresponding Alexandrescu's proposal, it is just a matter of
precious time :) )

Bye.
Sincerely yours, Michael.


Ioannis Vranos

unread,
Jan 18, 2005, 6:00:47 PM1/18/05
to
Herb Sutter wrote:

> But in fact there's more: Not only does threading require basic language
> support to be possible to do correctly at all, but we need also need
> still-to-be-designed higher-level language abstractions for concurrency
> that we don't yet have in any language on any platform. Lock-based
> programming is our status quo and it ain't enough; as semaphores are to
> assembler, locks are to C (they're just as low-level and probably more
> dangerous), and we need an "OO" level of abstraction for concurrency.
> There's work like Ada95 and Comega that begin raising the abstraction
> level, but we need more. I'm writing further about this problem (but not
> any solution) this weekend as one part of my March CUJ column. Deadlines,
> love 'em and hate 'em...


I think what we really need for concurrency so as to take advantage of
multicore processors in straight-forward applications (that is our usual
applications that have no reason to have concurrent design), is a safe
language level support in the style of OpenMP (which as far as I know is
not safe in the sense that it is "hard-coded" and does not throw
exceptions in case of errors for example).


Perhaps the "safe part", should be additional compiler checks on such
multithreading declarations.


--
Ioannis Vranos

http://www23.brinkster.com/noicys

Tom Widmer

unread,
Jan 18, 2005, 6:01:53 PM1/18/05
to

Michael Pryhodko wrote:
> > What you fail to understand (I agree that is not too clear from
> > n1489, you may also want to read the previous proposal n1449) is
that
> > template aliases and template typedefs are two completely different
> > concepts.
>
> No, I understand that. Unfortunately since I posted 'dried' version
of
> my thoughts and missed very important entry:
> . with proposed templatedef you cannot do like this:
> . templatedef<T> foo<T, smth<T> >* const& SmthMixedAndStrange;
>
> My reasong where to 'mirror' 'typedef' behavior to templates world.
So
> speaking your language I want 'template alias'. I am somewhat
surprised
> to your reaction since I alway thought that 'typedef' is just a way
to
> declare 'type alias'. Is there any hidden features in 'typedef' that
> makes impossible to mirror its functionality to templates world by
> replacing word 'type' with 'template'?

template syntax wasn't all that well thought out originally IMHO.
template<class T>
class A;
doesn't declare a class at all, which is slightly problematic to
understanding the concept. Similarly, extending ordinary typedef syntax
with templates wouldn't be a typedef. e.g.
template <class T>
typedef std::vector<T> Vec;

Your suggested templatedef at least doesn't suffer from the same
problem as class templates, but it isn't uniform either. The extension
of the "using" keyword to replace both typedef and templatedef seems
like quite a nice idea to me, since it distances us slightly from the
horrible old C declaration syntax.

> > That explains a lot of things, in particular:
> > 1) the different choice of keywords ("using" vs. "typedef")
>
> I will support it with only if you ban 'typedef' keyword (obviously
not
> good naming) and introduce generic type/template aliasing (for
example
> like proposed in n1489). But I doubt that because of backward
> compatibility.

typedef can't be banned; ideally we want to maintain or even improve C
compatibility. However, it could be demoted (but not deprecated) to
being a compatibility syntax that shouldn't be used in new code.

So since 'typedef' will stay, I propose to use similar
> looking syntax for template aliases, i.e. 'templatedef' (that means
> introducing new reserved keyword, however :( ) instead of introducing
> new syntax features in C++.

If you want a similar looking syntax, what's wrong with:

template <class T>
typedef std::vector<T> Vec;
?

>
> > 2) why specialization for template aliases is not allowed (you can
> > specialize a family of things, but you can't specialize one thing)
>
> Agreed, however that does not forbid *template specialization using
> template aliases*. Hmm... I hope you understand me, it looks like
> playing with words. I'll try with example:
>
> template<class T, class U> class foo;
> templatedef<class T> foo<T, T*> t_name;
>
> template<class T> t_name<T*> { ... };
> should be equivalent to:
> template<class T> class foo<T*, T**> { ... };
>
> I do not see any problems here, usual rules of template
specializations
> apply here.

Is it necessary though? Seems like an unnecessary addition to me,
unless you can come up with a reasonable use case where you can't use
the original template directly? It seems like a recipe for duplicate
specializations to me...

The ability to have the "typedef" point to different classes for
different T's is definitely useful, but we can already do that with a
traits class combined with the original proposal.

A key feature for me is that the template aliases must behave exactly
like a template of the parameters in question. e.g.

template <class T>
using myvec = std::vector<T>;

template <template<class> TT>
class Tester;

Tester<std::vector> - illegal since vector has 2 args
Tester<myvec> - hopefully legal, since myvec has only 1 arg

I haven't seen this issue mentioned in the proposal, but currently
template templates are restrictive because of the above problem.

Tom

Ioannis Vranos

unread,
Jan 18, 2005, 6:08:29 PM1/18/05
to
Herb Sutter wrote:

> But in fact there's more: Not only does threading require basic language
> support to be possible to do correctly at all, but we need also need
> still-to-be-designed higher-level language abstractions for concurrency
> that we don't yet have in any language on any platform. Lock-based
> programming is our status quo and it ain't enough; as semaphores are to
> assembler, locks are to C (they're just as low-level and probably more
> dangerous), and we need an "OO" level of abstraction for concurrency.
> There's work like Ada95 and Comega that begin raising the abstraction
> level, but we need more. I'm writing further about this problem (but not
> any solution) this weekend as one part of my March CUJ column. Deadlines,
> love 'em and hate 'em...

I think what we really need for concurrency so as to take advantage of
multicore processors in straight-forward applications (that is our usual
applications that have no reason to have concurrent design), is a safe
language level support in the style of OpenMP (which as far as I know is
not safe in the sense that it is "hard-coded" and does not throw
exceptions in case of errors for example).


Perhaps the "safe part", should be additional compiler checks on such
multithreading declarations.


--
Ioannis Vranos

http://www23.brinkster.com/noicys

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

ka...@gabi-soft.fr

unread,
Jan 18, 2005, 6:05:01 PM1/18/05
to
Michael Pryhodko wrote:
> > That's sort of true. In the same way that using a high-level
> > language instead of assembler is a testament of the average
> > programmers inability.

> No, it is not. There are too many reasons why this sentence is
> wrong.

Such as...

> Most obvious is platform independence.

I don't write platform independant code as is. I know that my
code will run on a Sun Sparc, under Solaris. And only on a Sun
Sparc, under Solaris.

I still don't use assembler (although I know Sparc assembler).

> Basically every 'language level' is an 'abstraction layer' for
> developer. GC in C++ is just a 'plug this damn hole' thing.

GC is an abstraction.

> > The only difference is one of cost -- it's usually cheaper
> > if the machine or the system does it, rather than the
> > programmers, provided the machine or the system can do it
> > correctly (where correctly, of course, also means meeting
> > any response time constraints on the application).

> You must be joking :). Maybe it is cheaper in terms of dollars
> spent on project? And I doubt it as well -- if your
> development group in order to produce reliable enough product
> needs GC you will pay twice in later product support and
> extension.

Could you point out some studies which back this up, or is it
just a figment of your imagination. All of the studies I've
seen suggest that GC reduces cost. Including maintenance
costs. (Actually, especially maintenance costs. It's actually
pretty easy to manage memory correctly in a new design. It's a
lot more difficult to ensure that later modifications don't
break anything.)

> In my experience good approach (e.g. usage of smart pointers
> and local objects) was always enough to handle leaks. And by
> the way -- C++ classes + stack unwinding was designed for the
> purpose of seamless semi-automatic resource handling!

C++ stack unwinding was designed to unwind the stack. Resource
handling is but a minor aspect. And of course, as you
doubtlessly know, no one smart pointer works everywhere. As
resources go, memory is a bit particular, because it can involve
cyclic dependancies. (It's also a bit particular because it is
a basic part of the machine, and not something "external".)

> > And of course, need a few small tweaks of the language for
> garbage collection to be possible.

> Yeah-yeah.... And will make it more complicated. Thus making
> C++ developers a bit more expensive. :))

Again, could you give some evidence of what you are talking
about? How would the language tweeks necessary for garbage
collection make the language more complicated.

> > Threading is simply impossible at the library level. The
> > major issues aren't library issues, but questions concerning
> > memory visibility and sequencing.

> Hmm... I am on slippery ground here, since I never used MT on
> other than x86 platforms. But:

> 1. It IS implemented for x86 (VC + Boost.Treads works for me
> along with some guarantees provided by compiler)

Precisely. Along with some guarantees provided by the
compiler. I use pthreads regularly; Posix makes a number of
requirements concerning visibility for a compiler to be Posix
compliant.

> 2. Could you:
> a) tell me about these issues or
> b) direct me to corresponding resources about this problem (I
> will read corresponding Alexandrescu's proposal, it is just a
> matter of precious time :) )

The issues are fairly complicated, and not easily explained in a
single posting. There have been threads concerning them here in
the past, but I suppose that working paper N1680
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf)
is as good a place to start as any.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Michael Pryhodko

unread,
Jan 19, 2005, 6:57:52 PM1/19/05
to
> template syntax wasn't all that well thought out originally IMHO.
> template<class T>
> class A;
> doesn't declare a class at all, which is slightly problematic to
> understanding the concept.

Well, I think in another way:

template<class T> // declaration of parametrized 'entity' that after
// substitution of its parameters will
result in *type* wich will look like:
class A { ... };

It is evident (IMHO) that main purpose of templates is to create TYPES
(well... and functions :) ) This is one of the reasons why I do not
like this:

1. template<class T> typedef ...; // this will not create type after
instantiation

also:

2. 'templatedef' syntax is shorter
3. 'templatedef' does not reads 'declaration of parametrized 'entity'
.... '. It is a new keyword and nobody has any assumptions regarding
it. It clearly states 'this is declaration of template name alias'.
4. 'templatedef' synatx will make thing like that:
template<class T> typedef A<T, T*>* const& B;

to look ugly/unnatural:
templatedef<class T> A<T, T*>* const& B;
(IMHO).

5. something telling me that 'templatedef' is easier to implement for
compiler vendor.


> Similarly, extending ordinary typedef syntax with templates wouldn't
> be a typedef. e.g.
> template <class T>
> typedef std::vector<T> Vec;

It will be typedef after instantiation (according to my approach of
understanding 'template' keyword). And I do not like it since I need
template name alias useable as template template parameter.


> Your suggested templatedef at least doesn't suffer from the same
> problem as class templates, but it isn't uniform either.

You want me to critique my child? ;)


> The extension of the "using" keyword to replace both typedef and
> templatedef seems like quite a nice idea to me, since it distances
> us slightly from the horrible old C declaration syntax.

Agreed 100%. After reading n1489 second time I found that I really like
uniform approach for name aliases proposed here. My first intention
with 'templatedef' was to create something very close to typedef since
everyone accustomized to it already.


> If you want a similar looking syntax, what's wrong with:
> template <class T> typedef std::vector<T> Vec; ?

See point above.


About specializations using template name aliases. I find this logical.
I understand this could create problems, but it looks natural to me,
and should not provide any problems to compiler vendors. I call it
'futher template specialization' :)


Bye.
Sincerely yours, Michael.


Herb Sutter

unread,
Jan 20, 2005, 6:26:16 PM1/20/05
to
On 17 Jan 2005 04:07:20 -0500, "Michael Pryhodko"

<mpry...@westpac.com.au> wrote:
>> Threading is simply impossible at the library level. The major issues
>>aren't library issues, but questions concerning memory visibility and
>>sequencing.
>
>Hmm... I am on slippery ground here, since I never used MT on other
>than x86 platforms. But:
>1. It IS implemented for x86 (VC + Boost.Treads works for me along with
>some guarantees provided by compiler)
>2. Could you:
>a) tell me about these issues or
>b) direct me to corresponding resources about this problem (I will
>read corresponding Alexandrescu's proposal, it is just a matter of
>precious time :) )

Here is a readable overview (displaying Hans' usual excellent clarity that
makes his papers a joy to read):

Hans Boehm. "Threads Cannot Be Implemented as a Library"
http://www.hpl.hp.com/techreports/2004/HPL-2004-209.html

Herb

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Michael Pryhodko

unread,
Jan 21, 2005, 5:23:10 AM1/21/05
to
I studied current publications and papers regarding the subjects we
discuss. Because topics are big and somewhat complicated I decided to
answer with one post for each topic. This one is about GC in C++.

I do not like GC in C++, because of:

========================================
Reason #1: It does not help to manage resources properly

Memory is not only resource available to application. Suppose you have
a class that "wraps" HANDLE (i.e. handle to some underlying system
resource). When you "lose" object of this class it will take a
considerable time before GC reclaims object and calls corresponding
destruction function which will in turn release system resource.
a) Deterministic destruction of local GC objects will not help -- you
cannot put every such object to local storage.
b) Introducing "special" Dispose() function:
b1) ugly as it could be. C# clearly demonstrated this with its
"using" keyword and countless try/catch clauses introduced only to call
Dispose for local objects and propagate exception further
b2) defies the whole purpose of C++ destructors
b3) what will you do if you derive a class B (which also handles some
system resources) from this class? Call A::Dispose() from B::Dispose()?
This defies fundamental feature of C++, i.e. coupling subobject's
constructors/destructors into one atomic-looking function


========================================
Reason #2: Leads to unnecessary high demands from underlying system

It is clear that increasing system resources possibilities (e.g. number
of simultaneously open handles) could solve the problem produced by
delayed objects destruction. For example Windows2000 allows something
around ~15k handles which is much more than in NT4. But increasing
application size and complexity could increases time of GC session,
thus increasing "resource release" delay and thus increasing demands
for open handles (I am not sure if these demands will be linear of
application complexity).
This effect pushes industry in "expansive way", forcing users to do
upgrades (both software and hardware) more often that necessary. I do
not like it.
Also -- "resource" is not only "system resource". Resources could be:
a) transaction
b) some action that should be done later
etc.

It is easy to think about such "resource" which provided with "resource
release delaying" will introduce exponential demands. That means you
need to use 'Dispose()' and 'using' thus defying C++ elegancy.


========================================
Reason #3: No one likes 30Mb memory footprint in quite simple program

Clearly with the progress of GC technology it would be better and
better, but anyway GC has cost and cost is big!


========================================
Reason #4: RT applications

GC is inappropriate for 99% of real-time sensitive applications. Thus
introducing GC into C++ will divide library vendors into two camps --
those who use GC and cannot be used by RT application and those who
does not.


========================================
Reason #5: Changing language syntax is one way road

GC could be implemented in more than one way. Changing language syntax
and dictated behaviour to satisfy current GC design could prevent
future introduction of "better" GC (or not GC) memory handling
mechanism


========================================
Reason #6: Giving developer one more reason to be not careful

I will risk repeating myself -- memory is not the only resource! It is
somewhat unique in the way that object's lifetime and memory bound
together (usually). Considerable amount of bugs I found in C# code (not
mine) was connected to missing 'Dispose()' calls, just because
developer "relaxed" too much with GC under him. :)


========================================
Reason #7: Unordered destruction

Could be a problem. Leads to 'Dispose()' introduction.


========================================
Reason #8: Political reasons

I am risking myself to be hanged right here... Everything here is my
IMHO after all:
a) MS is pushing its GC (which is mostly complete) design into C++ ->
MS will be the first one to implement C++ compiler with GC feature
b) Like in case of IE company plans to catch majority of users with
"cool features" and I fear that history will repeat itself but this
time with C++
c) As a platform vendor MS never will pursue platform independency ->
with b) this could drive majority of development into Windows domain

Herb, I really appreciate your efforts you made for C++ -- do not take
"political reasons" personally, please. :)


********************************************
And one more thing -- preparing this posting I was searching through
google and found that I have "made my way" into Herb's weblog. I am
really impressed and somewhat flattened, but:

> Michael's third not-in-my-language feature was:


>> lambda -- quite interesting idea, but not without flaws.

This is wrong; the whole idea behind that posting was to express my
opinion about certain popular features which are being pushed into C++.
With this sentence I meant exactly what I said, i.e. interesting idea +
has some flaws. I am not against putting that feature into C++, but
fear that flaws could make it impossible technically.


********************************************
Now, answering your statements:

> Specifically, GC is essential (or nearly so) for:
> a) guaranteeing type safety and memory safety

not convincing. C++ provides model with good enough type and memory
safety -- I do not see how GC could improve it.


> b) lock-free programming (see Andrei Alexandrescu's recent articles
> and talks; you can do it yourself without GC but it's like working
> with knives that are sharp on both edges and don't have handles).

I read "Lock-Free Data Structures" article. I do not understand how GC
will help here? It will help only if "read pointer and register new
root in GC" is an atomic operation (Is it? If yes -- how?). In steps:
1. thread read value
2. thread is interrupted for very long time
3. artificial map changes its data pointer
4. GC finds no root and disposes of object
5. thread awakes and (hopefully) fails to register new root in GC

Where I am wrong?

About this problem in general --- could be solved with MROW lock
(multiple readers one writer). Easily implemented as lock-free on x86
as a spinlock with highest bit is 'for writer'. (LOCK bts/btr). Like
any spinlock suitable for limited number of participants 2^31 in this
case.


> It's also true that GC is technically compelling (or essential) as a
> fundamental building block for a still-growing list of reasons.

I disagree. Main reason behind GC is to automate half of memory
management, which itself is a result of:
a) Low general C++ developer professional level
b) C++ complexity
c) Absence of common resource management approach in most development
companies

It turned out that introduction of GC has some neat features, indeed:
a) Each object has thread-safe reference-counted semantic
b) Automatic resolution of cycle dependencies (which is not a problem
until you introduce ref-counting :)) )
c) Memory allocation/deallocation seems very fast (if you calculate:
sum(allocation_time) + sum(deallocation_time) +
sum(garbage_collection_time)

over long period of time, I am sure it will be more that

sum(allocation_time) + sum(deallocation_time)

for application without GC (especially if application uses advanced
allocation technique, e.g. lock-free allocation)
)
d) Automatically improving locality of references by compacting storage
(indeed a good feature wich could only be half-beaten by careful design
of corresponding GC-free application)
e) Reduced development costs (unfortunately yes, from my experience 99%
of software is written bad. At first user uses it because there is no
alternative, and after -- because he is sticked to its bugs and
migration is just too costly. I am myself currently supporting 14-years
system which was developed by people who knows very little about
multithreading and many other things -- it a real pain in the #@@ to
make it work, I am sure that company payed many times more for support
than for development -- simply just because someone long ago decided to
cut down development costs)

Anyway -- I can not call GC as "essential fundamental building block".
It will become this after introduction to C++, but I will not be happy.
:)


Bye.
Sincerely yours, Michael.


Michael Pryhodko

unread,
Jan 21, 2005, 5:21:06 AM1/21/05
to
>> Basically every 'language level' is an 'abstraction layer'
>> for developer. GC in C++ is just a 'plug this damn hole' thing.
>
>GC is an abstraction.

This arguing is pointless, lets stop it :). When I think about GC I
always remember main reason of its invention.


>> You must be joking :). Maybe it is cheaper in terms of dollars spent
>> on project? And I doubt it as well -- if your development group in
>> order to produce reliable enough product needs GC you will pay
>> twice in later product support and extension.
>
> Could you point out some studies which back this up, or is it just a
> figment of your imagination. All of the studies I've seen suggest
> that GC reduces cost. Including maintenance costs. (Actually,
> especially maintenance costs. It's actually pretty easy to manage
> memory correctly in a new design. It's a lot more difficult to
> ensure that later modifications don't break anything.)

No, it is figment of my imagination. However I will say some resons:
a) GC will make "participation in complex designs" is more easy for
inexperienced(or simply saying bad) developers
b) as result companies in general will start to hire less competent
developers
c) since programming are MUCH more than just memory handling this will
result in increasing later support and maintenance costs

I clearly understand that small group of highly experienced developers
will do very well without GC and even better with it, but overall
picture will become darker (imho, as usual). However GC leads to some
complications which may remove it from "good tool" list for those
highly experienced developers, especially giving that they should not
have any problems managing memory. :)
And by the way -- imho, it is easy to manage memory correctly at any
time provided that everyone involved has know that given project memory
management approach and follows it.


>> And by the way -- C++ classes + stack unwinding was designed for
>> the purpose of seamless semi-automatic resource handling!
>
> C++ stack unwinding was designed to unwind the stack. Resource
> handling is but a minor aspect.

Hmm... let me explain my point of view:
what is a class? Simply speaking it is a bitset value + associated with
it resources, which are handled by its member functions (such as
constructor and destructor). In these terms "classes + unwinding" is a
major aspect.


> And of course, as you doubtlessly know, no one smart pointer works
> everywhere. As resources go, memory is a bit particular, because it
> can involve cyclic dependancies.

Which is impossible to create if you do not use smart pointers :). I
agree that GC elegantly solves 'cyclic dependency'. However, I think
that this is a problem in application architecture and should be solved
on another level.


> (It's also a bit particular because it is a basic part of the
> machine, and not something "external".)

Well... I was thinking about some things for last 3 years, it seem I
need to make them available to public. I hope they will change your
opinion, in any case you'll get an opportunity to look on these issues
from my angle. :)


>>> And of course, need a few small tweaks of the language for garbage
>>> collection to be possible.
>> Yeah-yeah.... And will make it more complicated. Thus making C++
>> developers a bit more expensive. :))
>
> Again, could you give some evidence of what you are talking about?
> How would the language tweeks necessary for garbage collection make
> the language more complicated.

Yes, any feature introduction that touches already existing ones
complicate language. I call it complication multiplication :)). I.e. if
we have two features and want to introduce third wich intersects with
those two -- it will make things more complicated. For example:
introducing '%' as pointer to GC object will lead to a lot of
construction:
1. T%* -- is it ok?
2. T& r = *(T%) -- is it ok?

and so on. Basically adding another axis of freedom increases number of
possibilities which leads to further complication.

James, do not take my statements personally; please, understand that
since I am not native speaker I can accidentally create, well,
embarassing sentences. It is not intentional.
You could read my answer to Herb about GC and participate in discussion
if you find that topic interesting. Meanwhile I need to familiarize
myself with current MT stuff :)

Bye.
Sincerely yours, Michael.


Ioannis Vranos

unread,
Jan 22, 2005, 12:06:33 AM1/22/05
to
Michael Pryhodko wrote:

> I studied current publications and papers regarding the subjects we
> discuss. Because topics are big and somewhat complicated I decided to
> answer with one post for each topic. This one is about GC in C++.


Having C++/CLI in mind:


> I do not like GC in C++, because of:
>
> ========================================
> Reason #1: It does not help to manage resources properly
>
> Memory is not only resource available to application. Suppose you have
> a class that "wraps" HANDLE (i.e. handle to some underlying system
> resource). When you "lose" object of this class it will take a
> considerable time before GC reclaims object and calls corresponding
> destruction function which will in turn release system resource.
> a) Deterministic destruction of local GC objects will not help -- you
> cannot put every such object to local storage.


C++/CLI is about "stack semantics", the real object is still in the
managed heap. Dispose() is automatically compiler generated by the
destructor (destructor is Dispose).


> b) Introducing "special" Dispose() function:
> b1) ugly as it could be. C# clearly demonstrated this with its
> "using" keyword and countless try/catch clauses introduced only to call
> Dispose for local objects and propagate exception further
> b2) defies the whole purpose of C++ destructors
> b3) what will you do if you derive a class B (which also handles some
> system resources) from this class? Call A::Dispose() from B::Dispose()?


Yes implicitly. The compiler produces automatically the Dispose()
function, including chaining calls to Dispose().


> This defies fundamental feature of C++, i.e. coupling subobject's
> constructors/destructors into one atomic-looking function
>
>
> ========================================
> Reason #2: Leads to unnecessary high demands from underlying system
>
> It is clear that increasing system resources possibilities (e.g. number
> of simultaneously open handles) could solve the problem produced by
> delayed objects destruction. For example Windows2000 allows something
> around ~15k handles which is much more than in NT4. But increasing
> application size and complexity could increases time of GC session,
> thus increasing "resource release" delay and thus increasing demands
> for open handles (I am not sure if these demands will be linear of
> application complexity).


Not if one uses deterministic destruction, the recommended way in C++/CLI.


> This effect pushes industry in "expansive way", forcing users to do
> upgrades (both software and hardware) more often that necessary. I do
> not like it.
> Also -- "resource" is not only "system resource". Resources could be:
> a) transaction
> b) some action that should be done later
> etc.
>
> It is easy to think about such "resource" which provided with "resource
> release delaying" will introduce exponential demands. That means you
> need to use 'Dispose()' and 'using' thus defying C++ elegancy.
>
>
> ========================================
> Reason #3: No one likes 30Mb memory footprint in quite simple program
>
> Clearly with the progress of GC technology it would be better and
> better, but anyway GC has cost and cost is big!


Well in general, C++ provides the choice not using GC if you can not
afford it.

C++/CLI will also provide the ability to create objects of managed types
in the unmanaged heap, objects of unmanaged types in the managed heap,
derived managed types from unmanaged, derive unmanaged from managed etc
(although I am not sure I can understand all of these). As far as I know
these will be supported by the VC++ release after the 2005 release.


Under C++/CLI, C++ is essentially two worlds, the managed and the
unmanaged and the choice which one will use, is yours.


There are some other things that I have concerns about though,
preserving C++ semantics.


The default access of interface class is public and not private, default
inheritance of ref classes is public etc, and I have strong objections
on these non-C++ semantics.


--
Ioannis Vranos

http://www23.brinkster.com/noicys

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

ka...@gabi-soft.fr

unread,
Jan 22, 2005, 12:09:45 AM1/22/05
to
Michael Pryhodko wrote:
> >> Basically every 'language level' is an 'abstraction layer'
> >> for developer. GC in C++ is just a 'plug this damn hole'
> >> thing.

> >GC is an abstraction.

> This arguing is pointless, lets stop it :). When I think about
> GC I always remember main reason of its invention.

Which is? (I always thought that it was because Lisp required
it.)

> >> You must be joking :). Maybe it is cheaper in terms of
> >> dollars spent on project? And I doubt it as well -- if your
> >> development group in order to produce reliable enough
> >> product needs GC you will pay twice in later product
> >> support and extension.

> > Could you point out some studies which back this up, or is
> > it just a figment of your imagination. All of the studies
> > I've seen suggest that GC reduces cost. Including
> > maintenance costs. (Actually, especially maintenance
> > costs. It's actually pretty easy to manage memory correctly
> > in a new design. It's a lot more difficult to ensure that
> > later modifications don't break anything.)

> No, it is figment of my imagination. However I will say some
> resons:
> a) GC will make "participation in complex designs" is more
> easy for inexperienced(or simply saying bad) developers
> b) as result companies in general will start to hire less
> competent developers
> c) since programming are MUCH more than just memory handling
> this will result in increasing later support and maintenance
> costs

Well, Cobol sort of had that effect. It looked sort of like
English, so managers did suppose that just anyone could do it.
But from what I can see, that sort of thing doesn't seem to be
too much of a problem no adays, or if it is, it doesn't work at
the level we're considering. (At higher level language and tool
levels, it is still sometimes a consideration. But generally,
only when someone has a financial interest to make it so -- buy
my product, and you can reduce programmer cost.)

A company that wants to use incompetent people on a project
because they are cheaper will do so. GC or no. And in the end,
companies that don't know what they are doing will write bad
software, and companies that do know what they are doing will
write good software. At that level, GC doesn't enter into the
equation.

What it does mean is that the competent people you have can do
more work, and be involved in more areas of the program, which
should improve quality.

> I clearly understand that small group of highly experienced
> developers will do very well without GC and even better with
> it, but overall picture will become darker (imho, as usual).
> However GC leads to some complications which may remove it
> from "good tool" list for those highly experienced developers,
> especially giving that they should not have any problems
> managing memory. :)

It's not necessarily a problem, but it is work. If a machine
can do it better, well, it's not like there is nothing else to
take up my time.

> And by the way -- imho, it is easy to manage memory correctly
> at any time provided that everyone involved has know that
> given project memory management approach and follows it.

In theory, everything necessary for writing good software is
easy. Good documentation is easy. Good communication between
programmers is easy. Still...

But we're talking about the necessity of designing and writing
code, then documenting it and communicating the underlying
principles, against letting the machine take care of
everything. Easy work (maybe) vs. no work (at the programming
level -- GC does not mean that you can skip on design).

> >> And by the way -- C++ classes + stack unwinding was
> >> designed for the purpose of seamless semi-automatic
> >> resource handling!

> > C++ stack unwinding was designed to unwind the
> > stack. Resource handling is but a minor aspect.

> Hmm... let me explain my point of view: what is a class?
> Simply speaking it is a bitset value + associated with it
> resources, which are handled by its member functions (such as
> constructor and destructor). In these terms "classes +
> unwinding" is a major aspect.

The fact that C++ calls destructors of local variables when the
variables go out of scope is an important aspect of C++.
Independantly of resource handling.

> > And of course, as you doubtlessly know, no one smart pointer
> > works everywhere. As resources go, memory is a bit
> > particular, because it can involve cyclic dependancies.

> Which is impossible to create if you do not use smart pointers
> :).

I'm not sure that I understand what you are trying to say here.
Cycles in memory references are a fact of life -- they're even
the basis of some very basic structures, like a double linked
list. In practice, you can't get away from them.

> I agree that GC elegantly solves 'cyclic dependency'.
> However, I think that this is a problem in application
> architecture and should be solved on another level.

Sometimes, you need more than garbage collection provides.
Sometimes you don't. At the design level, at least at the high
level design level, I think that the influence of garbage
collection is minimal; it's a programming tool, not a design
tool.

> > (It's also a bit particular because it is a basic part of
> > the machine, and not something "external".)

> Well... I was thinking about some things for last 3 years, it
> seem I need to make them available to public. I hope they will
> change your opinion, in any case you'll get an opportunity to
> look on these issues from my angle. :)

> >>> And of course, need a few small tweaks of the language for
> >>> garbage collection to be possible. Yeah-yeah.... And will
> >>> make it more complicated. Thus making C++ developers a bit
> >>> more expensive. :))

> > Again, could you give some evidence of what you are talking
> > about? How would the language tweeks necessary for garbage
> > collection make the language more complicated.

> Yes, any feature introduction that touches already existing
> ones complicate language. I call it complication
> multiplication :)). I.e. if we have two features and want to
> introduce third wich intersects with those two -- it will make
> things more complicated. For example: introducing '%' as
> pointer to GC object will lead to a lot of construction:

> 1. T%* -- is it ok?
> 2. T& r = *(T%) -- is it ok?

I agree that garbage collection can be done wrong. I certainly
don't see whether something is garbage collected or not as part
of the type system. I'm very sceptical as to the need of
anything special beyond a different new operator (for the
allocation of garbage collected memory). In fact, I'm not even
sure that that would be necessary.

> and so on. Basically adding another axis of freedom increases
> number of possibilities which leads to further complication.

> James, do not take my statements personally;

I didn't. I do think that that your original statements were
expressed rather dogmatically, without much backing argument.

> please, understand that since I am not native speaker I can
> accidentally create, well, embarassing sentences. It is not
> intentional.

I recognize this. For that matter, it happens even with native
speakers.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

ka...@gabi-soft.fr

unread,
Jan 22, 2005, 12:37:07 AM1/22/05
to
Michael Pryhodko wrote:
> I studied current publications and papers regarding the
> subjects we discuss. Because topics are big and somewhat
> complicated I decided to answer with one post for each
> topic. This one is about GC in C++.

> I do not like GC in C++, because of:

> ========================================
> Reason #1: It does not help to manage resources properly

> Memory is not only resource available to application.

So. And managing resources isn't the only thing necessary to do
right for a program to work. Garbage collection is a tool
designed to solve one very particular (but important) problem.
It solves that problem. It doesn't solve other problems.

I don't refuse to use a car because it won't get me from Paris
to New York.

> Suppose you have a class that "wraps" HANDLE (i.e. handle to
> some underlying system resource). When you "lose" object of
> this class it will take a considerable time before GC reclaims
> object and calls corresponding destruction function which will
> in turn release system resource.

Why do you want to loose an object of this class? If you loose
it without garbage collection, it is truely lost. If you losse
it with garbage collection, you can eventually signal the error
in the finalizer, if you decide to do so.

> a) Deterministic destruction of local GC objects will not help
> -- you cannot put every such object to local storage.

Local objects shouldn't be garbage collected.

> b) Introducing "special" Dispose() function:
> b1) ugly as it could be.

So call it clean-up. Or better still, call it ~ClassName. And
use a special syntax to call it, say delete ptr.

If you need deterministic clean-up, then waiting for garbage
collection to do it is obviously an error. If you need anything
deterministic, unless it follows scoping rules very rigorously,
you reall want some explicit indication of it being invoked.

I think you're looking at the problem backwards. The current
problem is that I am obliged to use deterministic cleanup even
when it is not the appropriate solution, because there is
nothing else.

> C# clearly demonstrated this with its "using" keyword and
> countless try/catch clauses introduced only to call Dispose
> for local objects and propagate exception further

> b2) defies the whole purpose of C++ destructors

I'm not too sure what you mean by "defies" in this context. The
purpose of C++ destructors is to provide deterministic cleanup.
Regretfully, we're also required to use them for memory
management, since we don't have any alternative.

> b3) what will you do if you derive a class B (which also
> handles some system resources) from this class? Call
> A::Dispose() from B::Dispose()? This defies fundamental
> feature of C++, i.e. coupling subobject's
> constructors/destructors into one atomic-looking function

Why do you want to change the way destructors work in C++?
There's nothing in the proposals I've seen for garbage
collection to even suggest that this should be done.

Adding garbage collection to C++ does not replace (and remove)
any present functionality. It offers an additional
functionality, for the cases where it is appropriate.

Have you read any of the actual proposals? Or the older ones?
Have you experimented with existing garbage collectors?

> ========================================
> Reason #2: Leads to unnecessary high demands from underlying
> system

> It is clear that increasing system resources possibilities
> (e.g. number of simultaneously open handles) could solve the
> problem produced by delayed objects destruction. For example
> Windows2000 allows something around ~15k handles which is much
> more than in NT4. But increasing application size and
> complexity could increases time of GC session, thus increasing
> "resource release" delay and thus increasing demands for open
> handles (I am not sure if these demands will be linear of
> application complexity).

What is the relationship between garbage collection and the
number of open file handles? I don't see one.

> This effect pushes industry in "expansive way", forcing users
> to do upgrades (both software and hardware) more often that
> necessary. I do not like it.
> Also -- "resource" is not only "system resource". Resources could be:
> a) transaction
> b) some action that should be done later
> etc.

> It is easy to think about such "resource" which provided with
> "resource release delaying" will introduce exponential
> demands. That means you need to use 'Dispose()' and 'using'
> thus defying C++ elegancy.

> ========================================
> Reason #3: No one likes 30Mb memory footprint in quite simple
> program

> Clearly with the progress of GC technology it would be better
> and better, but anyway GC has cost and cost is big!

This is probably the one real point you've made so far.
Typically, programs using garbage collection will have a bigger
memory footprint than those using manual memory management.
It's the classic time/space trade-off -- they run faster, but
require more space to do so.

> ========================================
> Reason #4: RT applications

> GC is inappropriate for 99% of real-time sensitive
> applications.

If you are talking about hard real time, all dynamic memory
allocation is inappropriate. If you are talking simply about
response times, garbage collection typically does better than
manual management.

There also exist real-time garbage collection implementations,
with guaranteed hard response times. (I don't know of anything
equivalent for malloc/free, but it would be possible. Using the
same techniques the real-time garbage collectors use.)

> Thus introducing GC into C++ will divide library vendors into
> two camps -- those who use GC and cannot be used by RT
> application and those who does not.

Again: if you're talking about hard real-time, most operating
systems don't support it. If you're talking about soft
real-time, garbage collection typically does better than
malloc/free.

> ========================================
> Reason #5: Changing language syntax is one way road

> GC could be implemented in more than one way. Changing
> language syntax and dictated behaviour to satisfy current GC
> design could prevent future introduction of "better" GC (or
> not GC) memory handling mechanism

The same thing could be said about any feature. Including
malloc/free.

> ========================================
> Reason #6: Giving developer one more reason to be not careful

> I will risk repeating myself -- memory is not the only
> resource! It is somewhat unique in the way that object's
> lifetime and memory bound together (usually). Considerable
> amount of bugs I found in C# code (not mine) was connected to
> missing 'Dispose()' calls, just because developer "relaxed"
> too much with GC under him. :)

C++ is one more reason not to be careful. Let's go back to
assembler.

> ========================================
> Reason #7: Unordered destruction

> Could be a problem. Leads to 'Dispose()' introduction.

I don't know where you got this idea that garbage collection has
any effect on destruction. Destruction works exactly like it
always has, garbage collection or not.

> ========================================
> Reason #8: Political reasons

> I am risking myself to be hanged right here... Everything here
> is my IMHO after all:

> a) MS is pushing its GC (which is mostly complete) design into
> C++ -> MS will be the first one to implement C++ compiler with
> GC feature

Actually, the first "push" came from Detlefs and Ellis
(http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-102.html).
Or maybe even before that. (That was 1993. Microsoft was still
a newcomer in the C++ arena. The copyright on the paper is
Digital Equipment and Xerox.)

> b) Like in case of IE company plans to catch majority of users
> with "cool features" and I fear that history will repeat
> itself but this time with C++

> c) As a platform vendor MS never will pursue platform
> independency -> with b) this could drive majority of
> development into Windows domain

> Herb, I really appreciate your efforts you made for C++ -- do
> not take "political reasons" personally, please. :)

Herb is actually a latecomer amongst the proponents of garbage
collection. The idea has been around for a long time.

[...]


> > It's also true that GC is technically compelling (or
> > essential) as a fundamental building block for a
> > still-growing list of reasons.

> I disagree. Main reason behind GC is to automate half of
> memory management, which itself is a result of:
> a) Low general C++ developer professional level

What's unprofessional about letting the machine do things it can
do better than you? I already use a compiler, rather than
compiling by hand.

(And why half: garbage collection automates all of the memory
management. You seem to be confounding memory management with a
lot of other unrelated issues, like the lifetime of objects.)

> b) C++ complexity

Or rather, application complexity. Which means that I have
enough things to worry about as is, without artificially adding
to the list.

> c) Absence of common resource management approach in most
> development companies

??? Don't understand this one.

> It turned out that introduction of GC has some neat features,
> indeed:
> a) Each object has thread-safe reference-counted semantic
> b) Automatic resolution of cycle dependencies (which is not a
> problem until you introduce ref-counting :)) )
> c) Memory allocation/deallocation seems very fast (if you
> calculate: sum(allocation_time) + sum(deallocation_time) +
> sum(garbage_collection_time)

> over long period of time, I am sure it will be more that

> sum(allocation_time) + sum(deallocation_time)

> for application without GC (especially if application uses
> advanced allocation technique, e.g. lock-free allocation)

Have you actually measured this? All of the benchmarks I've
seen contradict it.

> d) Automatically improving locality of references by
> compacting storage (indeed a good feature wich could only be
> half-beaten by careful design

A good feature which probably cannot be used in C++:-).

> of corresponding GC-free application)
> e) Reduced development costs (unfortunately yes, from my
> experience 99% of software is written bad. At first user uses
> it because there is no alternative, and after -- because he is
> sticked to its bugs and migration is just too costly.

> I am myself currently supporting 14-years system which was
> developed by people who knows very little about multithreading
> and many other things -- it a real pain in the #@@ to make it
> work, I am sure that company payed many times more for support
> than for development -- simply just because someone long ago
> decided to cut down development costs)

That's regretfully a frequent situation for most of us.
Technology advances, and that includes software engineering
technology. And applications written years ago don't use modern
technology; I'd sure complain about having to maintain code
using <generic.h>, rather than templates, but 15 years ago, it
was all we had. And of course, what was considered acceptable
has evolved as well; when I started in the profession, it was
frequent to not indent code at all, something that will get you
fired in just about any company today.

But what does all this have to do with garbage collection?
Unless to say that garbage collection is another of those
techniques.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Herb Sutter

unread,
Jan 22, 2005, 6:32:42 AM1/22/05
to
On 21 Jan 2005 05:21:06 -0500, "Michael Pryhodko"

<mpry...@westpac.com.au> wrote:
>>> Basically every 'language level' is an 'abstraction layer'
>>> for developer. GC in C++ is just a 'plug this damn hole' thing.
>>
>>GC is an abstraction.
>
>This arguing is pointless, lets stop it :). When I think about GC I
>always remember main reason of its invention.

What do you see as the main reason for its invention, and approximately
what year and language do you have in mind?

Herb

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Herb Sutter

unread,
Jan 22, 2005, 6:32:20 AM1/22/05
to
On 21 Jan 2005 05:23:10 -0500, "Michael Pryhodko"
<mpry...@westpac.com.au> wrote:
[...]

I agree with some of those points. Others are generalizations that are
only true of some GC approaches/systems, and that aren't true (at least
not as strongly as written) for all modern forms of GC. The
overgeneralizations don't acknowledge the variations among GC strategies
and actual range of implementations now in use.


>Now, answering your statements:
>
>> Specifically, GC is essential (or nearly so) for:
>> a) guaranteeing type safety and memory safety
>
>not convincing. C++ provides model with good enough type and memory
>safety -- I do not see how GC could improve it.

Then you need to do more research. Type safety is pretty boolean -- you
either have it or you don't. A basic requirement of type safety is to able
to guarantee that every pointer to a T object actually points to a T
object. It's nonobvious how to completely accomplish that without some
form GC (note that ref counting is one of the three forms of GC).
Simplistically, if you don't null out all pointers to the object, you
can't do a normal delete that also deallocates the memory (that would
violate the type safety constraint, as well as memory safety because you'd
have pointers to freed memory); but for each object to track all the
pointers to it so it can null them out is prohibitively expensive. That's
the basic sketch; there are other alternatives that also aren't practical
(for example to do stuff like keep a hash table of deleted pointes and
always check that first on pointer derefs but that's expensive too).

In my opinion Java and .NET are actually not quite type-safe in this
regard, but they are gradually closing the holes before construction and
after Dispose/destruction. In Java 5 they're mostly closing the leading
edge window (getting a reference to an object before it's fully
constructed) but since those platforms conflate object lifetime with
memory lifetime and have no system-supported concept of a destructor (only
a Dispose pattern) they have safety holes because object lifetime is a
subset of memory lifetime. So before full construction or after Dispose
you have a block of raw memory, not an object that satisfies the
invariants of its type. That's a violation of type safety because you have
a T* that doesn't really point to a T -- it just points to a block of
memory that's the right size and that soon will, or recently used to, hold
a T, and that's not the same thing.


>> b) lock-free programming (see Andrei Alexandrescu's recent articles
>> and talks; you can do it yourself without GC but it's like working
>> with knives that are sharp on both edges and don't have handles).
>
>I read "Lock-Free Data Structures" article. I do not understand how GC
>will help here?

Did you read his Hazard Pointers article? It shows (some of) what you need
to deal with if you roll your own memory management without GC. And
remember that some of his code is pseudocode and has to be atomic; if you
try running just the code as it appears you end up with windows of
vulnerability.

The basic idea is that lock-free structures do object versioning, and you
need to throw away the old versions when they're no longer needed. But at
any given time there can actually be multiple versions of the object in
use by different threads, so you can't just throw it away immediately
(again the issue is knowing who might be using the object). If you don't
have some GC (ref counting or something else) you need to have other
mechanisms that will throw away the old versions.

>It will help only if "read pointer and register new
>root in GC" is an atomic operation (Is it? If yes -- how?). In steps:
>1. thread read value

Not quite... in lock-free, the first thing you do is:

0. Take a copy of the pointer to your state, and then always use that
pointer (not the actual pointer).

Then:

>1. thread read value
>2. thread is interrupted for very long time
>3. artificial map changes its data pointer
>4. GC finds no root and disposes of object
>5. thread awakes and (hopefully) fails to register new root in GC
>Where I am wrong?

By omitting #0, which shows that #4 isn't right -- the state is still
reachable because you took a copy of the pointer.

Try reading a little more about this and try working through a few
examples to get the flavor (try searching the ACM Portal for "lock-free"
and there are several papers about implementing queues and hash tables).

Herb

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Dave Harris

unread,
Jan 22, 2005, 1:45:54 PM1/22/05
to
hsu...@gotw.ca (Herb Sutter) wrote (abridged):

> A basic requirement of type safety is to able to guarantee that
> every pointer to a T object actually points to a T object. It's
> nonobvious how to completely accomplish that without some form GC

I agree in principle, but surely it is too late to add this kind of type
safety to C++ ? C++ allows pointers to stack-allocated objects. When the
stack is unwound, the pointer is left hanging. None of the GC proposals
are going to take away stack-allocated objects.

Explicit destructors are as bad. After "delete p;" p no longer points to a
valid object, whether or not the expression deallocates memory.

As you say, type safety is boolean. It's guaranteed by the language or it
isn't. In C++, it isn't. Adding GC won't change that. It's not a relevant
issue here.

-- Dave Harris, Nottingham, UK

davide...@yahoo.com

unread,
Jan 22, 2005, 9:42:34 PM1/22/05
to
First, let me claim that I am just an average C++ programmer. I
don't have enough knowledge in machine level to argue whether GC is
good or bad for C++. I'd like to argue it form a different angle:
philosophy. Why do modern great physicists and mathematician are also
great philosophers? Philosophy always guides them to create great
theories. One of wisdom by intellectual means is beauty, or in Bjarne
Stroustrup's word, Elegance. This belief also guides Bjarne Stroustrup
and E. F. Codd to create two greatest abstraction models in computer
science: class and relational database. What's this beauty to do
with GC? A lot!

As trained in physics field, we all know very well what abstraction
means. A good abstraction model hides a great deal of detail
information. C++ class provides such a great model. It allows class
writers to control how objects are created, where and when they are
created, and how they are destroyed. Now, put the GC into the picture.
The class writers will no longer to control these details to provide a
great abstraction model. In other word, GC will totally destroy class
abstraction model, or the beauty of C++ class will be gone with GC,
period.

C++ is not like Java or .Net which are based on virtual machine
concept. C++ is compiled to native machine instruction and has a
limited run time environment. This characteristics determines that C++
shouldn't emulate Java or .Net. As an average C++ programmer, I
never feel there is problem to manage memory. I have great pleasure to
write my own smart pointer and memory manager. GC not only is
unnecessary but also violates the design philosophy of C++: elegant and
efficient. I wonder why these C++ gurus want to add GC to C++
standard? Does it come from political reasons or they just cannot see
the big picture?

Michael Pryhodko

unread,
Jan 24, 2005, 6:25:17 AM1/24/05
to
>> not convincing. C++ provides model with good enough type and memory
>> safety -- I do not see how GC could improve it.
>
> Then you need to do more research. Type safety is pretty boolean --
> you either have it or you don't. A basic requirement of type safety
> is to able to guarantee that every pointer to a T object actually
> points to a T object.

Hmm... My 'type safety' is slightly different than yours. Yours can not
be accomplished in C++ -- you will need to forbid casting of pointers
to integral types. Also even if you will achieve such type safety, you
will still have big (and almost the same) problem:
it is true that any T* will point to valid T, but after 'Dispose()'
call object becomes unusable. So the main problem is pretty the same --
when to call 'delete' (Dispose) in your program. GC will only prevent
your application from crashing.


> It's nonobvious how to completely accomplish that without some form
> GC (note that ref counting is one of the three forms of GC).

Agreed in the described context. But given my note above do you REALLY
NEED to accomplish that? :)
Also -- you can replace my 'refcounting' words with more generic
'shared ownership' -- it does not matter here.


I doubt that type safety you described has a big practical aplication
-- mostly its just replaces 'when to call delete' problem with 'when to
call Dispose'.


>> I read "Lock-Free Data Structures" article. I do not understand how
>> GC will help here?
>
> Did you read his Hazard Pointers article? It shows (some of) what you
> need to deal with if you roll your own memory management without GC.
> And remember that some of his code is pseudocode and has to be atomic
> ; if you try running just the code as it appears you end up with
> windows of vulnerability.

No, I didn't read it yet. And certainly I understand these
complications, I am quite proficient with lock-free concept -- it is
passed more than 3 years since I created my first lock-free
single-linked list.


[skip]


>> It will help only if "read pointer and register new root in GC" is
>> an atomic operation (Is it? If yes -- how?). In steps:
>> 1. thread read value
>
> Not quite... in lock-free, the first thing you do is:
>
> 0. Take a copy of the pointer to your state, and then always use that
> pointer (not the actual pointer).

Sorry, I was too brief. "Read value" meant "read state pointer's value
into register". What I was trying to say is:
this example will work with GC only if statement:

void Lookup()
{
. T* pLocalState = this->m_pState;
. ...
}

could be implemented atomically lock-free. Which is not evident to me
since conceptually you need to do two things (x86):
a) load value 'this->m_pState' from memory to register
b) for given object register new 'root' in GC

So I asked -- how compiler implements this step without any locking?

The only thing I could guess is that compiler will always load such
values to the same register and GC during 'search for roots' process
will look into every thread's state for specific register value.
However this approach should slowdown application considerably.

Another thing that comes to my mind is that GC will only interrupt
program if it is "appropriate" using some kind of flag variable... Or
maybe setting up special flag used by every thread to stop when it is
ok; and only after every threads stops -- perform garbage collection.
This approach looks very wxpensive to me.


> Try reading a little more about this and try working through a few
> examples to get the flavor (try searching the ACM Portal for
> "lock-free" and there are several papers about implementing queues
> and hash tables).

Thanks, I read about lock-free implementation of queues, hash-tables
and memory allocators quite long ago (basically soon after those papers
publication). :)


Bye.
Sincerely yours, Michael.


Ioannis Vranos

unread,
Jan 24, 2005, 6:33:56 AM1/24/05
to
Ioannis Vranos wrote:

> I think what we really need for concurrency so as to take advantage of
> multicore processors in straight-forward applications (that is our usual
> applications that have no reason to have concurrent design), is a safe
> language level support in the style of OpenMP (which as far as I know is
> not safe in the sense that it is "hard-coded" and does not throw
> exceptions in case of errors for example).
>
>
> Perhaps the "safe part", should be additional compiler checks on such
> multithreading declarations.


Or perhaps the answer to the clock speed problem is what I came across
today:

http://slashdot.org/articles/05/01/23/0239207.shtml?tid=126&tid=1


Very interesting article.

Francis Glassborow

unread,
Jan 24, 2005, 10:35:02 AM1/24/05
to
In article <1106434748.7...@f14g2000cwb.googlegroups.com>,
davide...@yahoo.com writes

> C++ is not like Java or .Net which are based on virtual machine
> concept. C++ is compiled to native machine instruction and has a
> limited run time environment. This characteristics determines that C++
> shouldn't emulate Java or .Net. As an average C++ programmer, I
> never feel there is problem to manage memory. I have great pleasure to
> write my own smart pointer and memory manager. GC not only is
> unnecessary but also violates the design philosophy of C++: elegant and
> efficient. I wonder why these C++ gurus want to add GC to C++
> standard? Does it come from political reasons or they just cannot see
> the big picture?

Go back to Bjarne (who, by the way, did not invent the class concept)
and you will find that he never excluded GC from C++, all he argued was
that it should not be essential and compulsory. He has always argued in
favour of it being an optional facility. The development and experience
from Managed C++ to C++/CLI is taking that route and providing some
practical experience with solving problems caused by having GC as an
option.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Michael Pryhodko

unread,
Jan 24, 2005, 3:11:10 PM1/24/05
to
> Having C++/CLI in mind:

>
> C++/CLI is about "stack semantics", the real object is still in the
> managed heap. Dispose() is automatically compiler generated by the
> destructor (destructor is Dispose).

Does not work for me. From C++'s point of view it does not matter where
local, temporary, static and dynamic objects are located. They all
could be allocated from the same heap... Main difference is how C++
environment will treat them (e.g. lifetime of local objects is bound by
declaration scope).
Since after call to Dispose object becomes basically a 'zombie' -- we
have the same problem: when we need to destroy(dispose) object? The
difference is that now you need to foresight access to disposed object
while in current C++ it is simply declared as undefined behavior (or
ill-formed?).


>> But increasing application size and complexity could increases time
>> of GC session, thus increasing "resource release" delay and thus
>> increasing demands for open handles (I am not sure if these demands
>> will be linear of application complexity).
>
> Not if one uses deterministic destruction, the recommended way in
C++/CLI.

As I understand you deterministic destruction applied to local objects
only (what about temporaries?). But this won't help with dynamically
allocated objects -- like I said you will need to call dispose sooner
or later. And to make thing more complicated object will stay after
this and will be considered valid (but unusable).


> Well in general, C++ provides the choice not using GC if you can not
> afford it.

[a lot of future C++ complications skipped :)]


> Under C++/CLI, C++ is essentially two worlds, the managed and the
> unmanaged and the choice which one will use, is yours.

I already stated this as one of the reasons I do not like GC in C++.
Bye.
Sincerely yours, Michael.

Herb Sutter

unread,
Jan 24, 2005, 5:40:40 PM1/24/05
to
On 22 Jan 2005 21:42:34 -0500, davide...@yahoo.com wrote:
>As trained in physics field, we all know very well what abstraction
>means. A good abstraction model hides a great deal of detail
>information. C++ class provides such a great model. It allows class
>writers to control how objects are created, where and when they are
>created, and how they are destroyed. Now, put the GC into the picture.
>The class writers will no longer to control these details to provide a
>great abstraction model. In other word, GC will totally destroy class
>abstraction model, or the beauty of C++ class will be gone with GC,
>period.

I think you're making the (very common) assumption that conflates GC
(reclaiming memory) and object lifetime/teardown (destruction). Consider:
How would you feel about a C++ memory manager that did all the usual
new/delete and malloc/free just as today, but under the covers when you
did a delete or a free it didn't really reclaim the memory immediately,
but did it lazily later in response to other memory demands? That
describes the effect of work like the Boehm collector, which when used in
that way is transparent to the program.

>C++ is not like Java or .Net which are based on virtual machine
>concept. C++ is compiled to native machine instruction and has a
>limited run time environment. This characteristics determines that

Of course, the virtual machine can be viewed as just another target
machine. C and C++ are very good at being able to target many processors
with the same source base.

>C++ shouldn't emulate Java or .Net.

Agreed. Anything added to C++ should be to better serve C++ developers,
not just because some other language has it (copying for the sake of
copying).

>As an average C++ programmer, I
>never feel there is problem to manage memory. I have great pleasure to
>write my own smart pointer and memory manager. GC not only is
>unnecessary but also violates the design philosophy of C++: elegant and
>efficient. I wonder why these C++ gurus want to add GC to C++
>standard? Does it come from political reasons or they just cannot see
>the big picture?

Well, in Bjarne's talks about C++0x evolution, you'll always find the
bullet "optional garbage collection." I hope Bjarne has the reputation of
being a credible C++ guru without a political axe to grind. :-)

More broadly, 15-20 years ago many people felt the same way about OO.
(Today, a significant fraction of C programmers still feel that way about
OO!) It can take time for a community that's used to a certain way of
doing things to appreciate the value of (apparently) new features and
strategies. When those features make sense they should be used -- I agree
it would be bad to adopt features just because other languages have them.
And not everyone may need them enough to find them compelling.

Your post represents a completely understandable and widely held view.
There was once a time, a decade ago, when I was in the "I don't need no
stinkin' garbage collection, isn't that for lazy programmers who need
languages with training wheels" mindset. I didn't get over it overnight,
but I now see much more real value in it for C++, and see why Bjarne
mentioned the value of optional GC for C++ as far back as D&E (over a
decade ago).

Herb

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

ka...@gabi-soft.fr

unread,
Jan 24, 2005, 4:05:18 PM1/24/05
to
davide...@yahoo.com wrote:

> GC not only is
> unnecessary but also violates the design philosophy of C++:
> elegant and efficient. I wonder why these C++ gurus want to
> add GC to C++ standard?

Probably because they realize that garbage collection is elegant
and efficient. Any time you want really efficient memory
management, you end up implementing garbage collection anyway.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Ioannis Vranos

unread,
Jan 24, 2005, 6:56:47 PM1/24/05
to
Michael Pryhodko wrote:

> Does not work for me. From C++'s point of view it does not matter where
> local, temporary, static and dynamic objects are located. They all
> could be allocated from the same heap... Main difference is how C++
> environment will treat them (e.g. lifetime of local objects is bound by
> declaration scope).
> Since after call to Dispose object becomes basically a 'zombie' -- we
> have the same problem: when we need to destroy(dispose) object? The
> difference is that now you need to foresight access to disposed object
> while in current C++ it is simply declared as undefined behavior (or
> ill-formed?).


Essentially the same after a call to delete in ISO C++. If you use the
object you get undefined behaviour.

In fact in C++/CLI you do not call Dispose, when in the stack, the
object is Disposed at the end of its scope, and when in the heap the
object is Disposed after a call to delete.

> As I understand you deterministic destruction applied to local objects
> only (what about temporaries?). But this won't help with dynamically
> allocated objects -- like I said you will need to call dispose sooner
> or later. And to make thing more complicated object will stay after
> this and will be considered valid (but unusable).


No, you do not call Dispose but delete. You can also call Dispose
explicitly, but it has the same effect with delete.


--
Ioannis Vranos

http://www23.brinkster.com/noicys

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Ben Hutchings

unread,
Jan 24, 2005, 6:52:56 PM1/24/05
to
Michael Pryhodko wrote:
<snip>

>>> It will help only if "read pointer and register new root in GC" is
>>> an atomic operation (Is it? If yes -- how?). In steps:
>>> 1. thread read value
>>
>> Not quite... in lock-free, the first thing you do is:
>>
>> 0. Take a copy of the pointer to your state, and then always use that
>> pointer (not the actual pointer).
>
> Sorry, I was too brief. "Read value" meant "read state pointer's value
> into register". What I was trying to say is:
> this example will work with GC only if statement:
>
> void Lookup()
> {
> . T* pLocalState = this->m_pState;
> . ...
> }
>
> could be implemented atomically lock-free. Which is not evident to me
> since conceptually you need to do two things (x86):
> a) load value 'this->m_pState' from memory to register
> b) for given object register new 'root' in GC
>
> So I asked -- how compiler implements this step without any locking?

There is no need for (b).

> The only thing I could guess is that compiler will always load such
> values to the same register and GC during 'search for roots' process
> will look into every thread's state for specific register value.
> However this approach should slowdown application considerably.

<snip>

On the contrary, registering and deregistering roots regularly would
slow things down. Marking doesn't need to be done that often.

Normally all registers are roots, and either all appropriately-
aligned stack slots are roots or the program has range tables or
similar statically-generated information indicating which slots in
each stack frame may contain pointers.

--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by
<http://womble.decadentplace.org.uk/c++/template-faq.html>.

Michael Pryhodko

unread,
Jan 25, 2005, 5:47:51 AM1/25/05
to
>> The only thing I could guess is that compiler will always load such
>> values to the same register and GC during 'search for roots' process
>> will look into every thread's state for specific register value.
>> However this approach should slowdown application considerably.
>
> <snip>
>
> On the contrary, registering and deregistering roots regularly would
> slow things down. Marking doesn't need to be done that often.
>
> Normally all registers are roots, and either all appropriately-
> aligned stack slots are roots or the program has range tables or
> similar statically-generated information indicating which slots in
> each stack frame may contain pointers.

Hmm... Consequently for given GC implementation that means:
1. optimizer is limited in the ways it could use registers (for example
never load pointer into EAX since it is used for arithmetic operations
and GC could not at given time detect whether EAX holds pointer or not)
2. GC performance depends on number of threads in the system... and
size of their stacks! (since it needs to traverse every ?registered?
stack frame to find all roots in the same way as it is done when
exception thrown)
3. also there is a cost associated with registering and "upong entry
initialization" of stack tables used to hold pointers. Thus making
function calls more expensive.

Point 2. looks small in comparison with garbage collection itself but
anyway adds...

Also in case of compacting GC we have additional two levels of
indirection (first -- read address of the pointers table, second --
using index stored in pointer to access object itself). This adds in
cost especially considering modern processor's architecture with
predictions.
And I wonder how object could be moved if any thread started working
with it? And which costs are associated with mechanism that makes this
safe?
And about memory visibility in multi-processor case -- it should not be
a big problem on x86, but what about other architectures? what cost
could incur GC in order to make sure that its looking at "current"
thread state and stack?

Unfortunately GC introduces additional costs all over the generated
code. Maybe propose to move GC support to hardware level? ;)
Bye.
Sincerely yours, Michael.


Michael Pryhodko

unread,
Jan 25, 2005, 5:48:47 AM1/25/05
to
>> When I think about GC Ialways remember main reason of its invention.

>
> What do you see as the main reason for its invention, and
> approximately what year and language do you have in mind?

:) You've catched me here...
Indeed it seems that GC was invented in Lisp. However in my defense
here is the quote from
'http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-102.pdf':

[quote]
We propose adding safe, efficient garbage collection to C++,
eliminating the possibility of storage-management bugs and making the
design of complex, object-oriented systems much easier.
[/quote]

As you see from the beginning of the introduction GC to C++ one of the
main idea was 'to eliminate storage-management bugs'.

I was working with Lisp about year or so when at the very beginning of
my career and GC didn't left any traces in my memory.
Bye.
Sincerely yours, Michael.

ka...@gabi-soft.fr

unread,
Jan 25, 2005, 2:19:06 PM1/25/05
to
Ben Hutchings wrote:

> Normally all registers are roots, and either all
> appropriately- aligned stack slots are roots or the program
> has range tables or similar statically-generated information
> indicating which slots in each stack frame may contain
> pointers.

That's true for conservative collectors. If you want a copying
collector, you need to know exactly which registers contain
addresses, and which don't. In a mono-threaded environment,
this is rather simple: the compiler knows when the garbage
collector may be invoked, and can do whatever is necessary. In
a multithreaded environment, it is a lot more difficult; I've
got some papers somewhere which describe the technique, but
basically, when garbage collecting cuts in, it looks at where
each thread is, and advances it to a "safe" point, where it can
know which registers contain addresses. (Presumably -- I've no
real experience with this, so I'm just guessing -- ensuring that
there are enough "safe" points could have a negative impact on
optimization. But I imagine that the people developing this
technology are aware of the issues, and taking them into
account.)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sergey P. Derevyago

unread,
Jan 25, 2005, 2:30:19 PM1/25/05
to
ka...@gabi-soft.fr wrote:
> > GC not only is
> > unnecessary but also violates the design philosophy of C++:
> > elegant and efficient. I wonder why these C++ gurus want to
> > add GC to C++ standard?
>
> Probably because they realize that garbage collection is elegant
> and efficient. Any time you want really efficient memory
> management, you end up implementing garbage collection anyway.
>
IMHO it's not the case, i.e. GC isn't the panacea.

In particular, MMM can be thought as N steps with nearly constant small
run-time cost.
While GC is N-1 nearly free steps plus one which is really big and heavy.

In other words, the complexity doesn't disappear: GC just changes the
distribution of the complexity.
--
With all respect, Sergey. http://ders.angen.net/
mailto : ders at skeptik.net

David Abrahams

unread,
Jan 25, 2005, 3:11:16 PM1/25/05
to
"Michael Pryhodko" <mpry...@westpac.com.au> writes:

> I was working with Lisp about year or so when at the very beginning of
> my career and GC didn't left any traces in my memory.

Probably because it "just works." It raises the abstraction level of
the programming language to the point where you never have to consider
allocations and deallocations (though you do have to watch out for
inadvertently hanging onto data that you ought to let go of).

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

david eng

unread,
Jan 26, 2005, 4:53:01 AM1/26/05
to

"David Abrahams" <da...@boost-consulting.com> wrote in message
news:uzmyxo...@boost-consulting.com...

> "Michael Pryhodko" <mpry...@westpac.com.au> writes:
>
> > I was working with Lisp about year or so when at the very beginning of
> > my career and GC didn't left any traces in my memory.
>
> Probably because it "just works." It raises the abstraction level of
> the programming language to the point where you never have to consider
> allocations and deallocations (though you do have to watch out for
> inadvertently hanging onto data that you ought to let go of).

Looks like we are planning to raise the abstraction level of C++ to get rid
of deallocation by garbage collection. Then, we raise another abstraction
level of C++ to get rid of allocation by garbage delivery. Finally, we can
raise yet another abstraction level of C++ to get rid of programming by
garbage container. Sounds wonderful, isn't it? Abstraction has a different
meaning to different people. However, to really understand it and use it
properly is hard. It requires good judgment and education. That's why only
few people can become Bjarne or Dennis Ritchie likes, I guess.

David Bradley

unread,
Jan 26, 2005, 4:53:41 AM1/26/05
to
Sergey P. Derevyago wrote:
> IMHO it's not the case, i.e. GC isn't the panacea.

I'm still leary of the fact that GC allows developers to create overly
complex object relationships.

In addition I've been very unimpressed with Java and .Net when running
in an OS that is under memory pressure.

What is needed is a hybrid approach. Don't assume I should never manage
an object's lifetime. GC should be a safety net, not a straight jacket.
C# has "using" IIRC which allows you to essentially scope an object,
though I don't know the details of eactly what happens to the memory. In
the end what I want is something that allows me to take control and
manage things when I need to but watches my back if I forget. There's
just things that I know about my application that GC can't know.

I should also be able to take memory allocation out of the realm of
collector when I know that traversing that memory will be expensive and
that all things in the group will have the same lifetime.

David