Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The Twelve C++ Extensions of Christmas

12 views
Skip to first unread message

Ben Liddicott

unread,
Dec 14, 2000, 4:44:13 AM12/14/00
to
Since it is nearly the holidays, here is a trivial and frivolous post.

One of the favourite topics in this group is people's favourite extensions
to C++. I see C++ as an evolving language, and I have no doubt that there
will be extensions added, if only to bring C++ in to line with C9X.

I have collected together a list of some of the ones I would like to see.
Some of them I got from newsgroups including this one. Some, while no
doubt unoriginal, I thought of independently. None of them are credited,
since they have been widely discussed (and I can't remember where I got
them).

All of them are controversial, and in general it is arguable whether they
are a good idea, but I like them, and I would be interested in your
comments.

I have dispensed with the customary sprinkling of acronyms (IMHO, IMO and
AFAIK etc) in favour of a more forthright writing style, however these are
only my opinions, so please read this as if they were present in spades.

I am looking forward to seeing how these are received!

Cheers,
Ben Liddicott

1) try, catch, finally
==========================

As in Java, or Microsoft SEH.
Advantage:
The simplest example is remembering to free some resource. For example:

Resource r = AquireResource();
try{
UseResouce(r);
FreeResource(r);
}catch(ExceptionWeKnowHowToDealWith& e){
FreeResource(r);
SomeOtherAction();
throw;
}catch(...){
FreeResource(r);
PageSysadminOutOfBed();
throw;
}

The obvious "C++" way of doing this is to use an auto_pointer, or some
other
type of templatised wrapper to free the resource so you can't forget.
template<class ResourceType, class FunctionType, FunctionType fn>
class
auto_free_resource { /*and so forth*/ };

The finally way is this:
Resource r = AquireResource();
try{
UseResource(r);
}catch(ExceptionWeKnowHowToDealWith& e){
SomeOtherAction();
throw;
}catch(...){
PageSysadminOutOfBed();
throw;
}finally{
FreeResource();
}


The point being that the finally block is executed either after the end of
the try block (if it exits normally), when the try block throws (if the
exception is not caught by any catch handler in the same
try..catch..finally
block), at the end of the catch block (if a catch block exits normally) or
when a catch block throws, which is the only case left.

This to me is one of the single most egregiously missing items on the
list.

2) Empty Member Optimization
==========================

This is like the empty base optimization, but for members too!

Many C++ classes are used purely for the destruction sematics they have,
e.g., auto_ptr. Some are occasionally used for destruction semantics that
are entirely independent of any data, for example to log the lifetimes of
objects to cerr, or to maintain counts of class types, in which case they
would output only their "this" pointer.

Objects allocated with new would stil have sizeof(T)>=1, of course.

The only problem this might cause would be that such members would not
have unique "this" pointers. This matters only if they rely on the
uniqueness of their "this" pointer, in which case the workaround is to add
an unused data member, e.g., "char unused;"

3) Allow classes with constructors/destructors as members of unions.
==========================

Classes with constructors or destructors are not allowed as members of
unions.

This is a no brainer really. Of course there is no way for the compiler to
know which to call, and when. But if the developer is prepared to take
responsibility for calling the correct constructors and destructors at the
right time, there is no reason to prevent them.

4) Property-like methods.
==========================

These are implemented in a number of compilers as optional extensions,
e.g.,
MSVC, Borland, Cormeu (with MS extensions turned on).

The story is that the developer provides two functions, for example
struct A{
short getProp();
void setProp(short);
_declspec(property(get=getProp,set=setProp)) short Prop;
};

The compiler provides all the assignments etc.

The caller can then say
A a;
a.Prop = 8;
a.Prop += 4;
and so forth.

I have a nearly-complete version of this, based on templatised helper
classes, so it is almost possible now. It would be relatively easy to
implement if only number 8 (function forwarding) were standard.

This of course gives you nothing but syntactic sugar -- everything can be
done another way (by calling the set/get functions). But then the same
criticism applies to the whole mechanism of overloading arithmetic and
assignment operators. Syntactic prettiness is a worthwhile secondary goal.

5) typeof() operator.
==========================

This is analogous to the sizeof() operator, but yields the type of the
expression (without evaluating it).

Example:
vector<mytemplate<short, short, int, long, myclass<long>*>> v;
for(typeof(v)::iterator it = v.begin(); it != v.end(); it++)
SomeAction(*it);

Clearly you can achieve this with a typedef as well, but so what?

When I was a novice, I naively assumed you could use :: to retrieve the
type of a variable (because there was no reason why not):
vector<mytemplate<short, short, int, long, myclass<long>*>> v;
for(v::iterator it = v.begin(); it != v.end(); it++) SomeAction(*it);

I still think this makes sense, and is even more natural than typeof.
After all, the compiler knows the type, so why shouldn't it tell you?

6) outer type for nested classes.
==========================

Example:
struct A
{
struct B
{
};
};

B::outer should refer to A. Clearly this can be done by putting a line:
typedef A outer; in B's definition. Also clearly B can (itself) access
things such as typedefs and statics from A without any rigmarole.

This is primarily useful in things like macros (as seen in MFC). Many such
macros are used like so:
class C {
MACRO(C, a);
};
This introduces bugs if you cut and paste, or misspell the macro
arguments. It would be better if this could be written MACRO(a), and this
is the principle benefit that an automatically available typedef to the
containing class definition would give us.

7) Loop Labels
==========================

As in perl and Java, loop labels would allow more flexible use of break
and continue, and have the added advantages of documenting the programmers
intention when breaking from a loop, and prevent an inner loop, added
later, from unexpectedly breaking the program. They would also allow a
programmer to break out of a loop from within a switch statement, which is
a virtue in itself.

I confidently predict that if loop labels were added to the ansi C++
standard, all C++ style gurus would recommend always using them whenever
using break and continue in a loop (though they may still deprecate this).

Proposed: continue and break can use a loop label, to allow them to
specify which loop to continue with or break from. A label is a loop label
if it is followed by do, while or for, and it refers to the loop
controlled by that do, while or for.

loop_for_i:for(int i = 1; i< 1000; i++)
{
loop_for_j:for(int j = 1; j < 1000; j++)
{
if(SomeCondition(i,j))
continue loop_for_i;
if(SomeOtherCondition(i,j))
break loop_for_j;
DoSomeAction();
}
}

The break and continue could be implemented easily enough using a goto,
and labels in different places.

for(int i = 1; i< 1000; i++)
{
for(int j = 1; j < 1000; j++)
{
if(SomeCondition(i,j))
goto continue_loop_for_i;
if(SomeOtherCondition(i,j))
goto break_loop_for_j;
DoSomeAction();
continue_loop_for_j:;
}
break_loop_for_j:;
continue_loop_for_i:;
}
break_loop_for_i:;


Obviously a trivial example such as this does not really need it, but it
does occasionally have it's uses.

8) Function Forwarding.
==========================

This would enable "Smart references" with much reduced wear and tear on
the fingertips.

There is no way to inherit from a reference or a simple type. Or rather,
you can inherit from a class that wraps a simple type, and it is
straightforward enought to generate template wrappers that work for
all simple types and for pointers.

However there is no way to override the dot. This may seem trivial
requirement, but it is all about function forwarding, which is commonly
done (though you may think it should not be).

Example:

struct A
{
aMethod();
};

struct B : public using A&
{
A* mA;
operator A& () {return *mA;};
};

B b;
b.aMethod(); // calls b.operator A&().aMethod();

This example would forward all method calls not in B itself to A.

An example of smart references would be in RogueWave Threads++.


9) More operators.
==========================

Why stick with those boring old C style operators? What about:
<=> comparison. Returns signed result (so 0 means equal).
~= like. Floating point numbers are similar. Overridable to do pattern
matching for strings.
<- Can't be done. Ambiguous with less-than followed by unary-minus.
&>,&, *>, *<, +<, +>, -<
Surely someone can think of something to do with these?


10) Pick Any functions and data
==========================

The pickany attribute is applied to a function or static data to inform
the linker that any instance will do, and it should not die if it finds
multiple definitions (though it should ensure that only one is linked
into the final object).

Support for the principle is required by compilers in any case, to support
inline functions that are not actually inlined, and static member data for
template instantiations.

11) Covariant out parameters
==========================

This is really two extensions.

The first is "out" parameters to functions. An out parameter is a pointer
(or reference), with semantics such that the initial value of the
pointed-to (or referenced) object is ignored.

Rather than create a new keyword "out" (which is used for a lot of things
now), "return" could be overloaded.

Syntax:
bool f(return long*pl)
{
long l1 = *pl; //undefined. *pl has not been set
*pl = 10;// ok
long l2 = *pl;// ok now
return true;
}

Where this really comes into it's own is with pointer parameters:
bool f(return MyObject*& rpObj)
{
rpObj = GetObjFromSomewhere();
return true;
}

And the benefit it has is with covariance:

struct A{};
struct B:A{};

struct X{
virtual bool GetAnA(return A*& rpA);
};

struct Y:X{
virtual bool GetAnA(return B*& rpB);// overrides GetAnA(return A*&)
};

int main()
{
B* pB=0;
Y y;
X* pX = &y;
x.GetAnA(pB);
return 0;
}

Ordinarily this is forbidden, of course, even though it is entirely safe.
It is safe because the programmer knows that the value of rpA is ignored
on entry, and recieves a class derived from A.

12) And some more gubbins.
==========================

There are a large number of things I would like to see standardized which
don't count as language extensions.

a) Sized integers.

In my opinion the original choice not to standardize the sizes of integer
types is an evil one. Yes, if you want sized integers, you can define them
in a platform specific header file:
#define _int8 char
#define _int16 short
#define _int32 long
#define _int64 long long // long long not a standard in C++. What aboutn
C9X?
// they are defines not typedefs to support unsigned _int32 etc.

And sure enough, this is what people seem to do. All the time. In any
non-trivial project. Some use defines, some use typedefs, but they are all
getting at the same thing: They want to know how big their integers are.

And don't say it isn't a choice: One could implement it the other way
around:
#define char _int8
#define short _int16
#define long _int32

Or rather one could if there wasn't the problem with separate overloads
for long and int (they being the same size on many platforms).

b) Endianism macros for reading from/writing to streams intended for other
architectures. These should deal with unsigned integral types of size
1, 2, 4, and 8 bytes, as well as doubles and floats.

Define
CHANGEENDIANISM_QWORD()
CHANGEENDIANISM_DWORD()
etc
and
MACHINETOBIGENDIAN_QWORD()
MACHINETOBIGENDIAN_DWORD
MACHINETOBIGENDIAN_WORD
MACHINETOBIGENDIAN_BYTE //obviously a nop.
and
MACHINETOLITTLEENDIAN_QWORD etc.

Of course, you can write a complete set of them yourself in half a day or
so, but why should you have to?

c) More control over inlining.

I would suggest:
forceinline Always inlined unless it is impossible to do so. Use
programmer's judgement.
inline Suggest inline. (Use compiler's judgement)
Not inlined
Then provide levels, such as inline1, inline2 to inline9.
And set options: inline_levels(1,3) would map inline1 to forceinline,
inline2 and inline3 to inline and the others to pickany, avoiding linker
errors (see above). This can be implemented today as macros (degrading
pickany to inline), but it would be nice to have a standard.

d) Standardized compiler options.

So you don't have to learn multiple sets.

e) Standardized compiler errors and warnings.

So you don't have to learn multiple sets.

f) The ablility to turn non-ansi features on and off one at a time.

How about it Microsoft? I don't want your old fashioned loop semantics,
but I sure like that _declspec(property) and C9X style struct hack!

g) Oh, yes:

void main() // This should be allowed.

Who are these self appointed language police who care enough to correct
posters about this? If the program doesn't have a meaningful return value,
then the compiler should return rubbish, or zero! The only tool I care
about that uses a return value is find (and test, of course, has a return
value that is meaningful to the shell).


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

tom

unread,
Dec 15, 2000, 11:09:12 AM12/15/00
to
Previously, Ben Liddicott wrote in comp.lang.c++.moderated:

> Since it is nearly the holidays, here is a trivial and frivolous post.

I'll comment on some of your ideas.

> 1) try, catch, finally
> ==========================

> This to me is one of the single most egregiously missing items on the
> list.

Agreed, although libraries being written for boost will largely remove
the need for this using features already in the language - preferable.

>
> 3) Allow classes with constructors/destructors as members of unions.
> ==========================
>
> Classes with constructors or destructors are not allowed as members of
> unions.
>
> This is a no brainer really. Of course there is no way for the compiler to
> know which to call, and when. But if the developer is prepared to take
> responsibility for calling the correct constructors and destructors at the
> right time, there is no reason to prevent them.

Unfortunately the language doesn't have any facilities at present for the
user to call a constructor. But how about:

union foo
{
A a;
B b;
};

foo f;
new (&f) A(5);

If that's what you want, then the language is already up to it I think.
Not sure if that is portable though.

>
> 4) Property-like methods.
> ==========================

I quite like properties - they save you from having to write worthless
get and set methods just in case.




> 5) typeof() operator.
> ==========================
>
> This is analogous to the sizeof() operator, but yields the type of the
> expression (without evaluating it).
>
> Example:
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(typeof(v)::iterator it = v.begin(); it != v.end(); it++)
> SomeAction(*it);
>
> Clearly you can achieve this with a typedef as well, but so what?
>
> When I was a novice, I naively assumed you could use :: to retrieve the
> type of a variable (because there was no reason why not):
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(v::iterator it = v.begin(); it != v.end(); it++) SomeAction(*it);
>
> I still think this makes sense, and is even more natural than typeof.
> After all, the compiler knows the type, so why shouldn't it tell you?

I like this one - it can save an enormous amount of typing (forgive the pun).


> 6) outer type for nested classes.
> ==========================
>
> Example:
> struct A
> {
> struct B
> {
> };
> };
>
> B::outer should refer to A. Clearly this can be done by putting a line:
> typedef A outer; in B's definition. Also clearly B can (itself) access
> things such as typedefs and statics from A without any rigmarole.

Not useful enough to be worth it. The typedef does it, and introducing
new keywords is undesirable.

> 7) Loop Labels
> ==========================
>
> As in perl and Java, loop labels would allow more flexible use of break
> and continue, and have the added advantages of documenting the programmers
> intention when breaking from a loop, and prevent an inner loop, added
> later, from unexpectedly breaking the program. They would also allow a
> programmer to break out of a loop from within a switch statement, which is
> a virtue in itself.
>
> I confidently predict that if loop labels were added to the ansi C++
> standard, all C++ style gurus would recommend always using them whenever
> using break and continue in a loop (though they may still deprecate this).
>
> Proposed: continue and break can use a loop label, to allow them to
> specify which loop to continue with or break from. A label is a loop label
> if it is followed by do, while or for, and it refers to the loop
> controlled by that do, while or for.
>
> loop_for_i:for(int i = 1; i< 1000; i++)
> {
> loop_for_j:for(int j = 1; j < 1000; j++)
> {
> if(SomeCondition(i,j))
> continue loop_for_i;
> if(SomeOtherCondition(i,j))
> break loop_for_j;
> DoSomeAction();
> }
> }

Hmm, not sure about this one. I would make some code more concise, and
perhaps more obvious too.


> 8) Function Forwarding.
> ==========================
>
> This would enable "Smart references" with much reduced wear and tear on
> the fingertips.

What's wrong with smart pointers?

> 9) More operators.
> ==========================
>
> Why stick with those boring old C style operators? What about:
> <=> comparison. Returns signed result (so 0 means equal).
> ~= like. Floating point numbers are similar. Overridable to do pattern
> matching for strings.
> <- Can't be done. Ambiguous with less-than followed by unary-minus.
> &>,&, *>, *<, +<, +>, -<
> Surely someone can think of something to do with these?

<=> and ~= might be nice. The rest would be pushing it though.

>
> 10) Pick Any functions and data
> ==========================
>
> The pickany attribute is applied to a function or static data to inform
> the linker that any instance will do, and it should not die if it finds
> multiple definitions (though it should ensure that only one is linked
> into the final object).
>
> Support for the principle is required by compilers in any case, to support
> inline functions that are not actually inlined, and static member data for
> template instantiations.

This is an odd thing to want. Why do you want it? Do you want to put
everything in headers or something? Most people are after the opposite - export.


> 11) Covariant out parameters
> ==========================

This is actually conceptually wrong. You haven't thought it through.

> This is really two extensions.
>
> The first is "out" parameters to functions. An out parameter is a pointer
> (or reference), with semantics such that the initial value of the
> pointed-to (or referenced) object is ignored.
>
> Rather than create a new keyword "out" (which is used for a lot of things
> now), "return" could be overloaded.
>
> Syntax:
> bool f(return long*pl)
> {
> long l1 = *pl; //undefined. *pl has not been set
> *pl = 10;// ok
> long l2 = *pl;// ok now
> return true;
> }
>
> Where this really comes into it's own is with pointer parameters:
> bool f(return MyObject*& rpObj)
> {
> rpObj = GetObjFromSomewhere();
> return true;
> }
>
> And the benefit it has is with covariance:
>
> struct A{};
> struct B:A{};

struct C:A{
void do_it();
};

> struct X{
> virtual bool GetAnA(return A*& rpA);
> };
>
> struct Y:X{
> virtual bool GetAnA(return B*& rpB);// overrides GetAnA(return A*&)
> };

struct Z:X{
virtual bool GetAnA(return C*& rpC);// overrides GetAnA(return A*&)
};

> int main()
> {
> B* pB=0;
> Y y;
> X* pX = &y;

> pX->GetAnA(pB);
C* pC=0;
pX->GetAnA(pC);
pC->do_it(); //boom, pC is actally a B

> return 0;
> }
>
> Ordinarily this is forbidden, of course, even though it is entirely safe.

No it is not at all safe.

> It is safe because the programmer knows that the value of rpA is ignored
> on entry, and recieves a class derived from A.

But it might receive a different class derived from A.

> 12) And some more gubbins.
> ==========================
>
> There are a large number of things I would like to see standardized which
> don't count as language extensions.
>
> a) Sized integers.

C99 has them already. C++ is sure to follow.

> g) Oh, yes:
>
> void main() // This should be allowed.
>
> Who are these self appointed language police who care enough to correct
> posters about this? If the program doesn't have a meaningful return value,
> then the compiler should return rubbish, or zero! The only tool I care
> about that uses a return value is find (and test, of course, has a return
> value that is meaningful to the shell).

I don't know why the C people chose an int return in the first place, but
I'm sure they had their reasons. Perhaps there are platforms that require
all programs to return a value? If so, why bugger them up? You can leave
off the return anyway, and it's shorter to type int than void :)

Tom

John G Harris

unread,
Dec 15, 2000, 11:46:05 AM12/15/00
to
In article <976747071.14502.1...@news.demon.co.uk>, Ben
Liddicott <ben.li...@bencat.demon.co.uk> writes
<snip>

>g) Oh, yes:
>
>void main() // This should be allowed.
>
>Who are these self appointed language police who care enough to correct
>posters about this? If the program doesn't have a meaningful return value,
>then the compiler should return rubbish, or zero! The only tool I care
^^^^^^^^^^^^^^^^^^^^^^

>about that uses a return value is find (and test, of course, has a return
>value that is meaningful to the shell).

But then "void" is a blatant lie, isn't it.

John
--
John Harris
mailto:jo...@jgharris.demon.co.uk

Ron Natalie

unread,
Dec 15, 2000, 9:59:30 PM12/15/00
to

tom wrote:
>
> > void main() // This should be allowed.
> >
> > Who are these self appointed language police who care enough to correct
> > posters about this? If the program doesn't have a meaningful return value,
> > then the compiler should return rubbish, or zero! The only tool I care
> > about that uses a return value is find (and test, of course, has a return
> > value that is meaningful to the shell).
>
> I don't know why the C people chose an int return in the first place, but
> I'm sure they had their reasons. Perhaps there are platforms that require
> all programs to return a value? If so, why bugger them up? You can leave
> off the return anyway, and it's shorter to type int than void :)
>

They chose int originally because C didn't originally have the concept
of void. Everybody just avoided looking at int returns if they had
void functions. Main is goofy enough as it (inversely overloaded and
goofy implicit returns), lets avoid messing it up further.

Ali Cehreli

unread,
Dec 16, 2000, 2:53:40 AM12/16/00
to
Ben Liddicott <ben.li...@bencat.demon.co.uk> wrote in message
news:976747071.14502.1...@news.demon.co.uk...

> 12) And some more gubbins.
> ==========================
>
> There are a large number of things I would like to see standardized which
> don't count as language extensions.
>

[...]

> g) Oh, yes:
>
> void main() // This should be allowed.
>
> Who are these self appointed language police who care enough to correct
> posters about this?

I am one of those people. You propose making void main() standard because it
is not. I correct posters for the same reason.

> If the program doesn't have a meaningful return value,
> then the compiler should return rubbish, or zero!

I agree. The compiler already inserts a "return 0;" when returning from main
if one is not provided. Why not also "change the return value to int" if
void (or some other type) is provided.

I will stop correcting when it is standard. :)

Ali
--
Please remove the dot between 'mar' and 'coni' before replying.

Nick Thurn

unread,
Dec 16, 2000, 2:59:09 AM12/16/00
to
Ben Liddicott wrote:
> 6) outer type for nested classes.
> ==========================
>
(Seriously) What about forward declaration of nested classes?

> 9) More operators.
> ==========================
>
(Silly) Yes we need operators :-) and :-(
Non-standarized versions of these are everywhere.

Perhaps a new keyword "hack" would be helpful in making code
more self documenting.

Happy Xmas!

Joseph Gottman

unread,
Dec 16, 2000, 3:11:46 AM12/16/00
to

"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
news:976747071.14502.1...@news.demon.co.uk...
> Since it is nearly the holidays, here is a trivial and frivolous post.
>
> One of the favourite topics in this group is people's favourite extensions
> to C++. I see C++ as an evolving language, and I have no doubt that there
> will be extensions added, if only to bring C++ in to line with C9X.
>
> I have collected together a list of some of the ones I would like to see.
> Some of them I got from newsgroups including this one. Some, while no
> doubt unoriginal, I thought of independently. None of them are credited,
> since they have been widely discussed (and I can't remember where I got
> them).
>
> 5) typeof() operator.
> ==========================
>
> This is analogous to the sizeof() operator, but yields the type of the
> expression (without evaluating it).
>
> Example:
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(typeof(v)::iterator it = v.begin(); it != v.end(); it++)
> SomeAction(*it);
>
> Clearly you can achieve this with a typedef as well, but so what?
>
> When I was a novice, I naively assumed you could use :: to retrieve the
> type of a variable (because there was no reason why not):
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(v::iterator it = v.begin(); it != v.end(); it++) SomeAction(*it);
>
> I still think this makes sense, and is even more natural than typeof.
> After all, the compiler knows the type, so why shouldn't it tell you?
>

typeof would be even more useful when combined with templates. For
instance, suppose you have a template class for polynomials. One obvious
member function would be operator()(), to evaluate the polynomial at a
point. If you have an object of type polynomial<X>, it might still make
sense to evaluate it at a point of some other type, for instance
polynomial<int> f; //f (x) = x^2 + x + 1
f(0.5) // Evaluate at a double, result = 1.75 is of type double
polynomial<double> g; //g(x) = x + .5;
g(1); // Evaluate at an int, result = 1.5 is of type double.

The problem is how would you declare operator()() in this case? Using
typeof would make it easy:
template <class X> class polynomial
{
....
template <class Y> typeof (X() * Y()) operator()(Y value) // Return type of
an X multiplied by a Y.
};

Without typeof, I can't see any way to get this function to always return
the correct type.

Joe Gottman

RCN News Server

unread,
Dec 16, 2000, 4:28:16 AM12/16/00
to
Before I add my comments to this wish list of new C++ extensions, let me say
my *absolute, most desired wish* is to be able to use a C++ compiler that
implements fully and correctly the current standard we have (and a close
second wish is to have *all* the C++ compilers meet this first wish so my
code can portably move between platforms (with great care given to not using
anything specific to a platform, of course). My third wish would be to have
a standard class library that included the same functionality as the Java
class libraries, in particular, standard database access, network access,
and (the real hard one) GUI access. If we had all three of the above wishes
granted I think we would be too busy writing C++ applications instead of
learning Java and coming of with language extensions.

"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
news:976747071.14502.1...@news.demon.co.uk...

> 1) try, catch, finally
> ==========================

This wouldn't be my top priority for the reasons you describe below, i.e.
there are auto_ptr like alternatives (see boost.org for their scoped class),
although not as elegantly.

I'm not sure I understand this one.

>
> This is like the empty base optimization, but for members too!
>
> Many C++ classes are used purely for the destruction sematics they have,
> e.g., auto_ptr. Some are occasionally used for destruction semantics that
> are entirely independent of any data, for example to log the lifetimes of
> objects to cerr, or to maintain counts of class types, in which case they
> would output only their "this" pointer.
>
> Objects allocated with new would stil have sizeof(T)>=1, of course.
>
> The only problem this might cause would be that such members would not
> have unique "this" pointers. This matters only if they rely on the
> uniqueness of their "this" pointer, in which case the workaround is to add
> an unused data member, e.g., "char unused;"
>
> 3) Allow classes with constructors/destructors as members of unions.
> ==========================

Since unions are mostly a memory saving technique and given that 128 MB on a
PC is not uncommon, this definitely wouldn't be on my list of gotta have
extensions. The few times I've ever used unions, unions of PODs worked
fine.

>
> Classes with constructors or destructors are not allowed as members of
> unions.
>
> This is a no brainer really. Of course there is no way for the compiler to
> know which to call, and when. But if the developer is prepared to take
> responsibility for calling the correct constructors and destructors at the
> right time, there is no reason to prevent them.

I think there's enough ways in C++ for a programmers to hang themselves that
we don't need another.

>
> 4) Property-like methods.
> ==========================
>
> These are implemented in a number of compilers as optional extensions,
> e.g.,
> MSVC, Borland, Cormeu (with MS extensions turned on).
>
> The story is that the developer provides two functions, for example
> struct A{
> short getProp();
> void setProp(short);
> _declspec(property(get=getProp,set=setProp)) short Prop;
> };
>
> The compiler provides all the assignments etc.
>
> The caller can then say
> A a;
> a.Prop = 8;
> a.Prop += 4;
> and so forth.
>
> I have a nearly-complete version of this, based on templatised helper
> classes, so it is almost possible now. It would be relatively easy to
> implement if only number 8 (function forwarding) were standard.

I've tried to do the same and come reasonably close that I don't think I'd
need a language extension to be happy. I'd rather see any extensions go
into the functionality of templates, which would be more general purpose.

>
> This of course gives you nothing but syntactic sugar -- everything can be
> done another way (by calling the set/get functions). But then the same
> criticism applies to the whole mechanism of overloading arithmetic and
> assignment operators. Syntactic prettiness is a worthwhile secondary goal.
>
> 5) typeof() operator.

See the CUJ article about a "portable typeof()" operator in the Nov 2000
issue (although I don't think it would do what you describe below (that's
why it's "mostly"
;-)):
A Portable 'typeof' Operator Bill Gibbons
Here's a not-so-stupid template trick that mostly meets the need for a
typeof operator.

http://www.cuj.com/archive/1811/index.html

I think you're bucking the trends here. Java eliminated them. C# reduced
the number you can play with. And you want to add to them!?! Good luck on
getting this one adopted.

Actually, I like defining my own implementation of operators for a class.
I'd take this extension one step further and allow the programmer to define
their own unary, binary, and tertiary operators, e.g.

int operator mod(int lhs, int rhs);
int operator "<==>" (int lhs, int rhs); // Because I arbitrarily
prefer <==> to <=>

At least one problem with this would be how do you specify the operator
precedence. Of course this extension has even less chance of making it into
the standard than yours does :-(.

Why would this have to be restricted to output parameters? It seems like
any reference/pointer parameter regardless of whether it's used as input or
output could be used. Maybe we could bring back the deprecated (and since
obsolete?) overload keyword (or was it override?).


>
> 12) And some more gubbins.
> ==========================
>
> There are a large number of things I would like to see standardized which
> don't count as language extensions.
>
> a) Sized integers.
>
> In my opinion the original choice not to standardize the sizes of integer
> types is an evil one. Yes, if you want sized integers, you can define them
> in a platform specific header file:
> #define _int8 char
> #define _int16 short
> #define _int32 long
> #define _int64 long long // long long not a standard in C++. What aboutn
> C9X?

I think C9X has some extensive changes in this area and I'd suspect C++ will
eventually adopt them. In CUJ they're talking about the C9X standard.

Randy Meyers
The New C: Integers, Part 2
The new C Standard has a novel idea: just accept that machine-word sizes
will grow. Randy explains C's proactive strategy for accommodating the
inevitable.

Good luck on this one ;-). I'd like to see it to for at least some simple
ones:
-O<some #> level of compiler optimization
-o file output file
-I dir Include directory
-D TOKEN=val Define symbol (#define TOKEN val)
-U TOKEN Undefine symbol (#undef TOKEN)
-w +|-token Disable (-)/enable (+) warning message "token"
where
token is compiler specific.
-f +|-token Disable (-)/enable (+) compiler feature, e.g.
inlining

Along the same lines and also a solution for c) would be to have a standard
set of #pragma's (what an oxymoron, but ...). One I could think of and
related to this extension would be:

#pragma options <compiler-specific comand line options>

e.g.

#pragma options -w -unused_local

would disable the warning message regarding unused variables. It might be
nice to have variants that have stack like qualities, e.g.

#pragma push_options -w -unused_local
// ...
#pragma pop_options

If you could get a standard command line option for disable/enable inline
functions, you could use the #pragma.

>
> So you don't have to learn multiple sets.
>
> e) Standardized compiler errors and warnings.

Another good luck! ;-)


>
> So you don't have to learn multiple sets.
>
> f) The ablility to turn non-ansi features on and off one at a time.
>
> How about it Microsoft? I don't want your old fashioned loop semantics,
> but I sure like that _declspec(property) and C9X style struct hack!

A standard set of command line options/#pragma options could help here.

>
> g) Oh, yes:
>
> void main() // This should be allowed.

Since your allowed to have a control path that doesn't have a "return val",
what's the big deal?

>
> Who are these self appointed language police who care enough to correct
> posters about this? If the program doesn't have a meaningful return value,
> then the compiler should return rubbish, or zero!

It does. From 3.6.1.5: If control reaches the end of main without
encountering a return statement, the effect is that of executing: return 0;

Now for my Christmas extension: I'd like the RTTI to be extended to include
the introspection capabilities of Java (to as great a degree as possible),
e.g.

class std::type_info
{
public:
// The stuff it already has, plus:
const char *full_name() const; // Returns fully-elaborated, human
readable name
// including all
namespaces and nested classes
// separated via
"::". This method could be added
// or name() could
be specified to return this
// string.

enum {
IS_CONST = 1,
IS_VOLATILE = 2
IS_PRIVATE = 4,
IS_PROTECTED = 8,
IS_PUBLIC = 16,
IS_REF = 32, // How do you handle pointers to functions, T **, T
*&, etc.???
IS_PTR = 64,
IS_INLINE = 128,
IS_STATIC = 256,
};

class arg_info
{
public:
const char *name() const;
const type_info &type() const;
bool has_default() const;
int modifiers() const; // Returns mask of applicable above enums.
};

class member_info
{
public:
const char *name() const;
int modifiers() const; // Returns mask of applicable above enums.
};

class method_info
{
public:
const char *name() const;
const char *mangled_name() const;
const std::vector<arg_info> args() const;
int modifiers() const; // Returns mask of applicable above enums.
};

const vector<type_info> &base_classes() const;
const vector<type_info> &friend_classes() const;
const vector<method_info> &methods() const;
const vector<member_info> &members() const;

// Anything else??
};


--
Michael (Mike) H. Cox

Ken Bloom

unread,
Dec 16, 2000, 5:27:12 AM12/16/00
to

"John G Harris" <jo...@nospam.demon.co.uk> wrote in message
news:fc2DoIA0...@jgharris.demon.co.uk...

> In article <976747071.14502.1...@news.demon.co.uk>, Ben
> Liddicott <ben.li...@bencat.demon.co.uk> writes
> <snip>
> >g) Oh, yes:
> >
> >void main() // This should be allowed.
> >
> >Who are these self appointed language police who care enough to correct
> >posters about this? If the program doesn't have a meaningful return
value,
> >then the compiler should return rubbish, or zero! The only tool I care
> ^^^^^^^^^^^^^^^^^^^^^^
> >about that uses a return value is find (and test, of course, has a return
> >value that is meaningful to the shell).
>
> But then "void" is a blatant lie, isn't it.

void would imply that the program itself doesn't return any meaningful
value, and that it would always return some kind of "success" value if there
are values that cause the system shell to report an error of some kind. The
compiler may be in a better position to figure this out if the user doesn't
have some specific integer value to return.

sieme...@my-deja.com

unread,
Dec 16, 2000, 5:37:32 AM12/16/00
to
In article <976747071.14502.1...@news.demon.co.uk>,
"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:

So what's wrong with the C++ way? Maybe that it leads to code that is
longer to write/read, because you have to define a new
auto_free_resource class for every usage? With enough templating, I
guess we wouldn't have to write too many of these classes, even in a
large project. So I don't see a big advantage here.

BTW, you could make a traits class whose operator() does the cleanup:
struct FreeResource { void operator()(Thing * thing) const; }
and your generic auto cleaning class will take just 2 template
parameters -- the Thing object and that traits class.

Or you could derive a class CleaningResource from Resource, and
CleaningResource's destructor will call Resource::FreeResource().

Also, if we somehow had the feature of a local class being able to
access local variables then we could just make a local sentry class
that cleans up,
Thing * thing=new Thing;
struct Cleanup { ~Cleanup() { delete thing; } } cleanup_;
...

And if we had unnamed variables, all the better
Thing * thing=new Thing;
struct { ~() { delete thing; } };
...


> 2) Empty Member Optimization
> ==========================
>
> This is like the empty base optimization, but for members too!
>
> Many C++ classes are used purely for the destruction sematics they
have,
> e.g., auto_ptr. Some are occasionally used for destruction semantics
that
> are entirely independent of any data, for example to log the
lifetimes of
> objects to cerr, or to maintain counts of class types, in which case
they
> would output only their "this" pointer.
>
> Objects allocated with new would stil have sizeof(T)>=1, of course.
>
> The only problem this might cause would be that such members would not
> have unique "this" pointers. This matters only if they rely on the
> uniqueness of their "this" pointer, in which case the workaround is
to add
> an unused data member, e.g., "char unused;"


I don't see what you're talking about.


> 3) Allow classes with constructors/destructors as members of unions.
> ==========================
>
> Classes with constructors or destructors are not allowed as members of
> unions.
>
> This is a no brainer really. Of course there is no way for the
compiler to
> know which to call, and when. But if the developer is prepared to take
> responsibility for calling the correct constructors and destructors
at the
> right time, there is no reason to prevent them.

Yes sure, they could call the right constructor.
But how to call the right copy constructor and op=?
And how to call the right destructor?

The only extension I see is to allow user types with trivial copy ctor,
op=, dtor to be part of a union. At present, only fundamental types
can be members.

Normally, if you find yourself using unions a lot, then it's time to
switch to the base class derived classes concept.

You got your template class, so why do you need a language extension?
Besides, a good optimizer will treat CProp<short> instances as if they
were short instances, and so there will be no overhead. This
optimization happens so long as all the members of CProp are inline.


> 5) typeof() operator.
> ==========================
>
> This is analogous to the sizeof() operator, but yields the type of the
> expression (without evaluating it).
>
> Example:
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(typeof(v)::iterator it = v.begin(); it != v.end(); it++)
> SomeAction(*it);
>
> Clearly you can achieve this with a typedef as well, but so what?
>
> When I was a novice, I naively assumed you could use :: to retrieve
the
> type of a variable (because there was no reason why not):
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(v::iterator it = v.begin(); it != v.end(); it++) SomeAction(*it);
>
> I still think this makes sense, and is even more natural than typeof.
> After all, the compiler knows the type, so why shouldn't it tell you?

Fine. But what big problems does it solve? For iterator, you could
very well use typedef typename Container::const_iterator Iter.


> 6) outer type for nested classes.
> ==========================
>
> Example:
> struct A
> {
> struct B
> {
> };
> };
>
> B::outer should refer to A. Clearly this can be done by putting a
line:
> typedef A outer; in B's definition. Also clearly B can (itself) access
> things such as typedefs and statics from A without any rigmarole.
>
> This is primarily useful in things like macros (as seen in MFC). Many
such
> macros are used like so:
> class C {
> MACRO(C, a);
> };
> This introduces bugs if you cut and paste, or misspell the macro
> arguments. It would be better if this could be written MACRO(a), and
this
> is the principle benefit that an automatically available typedef to
the
> containing class definition would give us.

Don't use macros, especially the ones like you have. Maybe in the end
Linux will outdo Microsoft and we won't have to deal with these
clever 'features' of Microsoft :).

But we'd have the same problem even if we use templates -- namely that
the inner class does not have a builtin typedef to name the outer
class. It's a nice feature, but what big problem does it solve?

Another one you forgot is an automatic typedef in the derived class for
the base classes. I came up with this --

class Derived :
public base=std::unary_function<char,char>,
public base2=Junk<Derived>

Looks like it could be useful.

But why not just use goto for break?
And maybe remove continue from the language?


> 8) Function Forwarding.
> ==========================
>
> This would enable "Smart references" with much reduced wear and tear
on
> the fingertips.
>
> There is no way to inherit from a reference or a simple type. Or
rather,
> you can inherit from a class that wraps a simple type, and it is
> straightforward enought to generate template wrappers that work for
> all simple types and for pointers.
>
> However there is no way to override the dot. This may seem trivial
> requirement, but it is all about function forwarding, which is
commonly
> done (though you may think it should not be).
>
> Example:
>
> struct A
> {
> aMethod();
> };
>
> struct B : public using A&
> {
> A* mA;
> operator A& () {return *mA;};
> };
>
> B b;
> b.aMethod(); // calls b.operator A&().aMethod();
>
> This example would forward all method calls not in B itself to A.
>
> An example of smart references would be in RogueWave Threads++.

I don't get it.

But const derivation could be good

class Derived : public const Base {

> 9) More operators.
> ==========================
>
> Why stick with those boring old C style operators? What about:
> <=> comparison. Returns signed result (so 0 means equal).
> ~= like. Floating point numbers are similar. Overridable to do
pattern
> matching for strings.
> <- Can't be done. Ambiguous with less-than followed by unary-
minus.
> &>,&, *>, *<, +<, +>, -<
> Surely someone can think of something to do with these?

We have too many operators already. Just think of the burden on
someone to learn all of these.

Maybe we could change the editor so that we can draw integral signs and
treble clefs, and overload these too :).

> 10) Pick Any functions and data
> ==========================
>
> The pickany attribute is applied to a function or static data to
inform
> the linker that any instance will do, and it should not die if it
finds
> multiple definitions (though it should ensure that only one is linked
> into the final object).
>
> Support for the principle is required by compilers in any case, to
support
> inline functions that are not actually inlined, and static member
data for
> template instantiations.

Well, what if not any will do? What if the different objects are
indeed different.

Besides, in the purest and best of all possible worlds, you won't get
this problem of multiple objects.

Tell your compiler vendor to supply this option, to give an error if
the objects are actually different and to do nothing if they are the
same. Be prepared that if your program outputs the address of the
object your program behaviour is unpredictable. Finally, linker
options have nothing to do with C++.

What happens here?
A * pA;
...
x.GetAnA(pA);

This one I like.

Also good is numbers with underscores like "double x=123_456.45;".

Inlining is an implementation detail.


> d) Standardized compiler options.
>
> So you don't have to learn multiple sets.

Standardizing also reduces the options available in the future. That
is, we lose experiments that compiler-vendors might try because now
they must all do the same thing.


> e) Standardized compiler errors and warnings.
>
> So you don't have to learn multiple sets.

> f) The ablility to turn non-ansi features on and off one at a time.
>
> How about it Microsoft? I don't want your old fashioned loop
semantics,
> but I sure like that _declspec(property) and C9X style struct hack!

Get a compiler that does this.

> g) Oh, yes:
>
> void main() // This should be allowed.
>
> Who are these self appointed language police who care enough to
correct
> posters about this? If the program doesn't have a meaningful return
value,
> then the compiler should return rubbish, or zero! The only tool I care
> about that uses a return value is find (and test, of course, has a
return
> value that is meaningful to the shell).

Yes, a void return should mean 0 return. In fact, egcs does this
anyway though it gives you a warning. I have no idea why they didn't
put this in the standard.

A nice extension would be for main to throw exceptions. Maybe if there
were some protocol where the shell could pass a list of possible
exceptions to main, then main could throw back one of these.

Then if we can have main accept std::string, all the better.

--
------------
Siemel Naran


Sent via Deja.com
http://www.deja.com/

Ken Bloom

unread,
Dec 16, 2000, 6:57:48 AM12/16/00
to
> 1) try, catch, finally
> ==========================
I like this idea. It would cut down source code bloat, and maybe object code
bloat. It would be so much easier to maintain code.

> 2) Empty Member Optimization
> ==========================

This could get too confusing and risky to bother with.

> 3) Allow classes with constructors/destructors as members of unions.
> ==========================

The thing with unions is that you can change one element by changing another
element. C'tors/D'tors would get in the way.

> 4) Property-like methods.
> ==========================
I happen to like get/sets. I wish that MSVC++'s #import directive would
automatically create get/sets for ActiveX objects, rather than creating
assignable properties. I dislike properties, but I like the concept of
property pages, perhaps that could be easily combined with get/sets like:
_propertyelement("Name",void setName (string),string getName(void));
this would add the property to a list, but not generate variable-like
things.
(this would, of course be entirely a compiler extension, and could never be
adopted into the ISO standard as it stands today.)

>
> 5) typeof() operator.
> ==========================
I like this idea, too, but the idea variable::subtype is too visually
confusing to anyone trying to read the code.

> 6) outer type for nested classes.
> ==========================

Huh? Are you suggesting that a line `typedef C this_t;' be automatically
parsed for each class `C'? Is that what you're saying? Please clarify.

> 7) Loop Labels
> ==========================
Hmmm. Currently you can do this with exceptions, but it's ugly. I like
things that make code somewhat easier to read.


> 9) More operators.
> ==========================
<=> and ~= are both nice, but I don't see any real need for the others. <=>
could be the basis for <, >, >=, <=, ==, and !=.
A good additional thing to consider here would be making dynamic_cast<>
overridable for smart pointer classes.

> 10) Pick Any functions and data
> ==========================

You would have to make sure that all definitions were the same.


I would like to add to this:
13) Overloadable dynamic_cast<>
==========================
I have seen the my_dynamic_cast<> and my_dynamic_caster<> code before, but
it would be much prettier if dynamic_cast<> could be overloaded for smart
pointer classes instead of having to write special classes and functions to
do it for you. And I should be able to do it in one function, not a function
and a class like I have to with my_dynamic_cast<>, now.


--
Ken Bloom

-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS/M/AT/U d- s++:--- a--- C++ UL P++ L+ E----
W+++ N++ ?o ?K w++ !O M++>$ V- PS PE Y-- PGP- t+
5 X++ R--- tv-- b++ DI+ D-- G e- !h r--@ y?
------END GEEK CODE BLOCK------

Ron Natalie

unread,
Dec 16, 2000, 2:21:51 PM12/16/00
to

Ben Liddicott wrote:

> 3) Allow classes with constructors/destructors as members of unions.
> ==========================
>
> Classes with constructors or destructors are not allowed as members of
> unions.
>
> This is a no brainer really. Of course there is no way for the compiler to
> know which to call, and when. But if the developer is prepared to take
> responsibility for calling the correct constructors and destructors at the
> right time, there is no reason to prevent them.

You can't call constructors. If you were going to call some member function
with constructor like semantics, you can do it now and put it in a union.
I'm not clear what this solves that you couldn't do anyhow.

>
> 5) typeof() operator.
> ==========================
>
> This is analogous to the sizeof() operator, but yields the type of the
> expression (without evaluating it).
>

Amen.

> 7) Loop Labels
> ==========================
>
> As in perl and Java, loop labels would allow more flexible use of break
> and continue, and have the added advantages of documenting the programmers
> intention when breaking from a loop, and prevent an inner loop, added
> later, from unexpectedly breaking the program.

Puke. Can you say "structured code." I knew you could. What does this
provide
that GOTO couldn't do with just as much ugliness?

>
> 9) More operators.
> ==========================
>
> Why stick with those boring old C style operators? What about:
> <=> comparison. Returns signed result (so 0 means equal).

operator-

> <- Can't be done. Ambiguous with less-than followed by unary-minus.

As long as you don't put a member name on the left side :-)

> 10) Pick Any functions and data
> ==========================
>
> The pickany attribute is applied to a function or static data to inform
> the linker that any instance will do, and it should not die if it finds
> multiple definitions (though it should ensure that only one is linked
> into the final object).

Yuck.

>
> Support for the principle is required by compilers in any case, to support
> inline functions that are not actually inlined, and static member data for
> template instantiations.

Actually not. Most compilers just define an internal linkage function for
the non-inlinable inline case. I'm not sure what you mean by static member
data for templates. You have to define that just like anything else.

>
> 11) Covariant out parameters


>
>
> Ordinarily this is forbidden, of course, even though it is entirely safe.
> It is safe because the programmer knows that the value of rpA is ignored
> on entry, and recieves a class derived from A.

Huh? It looks like a very eloborate way to do the samething as static_cast
which is not typesafe in general. You're upcasting from a base class to a
derived and you don't know the type is compatbile.

> b) Endianism macros for reading from/writing to streams intended for other
> architectures. These should deal with unsigned integral types of size
> 1, 2, 4, and 8 bytes, as well as doubles and floats.
>
> Define
> CHANGEENDIANISM_QWORD()
> CHANGEENDIANISM_DWORD()

If you want to define 1, 2, 4, and 8 byte-handling macros, I encourage
you to use those numbers in your macro names. WORD/DWORD/QWORD isn't
anymore meaning ful that "int". It's only lameness that pegs WORD at 16
anyhow.

Risto Lankinen

unread,
Dec 16, 2000, 2:24:01 PM12/16/00
to
Hi!

Nick Thurn <ni...@kipling.aus.deuba.com> wrote in message
news:91bjct$fuh$2...@kilmer.bain.oz.au...


> (Silly) Yes we need operators :-) and

> Non-standarized versions of these are everywhere.

This reminds me of a silly anecdote...

Recently in my career I have worked for a large database company
where my duties included writing a parser for a language that mixed
elements of Java and SQL.

At one time I added a grammar rule for testing purposes where the
smileyface :-) was an alternative token to the statement delimiting
semicolon, and whose purpose was to print out the parsed image
of that statement to the debug output, instead of executing it.

Thus, this was a legal statement in my private debugging version of
the language:

system.out.println( "Hello, World!" ) :-)

... which, when executed, would print itself to the debug output.

Cheers!

- Risto -

Andrei Alexandrescu

unread,
Dec 17, 2000, 2:36:56 PM12/17/00
to
"Joseph Gottman" <joego...@worldnet.att.net> wrote in message
news:hCf_5.17487$Ei1.1...@bgtnsc05-news.ops.worldnet.att.net...

> If you have an object of type polynomial<X>, it might still make
> sense to evaluate it at a point of some other type, for instance
> polynomial<int> f; file://f (x) = x^2 + x + 1

> f(0.5) // Evaluate at a double, result = 1.75 is of type double
> polynomial<double> g; file://g(x) = x + .5;

> g(1); // Evaluate at an int, result = 1.5 is of type double.
>
> The problem is how would you declare operator()() in this case? Using
> typeof would make it easy:
> template <class X> class polynomial
> {
> ....
> template <class Y> typeof (X() * Y()) operator()(Y value) // Return type
of
> an X multiplied by a Y.
> };
>
> Without typeof, I can't see any way to get this function to always return
> the correct type.

You can with traits :o). You will have to write a trait specialization for
all types :o(.

template <class T, class U>
struct ProductType;

template <>
struct ProductType<T, T>
{
typedef T Result;
};

template <>
struct ProductType<char, int>
{
typedef int Result;
};

...

If you already have access to some generic type traits (see boost.org) you
can simplify your work.


Andrei

Dennis Yelle

unread,
Dec 17, 2000, 8:19:29 PM12/17/00
to
Ken Bloom wrote:
[...]

[ context added by Dennis Yelle ]
// v is some kind of vector
// but the code below will not compile:
for( v::iterator i = v.begin(); i != v.end(); ++i) {
// do something
}

> > 5) typeof() operator.
> > ==========================
> I like this idea, too, but the idea variable::subtype is too visually
> confusing to anyone trying to read the code.

Confusing? What is confusing about it?
It seems very natural to me.

Dennis Yelle
--
I am a computer programmer and I am looking for a job.
There is a link to my resume here:
http://table.jps.net/~vert/

Ben Liddicott

unread,
Dec 18, 2000, 5:05:30 AM12/18/00
to

"Ken Bloom" <ken...@bigfoot.com> wrote in message
news:91f4ig$shl$1...@slb6.atl.mindspring.net...

> > 4) Property-like methods.
> > ==========================
> I happen to like get/sets. I wish that MSVC++'s #import directive would
> automatically create get/sets for ActiveX objects, rather than creating
> assignable properties.

Actually, it does. By default they are called get_XXX and put_XX or
putref_XXX.

> I dislike properties, but I like the concept of
> property pages, perhaps that could be easily combined with get/sets
like:
> _propertyelement("Name",void setName (string),string getName(void));
> this would add the property to a list, but not generate variable-like
> things.
> (this would, of course be entirely a compiler extension, and could never
be
> adopted into the ISO standard as it stands today.)

> > 5) typeof() operator.
> > ==========================
> I like this idea, too, but the idea variable::subtype is too visually
> confusing to anyone trying to read the code.

There is possible scope for clashes when mixing type and variable
namespaces.

> > 6) outer type for nested classes.
> > ==========================
> Huh? Are you suggesting that a line `typedef C this_t;' be automatically
> parsed for each class `C'? Is that what you're saying? Please clarify.

Yes.

> > 9) More operators.
> > ==========================
> <=> and ~= are both nice, but I don't see any real need for the others.
<=>
> could be the basis for <, >, >=, <=, ==, and !=.
> A good additional thing to consider here would be making dynamic_cast<>
> overridable for smart pointer classes.

You can do this with user_cast<>.
template<class TO, class FROM> user_cast(FROM from){return
dynamic_cast<TO>(from););

This makes user_cast the same as dynamic_cast, unless it is specialised.


> > 10) Pick Any functions and data
> > ==========================
> You would have to make sure that all definitions were the same.

Indeed.

> I would like to add to this:
> 13) Overloadable dynamic_cast<>
> ==========================
> I have seen the my_dynamic_cast<> and my_dynamic_caster<> code before,
but
> it would be much prettier if dynamic_cast<> could be overloaded for
smart
> pointer classes instead of having to write special classes and functions
to
> do it for you. And I should be able to do it in one function, not a
function
> and a class like I have to with my_dynamic_cast<>, now.

It would be nice to have something in this area that was standard, to be
sure.

Cheers,
Ben Liddicott

Ben Liddicott

unread,
Dec 18, 2000, 5:06:14 AM12/18/00
to

"Joseph Gottman" <joego...@worldnet.att.net> wrote in message
news:hCf_5.17487$Ei1.1...@bgtnsc05-news.ops.worldnet.att.net...
>
> typeof would be even more useful when combined with templates. For
> instance, suppose you have a template class for polynomials. One
obvious
> member function would be operator()(), to evaluate the polynomial at a
> point. If you have an object of type polynomial<X>, it might still make
> sense to evaluate it at a point of some other type, for instance
> polynomial<int> f; //f (x) = x^2 + x + 1
> f(0.5) // Evaluate at a double, result = 1.75 is of type double
> polynomial<double> g; //g(x) = x + .5;
> g(1); // Evaluate at an int, result = 1.5 is of type double.
>
> The problem is how would you declare operator()() in this case? Using
> typeof would make it easy:
> template <class X> class polynomial
> {
> ....
> template <class Y> typeof (X() * Y()) operator()(Y value) // Return type
of
> an X multiplied by a Y.
> };
>
> Without typeof, I can't see any way to get this function to always
return
> the correct type.

That is a much more useful example than the one I gave.

Cheers,
Ben Liddicott

Robert O'Dowd

unread,
Dec 18, 2000, 7:46:55 AM12/18/00
to
Ben Liddicott wrote:
> [Snip]
2
> 1) try, catch, finally
> ==========================
>
>[Snip]

>
> The point being that the finally block is executed either after the end of
> the try block (if it exits normally), when the try block throws (if the
> exception is not caught by any catch handler in the same
> try..catch..finally
> block), at the end of the catch block (if a catch block exits normally) or
> when a catch block throws, which is the only case left.
>
> This to me is one of the single most egregiously missing items on the
> list.

I disagree. You suggested some ways of doing the same thing. It can
also be done with nested try/catch blocks.

try
{
//
try
{
if (SomeCondition)
throw Something;
else
throw SomethingElse;
}
catch (Something &)
{
// may or may not throw an exception
}
}
catch(...)
{
final_cleanup();
throw;
}
final_cleanup();


Since the code in finally blocks would usually not throw exceptions,
the above achieves the same thing.

>
> 2) Empty Member Optimization
> ==========================
>
> This is like the empty base optimization, but for members too!
>
> Many C++ classes are used purely for the destruction sematics they have,
> e.g., auto_ptr. Some are occasionally used for destruction semantics that
> are entirely independent of any data, for example to log the lifetimes of
> objects to cerr, or to maintain counts of class types, in which case they
> would output only their "this" pointer.
>
> Objects allocated with new would stil have sizeof(T)>=1, of course.
>
> The only problem this might cause would be that such members would not
> have unique "this" pointers. This matters only if they rely on the
> uniqueness of their "this" pointer, in which case the workaround is to add
> an unused data member, e.g., "char unused;"

Yikes. So you're proposing that we have an object of size zero, unless
it
is allocated with operator new? That would mean information would need
to
be maintained with every object recording whether it was created with
operator new. That bookkeeping would sort of negate the benefits of
this
optimisation.

>
> 3) Allow classes with constructors/destructors as members of unions.
> ==========================
>
> Classes with constructors or destructors are not allowed as members of
> unions.
>
> This is a no brainer really. Of course there is no way for the compiler to
> know which to call, and when. But if the developer is prepared to take
> responsibility for calling the correct constructors and destructors at the
> right time, there is no reason to prevent them.

Except for the issue that constructors can not be called (except as part
of initialiser list from derived class constructors, although "call"
is probably not the right word).

>
> 4) Property-like methods.
> ==========================
>
> These are implemented in a number of compilers as optional extensions,
> e.g.,
> MSVC, Borland, Cormeu (with MS extensions turned on).
>

[Snip]


>
> This of course gives you nothing but syntactic sugar -- everything can be
> done another way (by calling the set/get functions). But then the same
> criticism applies to the whole mechanism of overloading arithmetic and
> assignment operators. Syntactic prettiness is a worthwhile secondary goal.

I agree with this one, although it can be done within the language now
in many ways.

>
> 5) typeof() operator.
> ==========================
>
> This is analogous to the sizeof() operator, but yields the type of the
> expression (without evaluating it).
>
> Example:
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(typeof(v)::iterator it = v.begin(); it != v.end(); it++)
> SomeAction(*it);
>
> Clearly you can achieve this with a typedef as well, but so what?
>
> When I was a novice, I naively assumed you could use :: to retrieve the
> type of a variable (because there was no reason why not):
> vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> for(v::iterator it = v.begin(); it != v.end(); it++) SomeAction(*it);
>
> I still think this makes sense, and is even more natural than typeof.
> After all, the compiler knows the type, so why shouldn't it tell you?

I also agree with this. There are cases (eg when reusing a third party
library, macro expansions) when relying on a typedef is only part of
the answer.

>
> 6) outer type for nested classes.
> ==========================
>
> Example:
> struct A
> {
> struct B
> {
> };
> };
>
> B::outer should refer to A. Clearly this can be done by putting a line:
> typedef A outer; in B's definition. Also clearly B can (itself) access
> things such as typedefs and statics from A without any rigmarole.

I may be slow, but fail to see that this gives you that the typedef does
not. Particularly since you are proposing a new keyword to give it to
you.

>
> 7) Loop Labels
> ==========================
>
> As in perl and Java, loop labels would allow more flexible use of break
> and continue, and have the added advantages of documenting the programmers
> intention when breaking from a loop, and prevent an inner loop, added
> later, from unexpectedly breaking the program. They would also allow a
> programmer to break out of a loop from within a switch statement, which is
> a virtue in itself.

Possibly. To me it's just a goto by another name. While I don't
believe goto's are inherently evil, I also don't believe we need more
than one way of achieving the same thing.

>
> 8) Function Forwarding.
> ==========================
>
> This would enable "Smart references" with much reduced wear and tear on
> the fingertips.
>
> There is no way to inherit from a reference or a simple type. Or rather,
> you can inherit from a class that wraps a simple type, and it is
> straightforward enought to generate template wrappers that work for
> all simple types and for pointers.
>
> However there is no way to override the dot. This may seem trivial
> requirement, but it is all about function forwarding, which is commonly
> done (though you may think it should not be).
>
> Example:
>
> struct A
> {
> aMethod();
> };
>
> struct B : public using A&
> {
> A* mA;
> operator A& () {return *mA;};
> };
>
> B b;
> b.aMethod(); // calls b.operator A&().aMethod();

It looks to me like you're asking for delegation. I agree that
a scheme for delegation would be a useful addition. I don't like
the method you propose. Also, delegation is something that
can be done within the current language, just not as easily as
it could be.

>
> 9) More operators.
> ==========================
>
> Why stick with those boring old C style operators? What about:
> <=> comparison. Returns signed result (so 0 means equal).

operator!= or operator- ?

> ~= like. Floating point numbers are similar. Overridable to do pattern
> matching for strings.

Problem is that you need to specify what operator~ does for various
types.


>
> 10) Pick Any functions and data
> ==========================
>
> The pickany attribute is applied to a function or static data to inform
> the linker that any instance will do, and it should not die if it finds
> multiple definitions (though it should ensure that only one is linked
> into the final object).
>
> Support for the principle is required by compilers in any case, to support
> inline functions that are not actually inlined, and static member data for
> template instantiations.

This tends to be handled now via compiler or linker options. I fail to
see
how putting it into the language will help.


>
> 11) Covariant out parameters
> ==========================
>
> This is really two extensions.
>
> The first is "out" parameters to functions. An out parameter is a pointer
> (or reference), with semantics such that the initial value of the
> pointed-to (or referenced) object is ignored.
>
> Rather than create a new keyword "out" (which is used for a lot of things
> now), "return" could be overloaded.
>

[Snip]


>
> Ordinarily this is forbidden, of course, even though it is entirely safe.

I fail to see how it is safe, unless your compiler is psychic and can
work out the situations in which the called function returns one type
of the other.


> It is safe because the programmer knows that the value of rpA is ignored
> on entry, and recieves a class derived from A.

What about little things like object slicing?

>
> 12) And some more gubbins.
> ==========================
>
> There are a large number of things I would like to see standardized which
> don't count as language extensions.
>
> a) Sized integers.
>
> In my opinion the original choice not to standardize the sizes of integer
> types is an evil one. Yes, if you want sized integers, you can define them
> in a platform specific header file:
> #define _int8 char
> #define _int16 short
> #define _int32 long
> #define _int64 long long // long long not a standard in C++. What aboutn
> C9X?
> // they are defines not typedefs to support unsigned _int32 etc.
>
> And sure enough, this is what people seem to do. All the time. In any
> non-trivial project. Some use defines, some use typedefs, but they are all
> getting at the same thing: They want to know how big their integers are.
>
> And don't say it isn't a choice: One could implement it the other way
> around:
> #define char _int8
> #define short _int16
> #define long _int32
>
> Or rather one could if there wasn't the problem with separate overloads
> for long and int (they being the same size on many platforms).

Possibly. C99 does something like this already. Personally I don't
like
what C99 does, but I'd say it's possible that C++ will follow suit.

>
> b) Endianism macros for reading from/writing to streams intended for other
> architectures. These should deal with unsigned integral types of size
> 1, 2, 4, and 8 bytes, as well as doubles and floats.
>
> Define
> CHANGEENDIANISM_QWORD()
> CHANGEENDIANISM_DWORD()
> etc
> and
> MACHINETOBIGENDIAN_QWORD()
> MACHINETOBIGENDIAN_DWORD
> MACHINETOBIGENDIAN_WORD
> MACHINETOBIGENDIAN_BYTE //obviously a nop.
> and
> MACHINETOLITTLEENDIAN_QWORD etc.
>
> Of course, you can write a complete set of them yourself in half a day or
> so, but why should you have to?

Mainly because endianism (as you call it) is only an issue if you're
writing distributed applications, or ones that rely on data files
in a particular binary format. And because it is inadequate when
you start looking at representation of things like floating point.

>
> c) More control over inlining.
>
> I would suggest:
> forceinline Always inlined unless it is impossible to do so. Use
> programmer's judgement.
> inline Suggest inline. (Use compiler's judgement)
> Not inlined
> Then provide levels, such as inline1, inline2 to inline9.
> And set options: inline_levels(1,3) would map inline1 to forceinline,
> inline2 and inline3 to inline and the others to pickany, avoiding linker
> errors (see above). This can be implemented today as macros (degrading
> pickany to inline), but it would be nice to have a standard.

Since compilers can usually do a better job of this than a programmer,
I fail to see the benefit. After all, the benefits of inlining
tend to be related to capabilities of underlying hardware or
operating system. And compilers tend to be written to take those
into account.

>
> d) Standardized compiler options.
>
> So you don't have to learn multiple sets.
>
> e) Standardized compiler errors and warnings.
>
> So you don't have to learn multiple sets.

Possibly a point. But I'll bet that getting consensus will be a
chore, assuming it's possible to make a case for specifying this
in the language.

>
> f) The ablility to turn non-ansi features on and off one at a time.
>
> How about it Microsoft? I don't want your old fashioned loop semantics,
> but I sure like that _declspec(property) and C9X style struct hack!

Most compilers provide something like this anyway.

>
> g) Oh, yes:
>
> void main() // This should be allowed.
>
> Who are these self appointed language police who care enough to correct
> posters about this? If the program doesn't have a meaningful return value,
> then the compiler should return rubbish, or zero! The only tool I care
> about that uses a return value is find (and test, of course, has a return
> value that is meaningful to the shell).
>

Language police? People who pick people up on this tend to care
about program portability. I'm sure they will be quite happy if
this sort of thing is standardised. Of course, that will need
to happen in the C standard as well.....

Ben Liddicott

unread,
Dec 18, 2000, 7:51:07 AM12/18/00
to

"RCN News Server" <mh...@acm.org> wrote in message
news:91dlhn$1r7$1...@bob.news.rcn.net...

> Before I add my comments to this wish list of new C++ extensions, let me
say
> my *absolute, most desired wish* is to be able to use a C++ compiler
that
> implements fully and correctly the current standard we have (and a close
> second wish is to have *all* the C++ compilers meet this first wish so
my
> code can portably move between platforms (with great care given to not
using
> anything specific to a platform, of course). My third wish would be to
have
> a standard class library that included the same functionality as the
Java
> class libraries, in particular, standard database access, network
access,
> and (the real hard one) GUI access. If we had all three of the above
wishes
> granted I think we would be too busy writing C++ applications instead of
> learning Java and coming of with language extensions.

I don't believe in portability as a language aim. If you are using
anything at all that interacts with the outside world (disk IO over cin,
cout and cerr, sockets etc) you are already outside the scope of C++.

> "Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
> news:976747071.14502.1...@news.demon.co.uk...
> > 1) try, catch, finally
> > ==========================
> This wouldn't be my top priority for the reasons you describe below,
i.e.
> there are auto_ptr like alternatives (see boost.org for their scoped
class),
> although not as elegantly.

But they are not in the standard.

> > 3) Allow classes with constructors/destructors as members of unions.
> > ==========================

> I think there's enough ways in C++ for a programmers to hang themselves
that
> we don't need another.

That's the other point of view, of course.

Mine is "More rope! More rope! I can't get enough of that rope!"

> > 4) Property-like methods.
> > ==========================


> I've tried to do the same and come reasonably close that I don't think
I'd
> need a language extension to be happy. I'd rather see any extensions go
> into the functionality of templates, which would be more general
purpose.

I'm curious to know what extensions to templates you'd suggest for this
problem. (Other than 2 above and 8 below).

> > 5) typeof() operator.
> See the CUJ article about a "portable typeof()" operator in the Nov 2000
> issue (although I don't think it would do what you describe below
(that's
> why it's "mostly"

Seen it. Liked it. Only problem is you have to declare every class that
you want to be able to use typeof on. This makes typedefs or traits
classes a superior solution to that particular implementation.


> > 9) More operators.
> > ==========================
> I think you're bucking the trends here. Java eliminated them. C#
reduced
> the number you can play with. And you want to add to them!?! Good luck
on
> getting this one adopted.

Java and C# made a mistake. They don't have predictable destruction
either, so I wouldn't see them as be be-all and end-all.

If I did, I would use them instead.

> Actually, I like defining my own implementation of operators for a
class.
> I'd take this extension one step further and allow the programmer to
define
> their own unary, binary, and tertiary operators, e.g.
>
> int operator mod(int lhs, int rhs);
> int operator "<==>" (int lhs, int rhs); // Because I arbitrarily
> prefer <==> to <=>
>
> At least one problem with this would be how do you specify the operator
> precedence. Of course this extension has even less chance of making it
into
> the standard than yours does :-(.

Curiously I have developed a way to define unary and binary operators in
C++. It's nasty, but it works:

(4 * cosine 1.23) + (3.5 raised_to 5.8)

does what you'd expect.


> > 11) Covariant out parameters
> > ==========================

> Why would this have to be restricted to output parameters? It seems


like
> any reference/pointer parameter regardless of whether it's used as input
or
> output could be used. Maybe we could bring back the deprecated (and
since
> obsolete?) overload keyword (or was it override?).

It's only necessary on output parameters. Input parameters (p&, p*const
etc) work already.


> > 12) And some more gubbins.
> > ==========================
> >

> > a) Sized integers.


> I think C9X has some extensive changes in this area and I'd suspect C++
will
> eventually adopt them. In CUJ they're talking about the C9X standard.

Cool.


> > d) Standardized compiler options.
>
> Good luck on this one ;-). I'd like to see it to for at least some
simple
> ones:

(good suggestions deleted)

Of course they would have to be selected so as not to clash with existing
options, and this means using long names:
-CLCM-optimization-speed
etc.

Of course this could be done with a Perl compiler driver.

> Along the same lines and also a solution for c) would be to have a
standard
> set of #pragma's (what an oxymoron, but ...). One I could think of and
> related to this extension would be:

I'm with you on this.

> > e) Standardized compiler errors and warnings.
> Another good luck! ;-)

Of course, this could be done with a Perl compiler driver. :-)

> > g) Oh, yes:
> >
> > void main() // This should be allowed.
>
> Since your allowed to have a control path that doesn't have a "return
val",
> what's the big deal?

Well, that's evil too.

> Now for my Christmas extension: I'd like the RTTI to be extended to
include
> the introspection capabilities of Java (to as great a degree as
possible),
> e.g.
>
> class std::type_info
> {
> public:
> // The stuff it already has, plus:
> const char *full_name() const; // Returns fully-elaborated, human
> readable name
> // including all
> namespaces and nested classes
> // separated via
> "::". This method could be added
> // or name()
could
> be specified to return this
> // string.

Some compilers provide this, notably MSVC++.

All looks quite reasonable to me. Have you seen .NET?

Cheers,
Ben Liddicott

Ben Liddicott

unread,
Dec 18, 2000, 12:46:22 PM12/18/00
to

<sieme...@my-deja.com> wrote in message
news:91f69q$ef8$1...@nnrp1.deja.com...

> > 1) try, catch, finally
> > ==========================
>

> So what's wrong with the C++ way? Maybe that it leads to code that is
> longer to write/read, because you have to define a new
> auto_free_resource class for every usage?

(deleted three suggestions on how to do this)


Yes, of course you could. The point is to avoid having to create a special
class just to match the particular and possibly unusual disposal semantics
of a particular variable in a particular function.

The point is that it is more natural to do it this way.

> Also, if we somehow had the feature of a local class being able to
> access local variables then we could just make a local sentry class
> that cleans up,
> Thing * thing=new Thing;
> struct Cleanup { ~Cleanup() { delete thing; } } cleanup_;
> ...
>
> And if we had unnamed variables, all the better
> Thing * thing=new Thing;
> struct { ~() { delete thing; } };
> ...

Also interesting ideas. The first had occured to me (it is like closures
in lisp). The second had not.

> > 2) Empty Member Optimization
> > ==========================
> >
> > This is like the empty base optimization, but for members too!

(...)


>
>
> I don't see what you're talking about.
>
>
> > 3) Allow classes with constructors/destructors as members of unions.
> > ==========================
> >
> > Classes with constructors or destructors are not allowed as members of
> > unions.
> >
> > This is a no brainer really. Of course there is no way for the
> compiler to
> > know which to call, and when. But if the developer is prepared to take
> > responsibility for calling the correct constructors and destructors
> at the
> > right time, there is no reason to prevent them.
>
> Yes sure, they could call the right constructor.
> But how to call the right copy constructor and op=?
> And how to call the right destructor?

The compiler would call the user-defined copy ctor for the union, or a
bitwise one. As I said, the destructor would be the responsibility of the
programmer.

As it stands, to put a class with a constructor into a union, you have to
define an equivalent class with the same data members but no constructor
and put that into the union, then make the original class inherit from
that. Then provide cleanup in member functions called from the derived
class.

> The only extension I see is to allow user types with trivial copy ctor,
> op=, dtor to be part of a union. At present, only fundamental types
> can be members.

Are you sure?

> Normally, if you find yourself using unions a lot, then it's time to
> switch to the base class derived classes concept.

I disagree. You can have arrays of unions. With base/derived, you have to
allocate memory for each individual object, which has a performance hit.

> > 4) Property-like methods.
> > ==========================


> >
> > This of course gives you nothing but syntactic sugar -- everything
> can be
> > done another way (by calling the set/get functions). But then the same
> > criticism applies to the whole mechanism of overloading arithmetic and
> > assignment operators. Syntactic prettiness is a worthwhile secondary
> goal.
>
> You got your template class, so why do you need a language extension?
> Besides, a good optimizer will treat CProp<short> instances as if they
> were short instances, and so there will be no overhead. This
> optimization happens so long as all the members of CProp are inline.

Sure.

But the template class will only work well with both the empty-member
optimization (2 above) and function forwarding (8 below).

> > 5) typeof() operator.
> > ==========================
> >
> > This is analogous to the sizeof() operator, but yields the type of the
> > expression (without evaluating it).
> >
> > Example:
> > vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> > for(typeof(v)::iterator it = v.begin(); it != v.end(); it++)
> > SomeAction(*it);
> >
> > Clearly you can achieve this with a typedef as well, but so what?
> >
> > When I was a novice, I naively assumed you could use :: to retrieve
> the
> > type of a variable (because there was no reason why not):
> > vector<mytemplate<short, short, int, long, myclass<long>*>> v;
> > for(v::iterator it = v.begin(); it != v.end(); it++) SomeAction(*it);
> >
> > I still think this makes sense, and is even more natural than typeof.
> > After all, the compiler knows the type, so why shouldn't it tell you?
>
> Fine. But what big problems does it solve? For iterator, you could
> very well use typedef typename Container::const_iterator Iter.

Except that in this case it is


vector<mytemplate<short, short, int, long,

myclass<long>*>>::const_iterator.
Which is precisely the problem that I intended to solve.

Other posters have also pointed out more substantial problems that would
be solved by typeof.

> > 6) outer type for nested classes.
> > ==========================

> Don't use macros, especially the ones like you have. Maybe in the end
> Linux will outdo Microsoft and we won't have to deal with these
> clever 'features' of Microsoft :).

Which in fairness were created when C++ was young.

> But we'd have the same problem even if we use templates -- namely that
> the inner class does not have a builtin typedef to name the outer
> class. It's a nice feature, but what big problem does it solve?

The problem I described.

> Another one you forgot is an automatic typedef in the derived class for
> the base classes. I came up with this --
>
> class Derived :
> public base=std::unary_function<char,char>,
> public base2=Junk<Derived>

But what problem would that solve?

> > 7) Loop Labels
> > ==========================


>
> Looks like it could be useful.
>
> But why not just use goto for break?

Because you need three labels.

> And maybe remove continue from the language?

I like continue. It cuts down on the levels of indentation.


> > 9) More operators.
> > ==========================
> >
> > Why stick with those boring old C style operators? What about:
> > <=> comparison. Returns signed result (so 0 means equal).
> > ~= like. Floating point numbers are similar. Overridable to do
> pattern
> > matching for strings.
> > <- Can't be done. Ambiguous with less-than followed by unary-
> minus.
> > &>,&, *>, *<, +<, +>, -<
> > Surely someone can think of something to do with these?
>
> We have too many operators already. Just think of the burden on
> someone to learn all of these.
>
> Maybe we could change the editor so that we can draw integral signs and
> treble clefs, and overload these too :).

This is the frivolous one. The others are trivial :-).

> > 10) Pick Any functions and data
> > ==========================

> Well, what if not any will do? What if the different objects are
> indeed different.

Undefined behavior.

> Besides, in the purest and best of all possible worlds, you won't get
> this problem of multiple objects.

When we live there, I'll withdraw the suggestion.

> Tell your compiler vendor to supply this option, to give an error if
> the objects are actually different and to do nothing if they are the
> same. Be prepared that if your program outputs the address of the
> object your program behaviour is unpredictable. Finally, linker
> options have nothing to do with C++.

My compiler (MSVC++) does provide this option. It is in fact where I got
the idea.

> > 11) Covariant out parameters
> > ==========================

> What happens here?
> A * pA;
> ...
> x.GetAnA(pA);

Sorry, typo. This is of course:

pX->GetAnA(pA);

On return pA contains a pointer to a B, which is fine since B derives from
A.

> > 12) And some more gubbins.
> > ==========================
> >
> > There are a large number of things I would like to see standardized
> which
> > don't count as language extensions.
> >
> > a) Sized integers.
>

> This one I like.
>
> Also good is numbers with underscores like "double x=123_456.45;".

That I like.

> > d) Standardized compiler options.
> >
> > So you don't have to learn multiple sets.
>
> Standardizing also reduces the options available in the future. That
> is, we lose experiments that compiler-vendors might try because now
> they must all do the same thing.

Not at all. I only suggest an alternate set of standardized options which
can be used in parallel to the existing ones. This could of course be
implemented with a compiler driver written in Perl or some such.


> > f) The ablility to turn non-ansi features on and off one at a time.
> >
> > How about it Microsoft? I don't want your old fashioned loop
> semantics,
> > but I sure like that _declspec(property) and C9X style struct hack!
>
> Get a compiler that does this.

Moolah.


Cheers,
Ben Liddicott

Ben Liddicott

unread,
Dec 18, 2000, 12:47:04 PM12/18/00
to

"tom" <the...@my-deja.com> wrote in message
news:Voyager.0012141...@administrator.co.uk...

> Previously, Ben Liddicott wrote in comp.lang.c++.moderated:
> > Since it is nearly the holidays, here is a trivial and frivolous post.
>
> I'll comment on some of your ideas.
>
> > 1) try, catch, finally
> > ==========================
>
> > This to me is one of the single most egregiously missing items on the
> > list.
>
> Agreed, although libraries being written for boost will largely remove
> the need for this using features already in the language - preferable.

I am not familiar with these libraries, so I can't comment. However it
does seem strange that they are only now "being written". Perhaps if they
were in std:: I woudl be satisfied. Nonstandard external libraries by
definition don't fit the bill however.


> > 3) Allow classes with constructors/destructors as members of unions.
> > ==========================
> >
> > Classes with constructors or destructors are not allowed as members of
> > unions.

(...)


> Unfortunately the language doesn't have any facilities at present for
the
> user to call a constructor. But how about:

(demo of placement new deleted)

If placement new is not "the ability to call a constructor" then I don't
know what is. It is what I meant, at any rate.

>
> If that's what you want, then the language is already up to it I think.

No, the standard explicitly forbids members of unions from having
constructors or destructors.

> > 5) typeof() operator.
> > ==========================


>
> I like this one - it can save an enormous amount of typing (forgive the
pun).

I expect this one to be the most popular, if only because I have seen
posters supporting it in this NG.


> > 6) outer type for nested classes.
> > ==========================

> Not useful enough to be worth it. The typedef does it, and introducing
> new keywords is undesirable.

Quite possibly. This one is quite weak.


> > 7) Loop Labels
> > ==========================


>
> Hmm, not sure about this one. I would make some code more concise, and
> perhaps more obvious too.

In practice that is what I do. However I sometimes seem to do it purely to
avoid this problem, and not because it is more obvious or natural. In
other words I feel I am programming around this shortcoming.


> > 8) Function Forwarding.
> > ==========================
> >
> > This would enable "Smart references" with much reduced wear and tear
on
> > the fingertips.
>
> What's wrong with smart pointers?

If you inherit from them, you don't get all the methods of the pointed to
object, only operator->.


> > 9) More operators.
> > ==========================
> >
> > Why stick with those boring old C style operators? What about:

(some operators deleted)


>
> <=> and ~= might be nice. The rest would be pushing it though.

Quite so.

> > 10) Pick Any functions and data
> > ==========================

> This is an odd thing to want. Why do you want it? Do you want to put
> everything in headers or something? Most people are after the opposite -
export.

Putting everything in headers can be handy. Suppose you have a bunch of
classes with all inline functions, but some static data. Having to add a
CPP file just to contain one line declaring an int is silly, and makes it
more complicated to distribute your code.


> > 11) Covariant out parameters
> > ==========================
>
> This is actually conceptually wrong. You haven't thought it through.
>
>

> struct Z:X{
> virtual bool GetAnA(return C*& rpC);// overrides GetAnA(return A*&)
> };
>
> > int main()
> > {
> > B* pB=0;
> > Y y;
> > X* pX = &y;
> > pX->GetAnA(pB);
> C* pC=0;
> pX->GetAnA(pC);
> pC->do_it(); //boom, pC is actally a B

That won't work because pX is typed as an X, so passing a pC& is an error,
just as it is today.

Only the implementor of the function can say whether it is safe or not, so
that is why it is left in the class definition.

> >
> > Ordinarily this is forbidden, of course, even though it is entirely
safe.
>
> No it is not at all safe.

Ooooh yes it is! Look behind you!

> > It is safe because the programmer knows that the value of rpA is
ignored
> > on entry, and recieves a class derived from A.
>
> But it might receive a different class derived from A.

That's fine. Either the caller is calling through an X* and expecting an A
(or something -- anything -- derived therefrom), or he is calling through
a Y* and expecting a B, or through an Z* and expecting a C. In no case
will he be disapointed, unless he has previously done an invalid downcast.

> > 12) And some more gubbins.
> > ==========================
> >
> > There are a large number of things I would like to see standardized
which
> > don't count as language extensions.
> >
> > a) Sized integers.
>
> C99 has them already. C++ is sure to follow.

That's good to know

Cheers,
Ben Liddicott

Ben Liddicott

unread,
Dec 18, 2000, 12:47:48 PM12/18/00
to
"Ron Natalie" <r...@sensor.com> wrote in message
news:3A3A47FD...@sensor.com...

> Ben Liddicott wrote:
>
> > 3) Allow classes with constructors/destructors as members of unions.
> > ==========================
> You can't call constructors. If you were going to call some member
function
> with constructor like semantics, you can do it now and put it in a
union.
> I'm not clear what this solves that you couldn't do anyhow.

You can use placement new, which I think is close enough.

> > 5) typeof() operator.
> > ==========================
> > This is analogous to the sizeof() operator, but yields the type of the
> > expression (without evaluating it).
>
> Amen.
>
> > 7) Loop Labels
> > ==========================
> >

> Puke. Can you say "structured code." I knew you could. What does this
> provide
> that GOTO couldn't do with just as much ugliness?

It provides things that goto can with slightly less ugliness :-).

I like it.


> > 10) Pick Any functions and data
> > ==========================
> >
> > The pickany attribute is applied to a function or static data to
inform
> > the linker that any instance will do, and it should not die if it
finds
> > multiple definitions (though it should ensure that only one is linked
> > into the final object).
>
> Yuck.
>
> >
> > Support for the principle is required by compilers in any case, to
support
> > inline functions that are not actually inlined, and static member data
for
> > template instantiations.
>
> Actually not. Most compilers just define an internal linkage function
for
> the non-inlinable inline case. I'm not sure what you mean by static
member
> data for templates. You have to define that just like anything else.

That's just evil.

> > 11) Covariant out parameters
> >
> >
> > Ordinarily this is forbidden, of course, even though it is entirely
safe.
> > It is safe because the programmer knows that the value of rpA is
ignored
> > on entry, and recieves a class derived from A.
>
> Huh? It looks like a very eloborate way to do the samething as
static_cast
> which is not typesafe in general. You're upcasting from a base class to
a
> derived and you don't know the type is compatbile.

You are not upcasting because you are ignoring the value of the pointer on
input, and it is safe because you are replacing it with a new object who's
type you know.

It is a straightforward and typesafe way to do something that can only be
done otherwise using an elaborate set of inline functions and unsafe
static_casts.

> > b) Endianism macros for reading from/writing to streams (...)


> If you want to define 1, 2, 4, and 8 byte-handling macros, I encourage
> you to use those numbers in your macro names. WORD/DWORD/QWORD isn't
> anymore meaning ful that "int". It's only lameness that pegs WORD at 16
> anyhow.

Fair enough. Those were just the names I used because I wrote it on Win32.

alg...@my-deja.com

unread,
Dec 18, 2000, 3:28:27 PM12/18/00
to
In article <3A3A47FD...@sensor.com>,

Ron Natalie <r...@sensor.com> wrote:
> Ben Liddicott wrote:
> > 3) Allow classes with constructors/destructors as members of unions.
> > ==========================
>
> You can't call constructors.

Except via placement new. Or you could allow the union constructor's
initialiser list to invoke a member's constructor.

> If you were going to call some member function
> with constructor like semantics, you can do it now and put it in a
union.
> I'm not clear what this solves that you couldn't do anyhow.

Two separate issues.

(1) Classes with non-trivial default constructors, or destructors.
These are tricky in unions. Perhaps they should be supported - for
experts only. It would make it possible to use STL classes in unions.
No doubt some programmers would then deliberately wrap classes in
unions as a way of avoiding the default constructor overhead.

(2) Classes with trivial default constructors and no destructor. There
is no technical reason these should not be in unions, and it appears to
be an oversight in the C++ standard that they are not. It is quite
natural to have classes with non-default constructors - the builtin
types have non-default constructors, e.g. we can say
int n = 2;
The ability to initialise an int does not stop it being in a union and
nor should it stop a struct, when the common factor is that their
default initialisation is "don't care".

Wrapping data types in classes is useful a technique to re-engineering
C with C++. Existing C code may contain unions. C++ has unions. It
should not put obstacles in the way of using unions with specific
features of C++. It should not take the view that "unions are a C
feature, C++ should no more than tolerate them". Even in cases where
unions are used only for space reasons, the comment that "PCs have
128Mb these days" is frankly juvenile. Customers expect to see their
PC upgrades reflected in ability to handle larger workloads - not
absorbed by new bloat in our code. And who said PCs were the smallest
C++ target platforms around, anyway? As the Embedded C++ (and to some
extent C99) efforts show, C++ risks fragmentation if the standards
people ignore efficiency.


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

alg...@my-deja.com

unread,
Dec 18, 2000, 3:29:51 PM12/18/00
to
In article <3A3A47FD...@sensor.com>,
Ron Natalie <r...@sensor.com> wrote:
> Ben Liddicott wrote:
> > 3) Allow classes with
constructors/destructors as members of unions.
>
> You can't call constructors.

Well the initialiser list of a union's
constructor would be a place to "invoke" the
constructor of a member.

> If you were going to call some member function
> with constructor like semantics, you can do it
now and put it in a union.
> I'm not clear what this solves that you
couldn't do anyhow.

Let's separate two things here.

Having non-trivial default constructors, and
destructors, in a union, is tricky. These are
things that must do stuff. The compiler does not
know whether to do stuff because it does not know
whether the object is really there (i.e. the
union really has the type of a particular
variant). You could do this, but it would be a
dangerous technique. You would have to rely on
the programmer knowing what type the union had.
Of course, in many programs involving unions,
this is already done. This would be a necessity
for using STL types in unions.

On the other hand, there is _no_ reason why a
class with a trivial default constructor and
other constructors and no destructor should not
be a member of a union. Constructing an object
of the union type would simply call the union's
constructor (if any). If that wanted to invoke
the constructor of a particular member, it
could. The other members are default-constructed
trivially, which means they don't mind what data
they get.

Unions exist, they are part of C++, and used in
many C programs. The argument that "PCs have
128Mb these days" is frankly juvenile - even PC
customers expect program capacities to scale
accordingly, and to be able to upgrade their
computers to handle larger workloads, not to
handle our code becoming progressively more
bloated. And PCs are not the smallest things
around, not by a long way.

Having to replace unions, in the process of
reengineering C to C++, with something less
efficient, for no good technical reason, is not a
regression that can be justified.


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 18, 2000, 3:31:13 PM12/18/00
to
RCN News Server wrote:

> Before I add my comments to this wish list of new C++ extensions,
> let me say my *absolute, most desired wish* is to be able to use a
> C++ compiler that implements fully and correctly the current
> standard we have (and a close second wish is to have *all* the C++
> compilers meet this first wish so my code can portably move between
> platforms (with great care given to not using anything specific to a
> platform, of course). My third wish would be to have a standard
> class library that included the same functionality as the Java class
> libraries, in particular, standard database access, network access,
> and (the real hard one) GUI access. If we had all three of the
> above wishes granted I think we would be too busy writing C++
> applications instead of learning Java and coming of with language
> extensions.

I couldn't agree more.

[...]


> > 3) Allow classes with constructors/destructors as members of unions.
> > ==========================

> Since unions are mostly a memory saving technique and given that 128
> MB on a PC is not uncommon, this definitely wouldn't be on my list
> of gotta have extensions. The few times I've ever used unions,
> unions of PODs worked fine.

Unions can be a lot more than just memory saving techniques. Often,
the problem is more that you don't know how to construct any but one
of the members. The obvious solution is a union of pointers, but this
generally means allocating the actual element on the heap, with the
concomitant problem of where to delete it. My usual solution is to
derive all of the variants from a common base, then use a reference
counted pointer to the base, and some downcasting to get at the actual
type when I want to use it. Not a negligible amount of added
complexity.

> > Classes with constructors or destructors are not allowed as
> > members of unions.

> > This is a no brainer really. Of course there is no way for the
> > compiler to know which to call, and when. But if the developer is
> > prepared to take responsibility for calling the correct
> > constructors and destructors at the right time, there is no reason
> > to prevent them.

> I think there's enough ways in C++ for a programmers to hang
> themselves that we don't need another.

Agreed. This cannot be made to work with C-style unions. Think about
assignment, for example. If I have:

union U { A anA ; B aB ; } aU ;
// initialized with anA...
aU.aB = B() ;

What should happen in the assignment? The assignment operator for B
is fine if the union already contains a B, but since the union
contains an A, it cannot safely be called. What is needed is to
destruct the A, then copy construct the B. But this isn't the
semantics of assignment today, and of course, the compiler has no way
of knowing that it is an A that must be destructed, and not a B.

In order for this to work, to begin with, you need a discrimate union,
such as was proposed by the Australian delegation. I'm no longer
familiar with the original proposal, but basically, the union becomes
intelligent, with a discriminator to indicate what it actually does
contain, built-in member functions to intergate which field is active,
and throws an exception if the wrong field is accessed. This would
make assignment semantics possible, although Herb Sutter and Scott
Meyers will have fits, since the semantics are exactly the same as
those of the explicit delete/placement new assignment operator.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

James Kanze

unread,
Dec 18, 2000, 3:37:16 PM12/18/00
to
Ben Liddicott wrote:

I think that finally, here, would be in a nested try block.

> The point being that the finally block is executed either after the
> end of the try block (if it exits normally), when the try block
> throws (if the exception is not caught by any catch handler in the
> same try..catch..finally block), at the end of the catch block (if a
> catch block exits normally) or when a catch block throws, which is
> the only case left.

This is what destructors are for in C++. The only problem I can see
with destructors is that you might not have a class at hand with an
appropriate destructor. But the solution isn't, IMHO, to introduce a
new flow control structure. The solution is to make it easier to
create usable local classes. (This also solves the problem of nested
functions.) Define a closure, or a lambda class, as a built-in class
with access to the context of the local frame. I had sort of imagined
a syntax along the lines of:

lambda { ... }
or
lambda : public BaseClass { ... }

In both cases, the result is a temporary object of an unnamed type,
with the implementation in the { ... }. This variable automatically
contains references to all local variables currently visible.

My original intent was for this to support variants on the Visitor
pattern, where a function took a reference to an abstract base class,
which would be implemented by the lambda. If templates were extended
to allow instantiation over local classes, such objects (without the
base class) could also be used as functional objects for the standard
library; functional objects which automatically have access to the
local scope.

A secondary use is the case where the only function of the lambda is
the destructor. For this to work, the lambda object would need to
have the lifetime of a declared variable, and not that of a normal
temporary. But the destructor would then do exactly what your finally
would do. I could even imagine a simplified syntax for this:

cleanup { ... }

where the code in the braces is just the code for the destructor,
instead of the complete class, with all functions. So one could write:

Resource r( acquire() ) ;
cleanup { r.free() } ;
...


--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

matthew denner

unread,
Dec 18, 2000, 3:37:46 PM12/18/00
to
Robert O'Dowd wrote:
>
> Ben Liddicott wrote:
> > [Snip]
> 2
> > 1) try, catch, finally
> > ==========================
>
> I disagree. You suggested some ways of doing the same thing. It can
> also be done with nested try/catch blocks.
>
> try
> {
> //
> try
> {
> if (SomeCondition)
> throw Something;
> else
> throw SomethingElse;
> }
> catch (Something &)
> {
> // may or may not throw an exception
> }
> }
> catch(...)
> {
> final_cleanup();
> throw;
> }
> final_cleanup();
>
> Since the code in finally blocks would usually not throw exceptions,
> the above achieves the same thing.

hang on, you're seriously telling us that you'd prefer to write 'complicated'
code like this rather than a simple try...catch...finally? you have to
look longer at this block of code to work out what's going on which suggests
to me that it is harder / more expensive to maintain.

> > 6) outer type for nested classes.
> > ==========================
> >
> > Example:
> > struct A
> > {
> > struct B
> > {
> > };
> > };
> >
> > B::outer should refer to A. Clearly this can be done by putting a line:
> > typedef A outer; in B's definition. Also clearly B can (itself) access
> > things such as typedefs and statics from A without any rigmarole.
>
> I may be slow, but fail to see that this gives you that the typedef does
> not. Particularly since you are proposing a new keyword to give it to
> you.

um, hang on: what are you trying to achieve here? do you want access to:
the members of the outer structure instance, or just access to what's
inside the outer structure (like constants)? in java the first has been
solved (and i always get this the wrong way round so if i'm wrong read
it right!) by saying that:

class A {
private int value = 1;

class B {
public void bar() {
A.this.value = 2; // access the outer A.value
}
}
}

i don't see how typedef or B::outer (described above) solves this. i
could only come up with:

struct A {
A() : m_inner(*this) { }

struct B {
typedef struct A outer;

B(A & a): m_outer(a) { }

outer & m_outer;
} m_inner;
};

which is nasty looking code anyway! now, if B::outer did that then i'd
be up for it!

if you're talking about accessing A::constant_value or whatever, then
i'm not really bothered as i can write A::constant_value, or typedef it,
now.

> > g) Oh, yes:
> >
> > void main() // This should be allowed.
> >
> > Who are these self appointed language police who care enough to correct
> > posters about this? If the program doesn't have a meaningful return value,
> > then the compiler should return rubbish, or zero! The only tool I care
> > about that uses a return value is find (and test, of course, has a return
> > value that is meaningful to the shell).

could this be because you're too lazy to write correct code? cut-n-paste
the following code into a file, build it into a library which you can include
in your application and then happily write the lazyMain method.

int main(int argc, char * argv[]) {
lazyMain();
return 0;
}

sorry, but that got my back up :) officer dibble, over-and-out.

Cheers,
Matt

-----------------------------------------------------------------------------
Sessami is a trademark of Escape Velocity Technology Mobile Services Limited.
All information contained in this e-mail is confidential and for the use of
the addressee only. If you receive this message in error please notify.

Ron Natalie

unread,
Dec 18, 2000, 5:00:48 PM12/18/00
to

Ben Liddicott wrote:

> > derived and you don't know the type is compatbile.
>
> You are not upcasting because you are ignoring the value of the pointer on
> input, and it is safe because you are replacing it with a new object who's
> type you know.

No, it's not typesafe (regardless as to whether you look at the variable) or
not. It works for your contrived example but it doesn't take much modification
to break it in a non-typesafe fashion.

You omitted the implementations of GetAnA, so lets fill them in with the
obvious implementations:

struct X{
virtual bool GetAnA(return A*& rpA) { return new A; }
};

struct Y:X{
virtual bool GetAnA(return B*& rpB) { return new B; }
};

Now all we have to do is make one tiny change in your main routine:

int main() {
B* pB = 0; // Same as yours
X x;
X* pX = &x; // lets use the base class.
x.GetAnA(pB); // BOOM, we've just crammed an A* into a B*

Marco Dalla Gasperina

unread,
Dec 18, 2000, 5:01:11 PM12/18/00
to

"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
news:977100910.29579.2...@news.demon.co.uk...

> > But it might receive a different class derived from A.
>
> That's fine. Either the caller is calling through an X* and expecting an A
> (or something -- anything -- derived therefrom), or he is calling through
> a Y* and expecting a B, or through an Z* and expecting a C. In no case
> will he be disapointed, unless he has previously done an invalid downcast.
>

Consider (C++ w/covariant args):

class BaseArg {};
class DerivedArg : public BaseArg {};

class BaseTarget {
public:
virtual void func( BaseArg& ba );
};

class DerivedTarget {
public:
virtual void func( DerivedArg& ba );
};

void foo( BaseTarget& bt, BaseArg& ba )
{
bt.func(ba);
}

DerivedTarget dt;
BaseArg ba;

foo( dt, ba );

results in DerivedTarget::func() being called with a BaseArg.
No illegal down-casting involved.

marco

Stephen Cleary

unread,
Dec 18, 2000, 4:46:43 PM12/18/00
to
> Since it is nearly the holidays, here is a trivial and frivolous post.

Why not? Here's my wish list, in order of preference:
. typeof() operator
. overloading operator.
. something like Borland's __closure extension

-Steve
e-mail replies to: scleary at jerviswebb dot com


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Dylan Nicholson

unread,
Dec 19, 2000, 6:15:19 AM12/19/00
to
In article <t3sn5ms...@corp.supernews.com>,

"Marco Dalla Gasperina" <mar...@panmed.com> wrote:
>
> "Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
> news:977100910.29579.2...@news.demon.co.uk...
> > > But it might receive a different class derived from A.
> >
> > That's fine. Either the caller is calling through an X* and
expecting an A
> > (or something -- anything -- derived therefrom), or he is calling
through
> > a Y* and expecting a B, or through an Z* and expecting a C. In no
case
> > will he be disapointed, unless he has previously done an invalid
downcast.
> >
>
> Consider (C++ w/covariant args):
>
> class BaseArg {};
> class DerivedArg : public BaseArg {};
>
> class BaseTarget {
> public:
> virtual void func( BaseArg& ba );
> };
>

Ben was quite specific about what sort of parameters would be allowed
to be covariant. They basically had to be pointers to references or
pointers to pointers, and be "out only" - i.e. what the pointer was
pointing to on the way in is irrelevant. In this case they are
indistinguishable from return values so should be just as safe.

Dylan


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Michael H. Cox

unread,
Dec 19, 2000, 6:21:18 AM12/19/00
to

"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
news:977100912.29579.4...@news.demon.co.uk...

>
> "RCN News Server" <mh...@acm.org> wrote in message
> news:91dlhn$1r7$1...@bob.news.rcn.net...
>
> I don't believe in portability as a language aim. If you are using
> anything at all that interacts with the outside world (disk IO over cin,
> cout and cerr, sockets etc) you are already outside the scope of C++.

Gee, you must work for Microsoft! ;-)

>
> > "Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote in message
> > news:976747071.14502.1...@news.demon.co.uk...
> > > 1) try, catch, finally
> > > ==========================
> > This wouldn't be my top priority for the reasons you describe below,
> i.e.
> > there are auto_ptr like alternatives (see boost.org for their scoped
> class),
> > although not as elegantly.
>
> But they are not in the standard.

Neither is "finally", but these boost classes can be used now and may be
added to the standard in the future. The boost.org charter is to develop
nice to have, general purpose libraries (primarily of the template variety)
that can be added to the standard. This way the standards committee (of
which many of the members of boost are also a member) will have a set of
well-designed libraries with lots of usage experience behind them for
inclusion into the next standard. Even if they don't eventually get
included, you can still use them.

> > > 11) Covariant out parameters
> > > ==========================
>
> > Why would this have to be restricted to output parameters? It seems
> like
> > any reference/pointer parameter regardless of whether it's used as input
> or
> > output could be used. Maybe we could bring back the deprecated (and
> since
> > obsolete?) overload keyword (or was it override?).
>
> It's only necessary on output parameters. Input parameters (p&, p*const
> etc) work already.

Huh? If you change the signature of a virtual function in the derived class
, you have a new virtual function.

> > Now for my Christmas extension: I'd like the RTTI to be extended to
> include
> > the introspection capabilities of Java (to as great a degree as
> possible),
> > e.g.
> >
> > class std::type_info
> > {
> > public:
> > // The stuff it already has, plus:
> > const char *full_name() const; // Returns fully-elaborated, human
> > readable name
> > // including all
> > namespaces and nested classes
> > // separated via
> > "::". This method could be added
> > // or name()
> could
> > be specified to return this
> > // string.
>
> Some compilers provide this, notably MSVC++.

Didn't notice this. But I'd still like to make it (or something like it)
standard. Especially if they could get the Java introspection capabilities
working with C++ and its pointers, reference, pass by value, etc.

>
> All looks quite reasonable to me. Have you seen .NET?

Nope.

Robert O'Dowd

unread,
Dec 19, 2000, 6:24:13 AM12/19/00
to

I'm not claiming I prefer to write "complicated" code. My point was
that
finally behaviour is not strictly required.

I tend to code things in different ways, that make using finally
pointless.

As an example, let's assume C++ supports try/catch/finally and we have
two functions that use them in the same way

void SomeFunction()
{
try
{
SomeFunctionThatThrows();
}
catch (AnException &a)
{
// handle AnException
}
catch (OtherException &o)
{
// handle OtherException
}
// etc
finally
{
// do cleanup
}
}

void SomeOtherFunction()
{
try
{
SomeFunctionThatThrows();
}
catch (AnException &a)
{
// handle AnException
}
catch (OtherException &o)
{
// handle OtherException
}
// etc
finally
{
// do cleanup
}
}

The above duplication of code in exception handlers is fairly
common in libraries that I've reviewed. And is a serious
maintenance problem for the future --- if you change one, odds
are you need to change the others. "finally" does not
cause the problem, but would definitely compound it.

Now, compare this with an approach that I tend to use,
based on approach of "object construction is initialisation,
destruction is cleanup".

class MyFinaliser
{
public:
MyFinaliser();
~MyFinaliser()
{
// do cleanup
};
}

// The Finaliser class can also be written as a template
// (parameterised by a function or "functor" that does
// the cleanup).

void SomeFunction()
{
MyFinaliser cleaner; // Destructor of Finaliser does necessary
// cleanup whether an exception is
// thrown or not

try
{
SomeFunctionThatThrows();
}
catch (...)
{
MyExceptionHandler();
}
}

void AnotherFunction()
{
MyFinaliser cleaner;
try
{
SomeOtherFunctionThatThrows();
}
catch (...)
{
MyExceptionHandler();
}
}


void MyExceptionHandler()
{
//
// Use this like the above to avoid replicating the following
// exception handling scheme in lots of functions.
//
try
{
throw; // if we get to here, an exception has been thrown
// rethrow it so we can handle it
}
catch (AnException &a)
{
// handle AnException
}
catch (OtherException &o)
{
// handle OtherException
}
// etc
}

The above combination of techniques, apart from facilitating code
reuse in exception handlers, make use of "finally" rather pointless.
In fact, finally would negate some of the benefits offered by a
scheme like the above (as the above technique would not facilitate
code reuse with "finally" handlers).

benoit...@my-deja.com

unread,
Dec 19, 2000, 6:24:50 AM12/19/00
to
> 1) try, catch, finally
> ==========================
The best I've done, in the case where I don't rethrow the exception,
is
Resource r
try { ... } catch(.) ;
FreeResource(r);

'finally' is indeed cleaner.

> PageSysadminOutOfBed();

Just keep this one out of the standard; might be overused :)

> 5) typeof() operator.
> ==========================
Gotta love gcc.

> When I was a novice, I naively assumed you could use :: to retrieve
> the type of a variable

I would like this too. Otherwise, I have dozens of typedefs, and if I
subclass from something that uses a useless name like 'iterator' and
forget to typedef iterator to something else in my class, I get weird
results (compiler errors if lucky, users shouting otherwise).


> 7) Loop Labels
> ==========================

Can be done now with goto -- about the only reason I use goto --, but I
prefer the perl solution (Java has this?)


> 9) More operators.
> ==========================
>
> Why stick with those boring old C style operators? What about:

> <=> comparison. Returns signed result (so 0 means equal).

As someone else said, operator-. Not as clear; tough. Or call a
function. Not enough need here.

> ~= like. Floating point numbers are similar.

How do you set epsilon? Is ~= ternary?

> &>,&, *>, *<, +<, +>, -<
> Surely someone can think of something to do with these?

Indeed, and I shudder to think...

> 10) Pick Any functions and data
> ==========================

Why?

> 12) And some more gubbins.
> ==========================

> a) Sized integers.

Yes!

> b) Endianism macros for reading from/writing to streams intended for
other

hton[sl] in <arpa/inet.h>
'host to network [short,long]'

Clearly, you have to know that 's' means short (16-bit signed), 'l'
means long (32-bit signed). So should probably be hton16 hton16u, and
so on.

> Define
> CHANGEENDIANISM_QWORD()
> CHANGEENDIANISM_DWORD()

There's more than one way to do endianness. Also, 'word' is 16-bit for
Win32 for compatibility with Win16. A word is usually the 'natural'
size of data that the CPU reads in (16, 32, 36, whatever).

> d) Standardized compiler options.

-g and -O are pretty standard.

> e) Standardized compiler errors and warnings.

And then we'd be stuck with the LCD of messages, which would be
terrible.

> f) The ablility to turn non-ansi features on and off one at a time.

The ability to turn non-standard stuff on? Obviously needs to remain
non-standard.

> g) Oh, yes:
>
> void main() // This should be allowed.

Likely. Allowing main to drop off with an arbitrary return value is
nasty. In fact, allowing any function to drop off with arbitrary return
is nasty, but most compilers will have that as just about the first
thing they warn against.


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 19, 2000, 8:29:24 AM12/19/00
to
Ben Liddicott wrote:

> > Normally, if you find yourself using unions a lot, then it's time to
> > switch to the base class derived classes concept.

> I disagree. You can have arrays of unions. With base/derived, you
> have to allocate memory for each individual object, which has a
> performance hit.

To hell with performance? With base/derived, you have to be sure to
delete the memory at the correct time, which is a horrible source of
errors and a maintainance nightmare.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Anthony Williams

unread,
Dec 19, 2000, 8:31:30 AM12/19/00
to
In article <91kv8m$g95$1...@nnrp1.deja.com>,

alg...@my-deja.com wrote:
> In article <3A3A47FD...@sensor.com>,
> Ron Natalie <r...@sensor.com> wrote:
> > Ben Liddicott wrote:
> > > 3) Allow classes with constructors/destructors as members of
unions.
> > > ==========================
> >
> > You can't call constructors.
>
> Except via placement new. Or you could allow the union constructor's
> initialiser list to invoke a member's constructor.
>
> > If you were going to call some member function
> > with constructor like semantics, you can do it now and put it in a
> union.
> > I'm not clear what this solves that you couldn't do anyhow.
>
> Two separate issues.
>
> (1) Classes with non-trivial default constructors, or destructors.
> These are tricky in unions. Perhaps they should be supported - for
> experts only. It would make it possible to use STL classes in unions.
> No doubt some programmers would then deliberately wrap classes in
> unions as a way of avoiding the default constructor overhead.

Perhaps, the compiler could not generate default constructors and
assignment operators for such a union, so that the programmer would be
forced to write them. Obviously, this doesn't cover all eventualities,
or force the programmer to write them correctly, but it's a start.

> (2) Classes with trivial default constructors and no destructor.
There
> is no technical reason these should not be in unions, and it appears
to
> be an oversight in the C++ standard that they are not. It is quite
> natural to have classes with non-default constructors - the builtin
> types have non-default constructors, e.g. we can say
> int n = 2;
> The ability to initialise an int does not stop it being in a union and
> nor should it stop a struct, when the common factor is that their
> default initialisation is "don't care".
>
> Wrapping data types in classes is useful a technique to re-engineering
> C with C++. Existing C code may contain unions. C++ has unions. It
> should not put obstacles in the way of using unions with specific
> features of C++. It should not take the view that "unions are a C
> feature, C++ should no more than tolerate them". Even in cases where
> unions are used only for space reasons, the comment that "PCs have
> 128Mb these days" is frankly juvenile. Customers expect to see their
> PC upgrades reflected in ability to handle larger workloads - not
> absorbed by new bloat in our code. And who said PCs were the smallest
> C++ target platforms around, anyway? As the Embedded C++ (and to some
> extent C99) efforts show, C++ risks fragmentation if the standards
> people ignore efficiency.
>

I agree

Anthony

--
al...@anthonyw.cjb.net -- Questions relating to ALINK
ant...@anthonyw.cjb.net -- Non-ALINK questions
anthonyw.cjb.net -- ALINK home page
PGP Key at: i3.yimg.com/3/c7e5ee24/g/68fc2307.asc

Kevin Cline

unread,
Dec 19, 2000, 6:21:25 PM12/19/00
to
Ken Bloom wrote:

> > 4) Property-like methods.
> > ==========================


> I happen to like get/sets. I wish that MSVC++'s #import directive would
> automatically create get/sets for ActiveX objects, rather than creating

> assignable properties. I dislike properties, but I like the concept of


> property pages, perhaps that could be easily combined with get/sets like:
> _propertyelement("Name",void setName (string),string getName(void));
> this would add the property to a list, but not generate variable-like
> things.

Whenever I see sets of functions with similar names, like doThisToX,
doThatToX,
doThisToY, doThatToY,
I immediately think that X and Y should be an instance of a class with member
functions doThis and doThat.

So instead of

class C {
int x() const;
void set_x(int new_x);
string const& s() const;
void set_s(string const& new_y);
};

I write:

template <class T> Property<T> {
private:
T v;
public:
void set(T const& new_v) { v = new_v; }
const T& get() const { return v; }
}

class C {
public:
Property<int> x;
Property<string> s;
}

C c;
c.x.set(17);
c.s.set("randomness");

This makes it easy to write other generic classes and functions that map
properties to database columns, or
inserts and retrieves them from streams, or both! Or I could write a class
UndoableProperty that records the
set operations on a list, and then change my Property declarations to
UndoableProperty.

Dylan Nicholson

unread,
Dec 19, 2000, 6:22:29 PM12/19/00
to
In article <3A3E5BB9...@sensor.com>,
Well no-one (I believe) is suggesting that the language be changed to
allow that last line to be compilable.
X::GetAnA() takes an (A*&) - you can't pass a B* into that...

Dylan

Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Ross Smith

unread,
Dec 19, 2000, 7:39:42 PM12/19/00
to
benoit...@my-deja.com wrote:
>
> In article <976747071.14502.1...@news.demon.co.uk>,
> "Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:
>
> > d) Standardized compiler options.
>
> -g and -O are pretty standard.

The Single Unix Standard
(http://www.opengroup.org/onlinepubs/007908799/toc.htm) specifies some
options required of the C89 compiler. I don't think this sort of thing
belongs in the language standard.

-c = Create object file, don't link
-g = Include symbolic debugging information
-s = Strip unnecessaru information from output file (behaviour is
unspecified if both -g and -s are present)
-o file = Specify output file
-D name[=value] = Define preprocessor macro
-E = Do the preprocessing step only
-I dir = Add to search path for header files
-L dir = Add to search path for link libraries
-O = Optimise
-U name = Undefine preprocessor macro

--
Ross Smith <ros...@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"Normally he was insane, but he had lucid moments
when he was merely stupid." -- Heinrich Heine

Tom

unread,
Dec 19, 2000, 11:26:07 PM12/19/00
to
Previously, Ben Liddicott wrote in comp.lang.c++.moderated:

> > > 11) Covariant out parameters


> > > ==========================
> >
> > This is actually conceptually wrong. You haven't thought it through.
> >
> >
> > struct Z:X{
> > virtual bool GetAnA(return C*& rpC);// overrides GetAnA(return A*&)
> > };
> >
> > > int main()
> > > {
> > > B* pB=0;
> > > Y y;
> > > X* pX = &y;
> > > pX->GetAnA(pB);
> > C* pC=0;
> > pX->GetAnA(pC);
> > pC->do_it(); //boom, pC is actally a B
>
> That won't work because pX is typed as an X, so passing a pC& is an error,
> just as it is today.

But so is passing a B*&! All you can pass to X::GetAnA is an A*&. But I had
changed your example because it contained a typo (x was undefined) - but I
think I corrected it wrongly.

> > > It is safe because the programmer knows that the value of rpA is
> ignored
> > > on entry, and recieves a class derived from A.

You foxed me with the above statement, which is false. rpA only receives an
A*, not a B* or a C*. Obviously the value of A*, and therefore what object it
is pointing to is ignored.

Going back to your original example, could you fix the typo to confirm what
you are saying:

struct A{};
struct B:A{};

struct X{
virtual bool GetAnA(return A*& rpA);
};

struct Y:X{
virtual bool GetAnA(return B*& rpB);// overrides GetAnA(return A*&)
};

int main()
{
B* pB=0;
Y y;
X* pX = &y;

x.GetAnA(pB);
return 0;
}

x is undefined, which is what has caused all the confusuion.

> >
> > But it might receive a different class derived from A.
>
> That's fine. Either the caller is calling through an X* and expecting an A
> (or something -- anything -- derived therefrom), or he is calling through
> a Y* and expecting a B, or through an Z* and expecting a C. In no case
> will he be disapointed, unless he has previously done an invalid downcast.

If you continue to leave off *s where you mean them and add them where they
are not required, I shall surely die of confusion! Calling through an X* (or
X& or X) he is expecting an A*&, which must have been bound to an A*.

Anyway, as Dylan Nicholson says, if you mean what I think you mean (i.e.
y.GetAnA(pB) in your example, with pX a strange and irrelevant diversion),
then covariant out parameters are just as valid as covariant returns, and
therefore fine. But I don't see why you think they are particularly useful -
it just allows multiple covariant return values. I've never needed such a
thing - one has been enough.

Tom

James Kanze

unread,
Dec 20, 2000, 11:10:59 AM12/20/00
to
Anthony Williams wrote:

> > (1) Classes with non-trivial default constructors, or destructors.
> > These are tricky in unions. Perhaps they should be supported - for
> > experts only. It would make it possible to use STL classes in unions.
> > No doubt some programmers would then deliberately wrap classes in
> > unions as a way of avoiding the default constructor overhead.

> Perhaps, the compiler could not generate default constructors and
> assignment operators for such a union, so that the programmer would
> be forced to write them. Obviously, this doesn't cover all
> eventualities, or force the programmer to write them correctly, but
> it's a start.

That doesn't really solve the problem. The initialisation problem
could be solved with something like the designated initailizers in C;
the programmer states which element he wants to initialize. The
problem is assignment and destruction. To correctly write or generate
an assignment operator or a destructor, it is necessary to know what
type is currently stored in the union. The compiler doesn't generally
know it, and I don't see how user code in a member function can know
it either.

Assignment also adds a semantic problem, since it typically cannot use
the assignment operator of the type being assigned. In fact, the only
way I can think of to implement assignment correctly is with the
explicit destructor/placement new pattern, which introduces a
completely new set of problems.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

ben.li...@bencat.demon.co.uk

unread,
Dec 20, 2000, 11:45:44 AM12/20/00
to
In article <Voyager.0012191...@administrator.co.uk>,

Tom <the...@my-deja.com> wrote:
> Previously, Ben Liddicott wrote in comp.lang.c++.moderated:
>
> > > > 11) Covariant out parameters
> > > > ==========================
(...)

>
> If you continue to leave off *s where you mean them and add them
where they
> are not required, I shall surely die of confusion! Calling through an
X* (or
> X& or X) he is expecting an A*&, which must have been bound to an A*.


Duh! I am so stupid.

I mean this:
Y y;
B* pB=0;
y.getAnA(pB);
X* pX=&y;
A* pA=0;
pX->getAnA(pA);

Which is of course fine (unless I have made another five stupid typeos)
except for the bit where I override X::getAnA(A*&) with Y::getAnA(B*&),
which is what I want to allow.

> Anyway, as Dylan Nicholson says, if you mean what I think you mean
(i.e.
> y.GetAnA(pB) in your example, with pX a strange and irrelevant
diversion),
> then covariant out parameters are just as valid as covariant returns,
and
> therefore fine. But I don't see why you think they are particularly
useful -
> it just allows multiple covariant return values. I've never needed
such a
> thing - one has been enough.

Quite so.

I don't think covariant out parameters are particularly useful, I think
they are a bit useful. I don't think covariant returns are gigantically
useful either. I rarely need them, and when I do the compiler I happen
to be using at the time generally doesn't support them. I simply paper
over the cracks with inline wrappers that use known (to me) safe
static_casts.

Covariant returns are useful as you say when more than one covariant
return is required. They are also useful where the return value is
being used for something else.

The particular motivator was a library I used once. (I still use it in
fact). In version 1 the library supplied X and A, in version 2 they
supplied Y and B, and in version 3 they supplied Z and C.

Since the objects were obtained from a well-known named entrypoint in a
dynamically loaded shared object (factory pattern), this meant you
could upgrade the library without recompilation. Since the decision had
already been taken that A was returned through an out parameter, they
had little choice while retaining binary compatibility.

This generally worked fine. However the newer versions of the library
while binary-compatible where compile-incompatible, resulting in a not-
too-arduous search and replace exercise. (This was partly due to the
fact that they renamed X to X from P, and A to A from Q, and in the
headers kept P and Q as a typedef for the latest X/A derived class. Of
course they could have used inlines as I described to fix the problem,
but they never did.)

Cheers,
Ben Liddicott


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

ben...@my-deja.com

unread,
Dec 20, 2000, 11:56:28 AM12/20/00
to
In article <91mk67$uoo$1...@nnrp1.deja.com>,

Dylan Nicholson <dn...@my-deja.com> wrote:
> In article <3A3E5BB9...@sensor.com>,
> Ron Natalie <r...@sensor.com> wrote:
> >
> Well no-one (I believe) is suggesting that the language be changed to
> allow that last line to be compilable.
> X::GetAnA() takes an (A*&) - you can't pass a B* into that...

Indeed, that was a stupid typo on my part, that has made me look
extremly silly. Unfortunately there is no spellchecker for proposed
language extensions :-).

I meant:

B* pB=0;
Y y;
y.getAnA(pB);
A* pA=0;
X*pX=&y;
pX->getAnA(pA);


Which is fine today except for the point where Y::getAnA(B*&pB)
overrides X::getAnA(A*&pA). It is that overriding that I want to allow,
I am not proposing changing the way it is called. This is of course
unsafe if Y::getAnA makes use of the initial value of pB, but safe if
it treats it as out-only. A reference to an object capable of holding a
pointer to A is by definition capable of holding a pointer to B.

The problem that exists at the moment, is that the compiler must forbid
this because it has no way of determining whether this is the case. So
I propose using a keyword to distinguish which parameters are out-only.

Cheers,
Ben Liddicott

Ron Natalie

unread,
Dec 20, 2000, 1:00:59 PM12/20/00
to

Dylan Nicholson wrote:
>
>
> >
> > int main() {
> > B* pB = 0; // Same as yours
> > X x;
> > X* pX = &x; // lets use the base class.
> > x.GetAnA(pB); // BOOM, we've just crammed an A* into a B*
> >
> Well no-one (I believe) is suggesting that the language be changed to
> allow that last line to be compilable.
> X::GetAnA() takes an (A*&) - you can't pass a B* into that...
>

Sorry, I fell into the same bug that the orignal poster made:

It should read this way:

struct A{};
struct B:A{};

struct X{
virtual bool GetAnA(return A*& rpA);
};

struct Y:X{
virtual bool GetAnA(return B*& rpB);// overrides GetAnA(return A*&)
};

int main()
{
B* pB=0;
Y y;
X* pX = &y;
pX->GetAnA(pB);

return 0;
}

The only difference between what he is proposing and what I posted was
intended to be the dynamic type of the object (being an X not a Y).

Nicola Musatti

unread,
Dec 20, 2000, 1:01:22 PM12/20/00
to
You seem to forget that program exit codes are an essential feature of
Unix, which is what C was designed for. Even DOS has a clumsy way for
checking them.

Best regards,
Nicola Musatti

ben...@my-deja.com

unread,
Dec 21, 2000, 5:41:55 PM12/21/00
to
In article <3A40A0B9...@dresdner-bank.com>,
James Kanze <James...@dresdner-bank.com> wrote:

> Anthony Williams wrote:
>
> > Perhaps, the compiler could not generate default constructors and
> > assignment operators for such a union, so that the programmer would
> > be forced to write them. Obviously, this doesn't cover all
> > eventualities, or force the programmer to write them correctly, but
> > it's a start.

This is what I had in mind. The compiler might want to do a zero-init,
but anything more would surely be unsafe. My idea is to make the
programmer responsible.

> That doesn't really solve the problem. The initialisation problem
> could be solved with something like the designated initailizers in C;
> the programmer states which element he wants to initialize. The
> problem is assignment and destruction. To correctly write or generate
> an assignment operator or a destructor, it is necessary to know what
> type is currently stored in the union. The compiler doesn't generally
> know it, and I don't see how user code in a member function can know
> it either.

No, you are quite right, in the general case it can't. Since the
general case is not an option, the programmer must do some work to
create a special case.

Consider:

// A and B have non-trivial construction/assignment/destruction
semantics

enum exampleType{etA, etB};
class C1
{
protected:
exampleType eType;
union U1
{
A a;
B b;
} u1;
public:
// here put assignment semantics etc.
};

> Assignment also adds a semantic problem, since it typically cannot use
> the assignment operator of the type being assigned. In fact, the only
> way I can think of to implement assignment correctly is with the
> explicit destructor/placement new pattern, which introduces a
> completely new set of problems.

In most cases, for a bare union, the union probably could not portably
know what constructor/assignment to use. However, in the example above,
C1 takes responsibility for this. (I don't think I need to fill in the
details).

I am not sure if the following is guaranteed portable behavior, but in
practice it would be OK in the absence of virtual functions (and could
probable be made better with some use of offsetof).

union U2
{
protected:
exampleType eType;
struct A
{
exampleType eType;
// more members
double d;
} a;
struct B
{
exampleType eType;
// more members
long l1;
long l2;
} b;
public:
//constructors, assignment, destructors.
};

Here we take advantage of our knowledge of the layout of U2, U2::A and
U2::B, namely that u2.a.eType is at the same offset as u2.b.eType and
u2.eType.

I might hazard the statement that only an insane compiler vendor would
fail to support this code, since much C code in existance relies on
this behavior.

Typically the paradigm is to have a setup/destroy function for each non-
trivial member of the union, and for the programmer to write logic to
call each as neccessary. The only thing that is new is the ability to
make objects with non-trivial destruction semantics members of unions.

Cheers,
Ben Liddicott


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Dec 21, 2000, 5:46:09 PM12/21/00
to
Nicola Musatti wrote:

> You seem to forget that program exit codes are an essential feature
> of Unix, which is what C was designed for. Even DOS has a clumsy way
> for checking them.

As does every other OS I've ever heard of.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Ben Liddicott

unread,
Dec 21, 2000, 7:50:22 PM12/21/00
to
In article <3A3EA071...@nonexistant.com>,
"Robert O'Dowd" <nos...@nonexistant.com> wrote:
> matthew denner wrote:
> >
(...)

I really like your approach to code reuse in exception handling. It
could be useful when a lot of exceptions are thrown that are unrelated
by inheritance. It has given me a lot of food for thought.

I'm no language lawyer, though: Is it legal? It amounts to this:

try{
SomeFunctionThatThrows();
}catch(...)
try{throw;}
catch(A a)
{
}
catch(B b)
{
}
}

Which seems to be a strange thing to allow. In addition I was under the
impression that "throw;" was illegal outside of a catch block. Have I
got this wrong?

I also have to question whether it is commonplace for exception
handling code to really require duplication. I often see similar code
in different places, but rarely similar enough to be parameterized, or
in enough places to make it worthwhile.

> The above duplication of code in exception handlers is fairly
> common in libraries that I've reviewed. And is a serious
> maintenance problem for the future --- if you change one, odds
> are you need to change the others. "finally" does not
> cause the problem, but would definitely compound it.
>
> Now, compare this with an approach that I tend to use,
> based on approach of "object construction is initialisation,
> destruction is cleanup".
>

(...)


>
> The above combination of techniques, apart from facilitating code
> reuse in exception handlers, make use of "finally" rather pointless.
> In fact, finally would negate some of the benefits offered by a
> scheme like the above (as the above technique would not facilitate
> code reuse with "finally" handlers).

The described method of facilitating code re-use in exception handling
looks fascinating, and useful. However it is completely orthogonal to
the issue of finally blocks vs. destructors.

Your point about using destruction semantics of a special class is well
taken, and has been mentioned by other posters including myself.
However it strikes me as more cumbersome and awkward to write. It also
obfuscates the situation as the cleanup code is in a different place
from where the cleanup logically takes place.

In short it strikes me as coding around the problem, and confirms my
view that this is a shortcoming of C++. If you have to go to such
lengths to solve the problem, it proves there is a problem to solve.

Cheers,
Ben Liddicott

Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Ben Liddicott

unread,
Dec 22, 2000, 7:04:53 AM12/22/00
to

"James Kanze" <James...@dresdner-bank.com> wrote in message
news:3A3E1065...@dresdner-bank.com...

> RCN News Server wrote:
> > > Classes with constructors or destructors are not allowed as
> > > members of unions.
>
> > > This is a no brainer really. Of course there is no way for the
> > > compiler to know which to call, and when. But if the developer is
> > > prepared to take responsibility for calling the correct
> > > constructors and destructors at the right time, there is no reason
> > > to prevent them.
>
> > I think there's enough ways in C++ for a programmers to hang
> > themselves that we don't need another.
>
> Agreed. This cannot be made to work with C-style unions. Think about
> assignment, for example. If I have:
>
> union U { A anA ; B aB ; } aU ;
> // initialized with anA...
> aU.aB = B() ;
>
> What should happen in the assignment? The assignment operator for B
> is fine if the union already contains a B, but since the union
> contains an A, it cannot safely be called. What is needed is to
> destruct the A, then copy construct the B. But this isn't the
> semantics of assignment today, and of course, the compiler has no way
> of knowing that it is an A that must be destructed, and not a B.

Caveat scriptor, obviously. I would suggest that this should use
operator=, and if it contained an A before, then tough luck. Using unions
directly in this way is bad programming practice in any case; there is no
discriminant for one thing.

There is certainly no reason to forbid this:

enum exampleType{etA, etB};
class C

{
protected:
exampleType eType;
union U
{
A a;
B b;
} u;
public:
// obvious stuff here.
};


> In order for this to work, to begin with, you need a discrimate union,
> such as was proposed by the Australian delegation. I'm no longer
> familiar with the original proposal, but basically, the union becomes
> intelligent, with a discriminator to indicate what it actually does
> contain, built-in member functions to intergate which field is active,
> and throws an exception if the wrong field is accessed. This would
> make assignment semantics possible, although Herb Sutter and Scott
> Meyers will have fits, since the semantics are exactly the same as
> those of the explicit delete/placement new assignment operator.

The common C+ idiom with unions I have seen is:
// X and Y have trivial construction/destruction semantics
enum exampleType{etX, etY};
class C
{
protected:
exampleType eType;
union U
{
X x;
Y y;
};
void initX();// initializes X, assuming uninitialized memory
void deinitX();// the others do the obvious
void initY();
void deinitY();
void setType(exampleType);// check the type then call two of the above
public:
//ctor
C():eType(etX){initX();};
// other functions
setX(const X&rX){setType(etX); u.x = rX;};
};

This idiom could work perfectly well in the presence of non POD types.

Clearly forbidding the presence of types with non-trivial destructors in a
union serves the purpose of protecting the programmer from himself. But it
seems to me that the philosophy of C++ is "give them enough rope, and let
them do what they want with it". Strictures against such things are a
matter for coding style gurus, not language restrictions.

Cheers,
Ben Liddicott

Ben Liddicott

unread,
Dec 22, 2000, 7:05:56 AM12/22/00
to
"Nicola Musatti" <obje...@divalsim.it> wrote in message
news:3A40E1C0...@divalsim.it...

> You seem to forget that program exit codes are an essential feature of
> Unix, which is what C was designed for. Even DOS has a clumsy way for
> checking them.

I don't forget it, I just don't care.

While exit codes are meaningful to most operating systems, they are not
meaningful for all programs. I just think that programs that don't have a
meaningful exit code should not have to return one.

Cheers,
Ben Liddicott

Ben Liddicott

unread,
Dec 22, 2000, 7:09:16 AM12/22/00
to

<benoit...@my-deja.com> wrote in message
news:91m6ue$jq2$1...@nnrp1.deja.com...

> In article <976747071.14502.1...@news.demon.co.uk>,
> "Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:
> > 7) Loop Labels
> > ==========================
>
> Can be done now with goto -- about the only reason I use goto --, but I
> prefer the perl solution (Java has this?)

No. Yet another typo. Sorry.

> > 9) More operators.
> > ==========================
> >
> > Why stick with those boring old C style operators? What about:
> > <=> comparison. Returns signed result (so 0 means equal).
>
> As someone else said, operator-. Not as clear; tough. Or call a
> function. Not enough need here.
>
> > ~= like. Floating point numbers are similar.
>
> How do you set epsilon? Is ~= ternary?

With:
double set_epslion(double d)
of course :-).

> > &>,&, *>, *<, +<, +>, -<
> > Surely someone can think of something to do with these?
>
> Indeed, and I shudder to think...

> > 10) Pick Any functions and data
> > ==========================
> Why?

So you can put everything in header files. With functions, just say
"inline". Data is harder, though you can do this with templates. But
that's a workaround.

> > b) Endianism macros for reading from/writing to streams intended for
> other
>
> hton[sl] in <arpa/inet.h>
> 'host to network [short,long]'

These are a nop on a bigendian platform. What if they need to read a
littleendian stream?

> There's more than one way to do endianness. Also, 'word' is 16-bit for
> Win32 for compatibility with Win16. A word is usually the 'natural'
> size of data that the CPU reads in (16, 32, 36, whatever).

I was on Win32 when I wrote them, so that is the reason for the names.
CHANGEEND16, CHANGEEND32 etc would probably be better.


> > d) Standardized compiler options.
> -g and -O are pretty standard.

But not much else.

>
> > e) Standardized compiler errors and warnings.
>
> And then we'd be stuck with the LCD of messages, which would be
> terrible.

We wouldn't have to. If we define a heirarchy of more and more detailed
error messages, (named, for example
syntax.unexpected-token.expected-closebracket) then we could map the
underlying message to one that was appropriately detailed.


> > f) The ablility to turn non-ansi features on and off one at a time.
>
> The ability to turn non-standard stuff on? Obviously needs to remain
> non-standard.

Non-standard stuff is surprisingly standard. For example changes in the
draught standard are reflected in different versions of the same compiler.
Other examples might be soon-to-be added stuff from C99. Usually you can
use a flag to set things like loop variable scope, but only all-at once.

>
> > g) Oh, yes:
> >
> > void main() // This should be allowed.
>
> Likely. Allowing main to drop off with an arbitrary return value is
> nasty. In fact, allowing any function to drop off with arbitrary return
> is nasty, but most compilers will have that as just about the first
> thing they warn against.

Non-returning control paths are evil. They should be forbidden.

Cheers,
Ben Liddicott

Nicola Musatti

unread,
Dec 22, 2000, 4:37:21 PM12/22/00
to

Ben Liddicott wrote:
>
> Since it is nearly the holidays, here is a trivial and frivolous post.

They usually generate the most fervent discussions :-)

> 1) try, catch, finally

I think that "finally" is not only useless in C++, but leads to worse
code. Languages like Java, Object Pascal and C# lost much when they
forsook C++'s destructors, which is the only reason why they must
provide an "always executed" branch to try statements.

RAII is a much better solution because it has a much stronger support
for encapsulation and reuse; you cannot reuse a "finally" block except
by putting its content in a function. You might as well go back to
programming C.

[...]
> 2) Empty Member Optimization

No-op (as in "No opinion")

[...]


> 3) Allow classes with constructors/destructors as members of unions.

Runtime polymorphism makes unions almost useless: what's left are mostly
low level unportable hacks which should be avoided in the first place.

> 4) Property-like methods.

As a metaphor it's a valid one, but I find it misleading in C++; there
are already too many ways to hide behaviour from the eyes of the
programmer and I feel that replacing setter/getter methods with
assignment is too little a gain.

[...]
> 5) typeof() operator.

I don't have a very strong opinion on this, but it's supported by
several people whose opinions I respect, so I guess it gets my vote.

> 6) outer type for nested classes.

As it is expressed I don't think it very useful, it is a very limited
version of:

6a) nested dynamic scopes
=========================

This is a feature common in Algol derived languages and is supported by
Java's inner classes. Nested and local classes should have visibility
over the enclosing scope, e.g.:

int i; // (1)
void f() {
int i; // (2)
struct local {
operator() (int j) { i += j; } // increments the i from the
}; // nearest encosing scope, i.e. (2)
}

The next step would be to allow local functions, e.g.

int i;
void g() {
int i;
void h(int j) { i += j; } // same as operator() above
}

This might prove very effective in simplifying the use of standard
algorithms. On the other hand it would be a radical departure from how
we expect things to work and it may be a source of confusion.

> 7) Loop Labels

Nah. Either you write structured code or you use "goto's". Inline
functions provide a way to better structure your code without forsaking
the efficiency.

> loop_for_i:for(int i = 1; i< 1000; i++)
> {
> loop_for_j:for(int j = 1; j < 1000; j++)
> {
> if(SomeCondition(i,j))
> continue loop_for_i;
> if(SomeOtherCondition(i,j))
> break loop_for_j;
> DoSomeAction();
> }
> }

I know this is just an example, but coincidentally both labeled breaks
above can be substituted with plain break, and even this can be
eliminated by inverting the conditions...

> 8) Function Forwarding.

I would like some forwarding mechanism, to make it easier to implement
patterns such as Proxy. I also feel that this would have the effect of
reducing the abuse of public inheritance. This could be achieved by
"overloading" the "using" keyword as follows:

struct A {
int f() { return 5; }
int g() { return 6; }
};

struct B {
A a;
A * pa;
using a; // calls to B::f and B::g are forwarded
// to a.f and a.g
using *pa; // calls to B::f and B::g are forwarded
// to pa->f and pa->g
using a.f; // only calls to B::f are forwarded to a.f
using pa->g; // only calls to B::g are forwarded to pa->g
};

> 9) More operators.

Can't say I like these much.

> 10) Pick Any functions and data

Frankly I can't see the use of this.

> 11) Covariant out parameters

Thumbs down.
[...]


> 12) And some more gubbins.

> a) Sized integers.

Hope they come soon!

> b) Endianism macros for reading from/writing to streams intended for other

> architectures. These should deal with unsigned integral types of size
> 1, 2, 4, and 8 bytes, as well as doubles and floats.

I like the idea, but not the solution. I'd rather have some
"swap_bytes<T>" algorithm defined for builtin types, to be specialized
for user defined ones. Still there are librararies that deal with this
(Sun's ONC/XDR comes to mind).

> c) More control over inlining.

No, the compiler *should* know better. Don't let the implementors grow
sloppy :-)

> d) Standardized compiler options.

I like this very much. At least for a subset of common task it would be
nice if the standard (or some standard...) said "if you provide this
functionality, it shall be activated by means of option <whatever>"

> e) Standardized compiler errors and warnings.

It would be nice but even less feasible. Something could maybe be done
to classify errors explicitly identified by the standard (but I'm sure
that committee members have much more useful things to do).

> f) The ablility to turn non-ansi features on and off one at a time.

Ask your favourite supplier.

> g) Oh, yes:
>
> void main() // This should be allowed.

No.

Best regards,
Nicola Musatti

Ben Liddicott

unread,
Dec 22, 2000, 11:21:58 PM12/22/00
to

"Robert O'Dowd" <nos...@nonexistant.com> wrote in message
news:3A3D48F8...@nonexistant.com...
> > 2) Empty Member Optimization
> > ==========================
> >
> > This is like the empty base optimization, but for members too!
> >
> > Many C++ classes are used purely for the destruction sematics they
have,
> > e.g., auto_ptr. Some are occasionally used for destruction semantics
that
> > are entirely independent of any data, for example to log the lifetimes
of
> > objects to cerr, or to maintain counts of class types, in which case
they
> > would output only their "this" pointer.
> >
> > Objects allocated with new would stil have sizeof(T)>=1, of course.
> >
> > The only problem this might cause would be that such members would not
> > have unique "this" pointers. This matters only if they rely on the
> > uniqueness of their "this" pointer, in which case the workaround is to
add
> > an unused data member, e.g., "char unused;"
>
> Yikes. So you're proposing that we have an object of size zero, unless
> it
> is allocated with operator new? That would mean information would need
> to
> be maintained with every object recording whether it was created with
> operator new. That bookkeeping would sort of negate the benefits of
> this
> optimisation.

No bookeeping is required. Why would it be? sizeof() can still return 1.
It's just like the empty base optimization, with the same advantages, but
extended to members.


> > 3) Allow classes with constructors/destructors as members of unions.

> > ==========================


> >
> > Classes with constructors or destructors are not allowed as members of
> > unions.
> >

> Except for the issue that constructors can not be called (except as part
> of initialiser list from derived class constructors, although "call"
> is probably not the right word).

I'm referring to placement new.

> > 6) outer type for nested classes.

> > ==========================
> I may be slow, but fail to see that this gives you that the typedef does
> not. Particularly since you are proposing a new keyword to give it to
> you.

Not a lot. This was rather a weak one, I am afraid. It can be done with a
typedef, but I'd just rather it was ubiquitous.

> > 8) Function Forwarding.
> > ==========================
> >
> > This would enable "Smart references" with much reduced wear and tear
on
> > the fingertips.
>
> It looks to me like you're asking for delegation. I agree that
> a scheme for delegation would be a useful addition. I don't like
> the method you propose. Also, delegation is something that
> can be done within the current language, just not as easily as
> it could be.

C++ is turing complete. We can do anything in C++ already, the only point
of language enhancements is to make things easier.


> > 9) More operators.
> > ==========================
> >
> > Why stick with those boring old C style operators? What about:
> > <=> comparison. Returns signed result (so 0 means equal).

> operator!= or operator- ?

operator!= returns 1 if the numbers are unequal. operator<=> returns 1 if
lhs>rhs, 0 if lhs==rhs and -1 if lhs<rhs.

> > ~= like. Floating point numbers are similar. Overridable to do
pattern
> > matching for strings.
>
> Problem is that you need to specify what operator~ does for various
> types.

Well, what does operator< do for strings? Complex numbers? It doesn't have
to work at all for int, for example, any more than operator<<(int) works
for double.

> > 11) Covariant out parameters
> > ==========================

> > Ordinarily this is forbidden, of course, even though it is entirely
safe.
>
> I fail to see how it is safe, unless your compiler is psychic and can
> work out the situations in which the called function returns one type
> of the other.

Sadly my original post had a nasty typo which rendered the example
meaningless. I've posted clarification elsewhere...

> > 12) And some more gubbins.

> > ==========================


> >
> > b) Endianism macros for reading from/writing to streams intended for
other
> > architectures. These should deal with unsigned integral types of size
> > 1, 2, 4, and 8 bytes, as well as doubles and floats.
> >

> Mainly because endianism (as you call it) is only an issue if you're
> writing distributed applications, or ones that rely on data files
> in a particular binary format. And because it is inadequate when
> you start looking at representation of things like floating point.

I think most people use IEEE.

> > c) More control over inlining.
>

> Since compilers can usually do a better job of this than a programmer,
> I fail to see the benefit. After all, the benefits of inlining
> tend to be related to capabilities of underlying hardware or
> operating system. And compilers tend to be written to take those
> into account.

A fair point.

> > f) The ablility to turn non-ansi features on and off one at a time.
> >

> > How about it Microsoft? I don't want your old fashioned loop
semantics,
> > but I sure like that _declspec(property) and C9X style struct hack!
>
> Most compilers provide something like this anyway.


>
> >
> > g) Oh, yes:
> >
> > void main() // This should be allowed.
> >

> > Who are these self appointed language police who care enough to
correct
> > posters about this? If the program doesn't have a meaningful return
value,
> > then the compiler should return rubbish, or zero! The only tool I care
> > about that uses a return value is find (and test, of course, has a
return
> > value that is meaningful to the shell).
>
> Language police? People who pick people up on this tend to care
> about program portability. I'm sure they will be quite happy if
> this sort of thing is standardised. Of course, that will need
> to happen in the C standard as well.....

I'm only thinking of my pore ole fingertips, typing that "return 0;" every
time :-).


Cheers,
Ben Liddicott

Nicola Musatti

unread,
Dec 22, 2000, 11:23:10 PM12/22/00
to

Ben Liddicott wrote:
[...]


> While exit codes are meaningful to most operating systems, they are not
> meaningful for all programs. I just think that programs that don't have a
> meaningful exit code should not have to return one.

That's why one is provided for you if you don't feel like writing
"return 0;".
I think that the rest of Ron's argument still holds though.

Best regards,
Nicola Musatti

James Kanze

unread,
Dec 22, 2000, 11:27:07 PM12/22/00
to
Ben Liddicott wrote:

> > > void main() // This should be allowed.

> > Likely. Allowing main to drop off with an arbitrary return value
> > is nasty. In fact, allowing any function to drop off with
> > arbitrary return is nasty, but most compilers will have that as
> > just about the first thing they warn against.

> Non-returning control paths are evil. They should be forbidden.

Then most of the programs I have ever written are evil, because *most*
of them have the basic pattern:

initializeEverything() ;
for ( ; ; ) {
handleAnEvent() ;
}

You can write a return statement after the loop, but it's still not
going to return.

I've been mainly active in real time, process control applications,
but this is also the basic code for an OS. And since your
applications are just functions (with the name "main") called by the
OS, in the end, your code only returns so far, too:-).

(I'm joking, of course. But I still use assertions, and an assertion
failure doesn't return -- it calls abort.)

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Jim Hill

unread,
Dec 23, 2000, 5:55:10 AM12/23/00
to
Ben Liddicott <ben.li...@bencat.demon.co.uk> wrote:
> "Joseph Gottman" <joego...@worldnet.att.net> wrote
> > template <class X> class polynomial
> > {
> > // Return type of an X multiplied by a Y.
> > template <class Y> typeof (X() * Y()) operator()(Y value)
> > };
> >
> > Without typeof, I can't see any way to get this function to always
> > return the correct type.
>
> That is a much more useful example than the one I gave.

Why use a new keyword? There are a few conveniences along this line
I've been hankering for, and I think `auto` covers them all without
breaking legal code now that the wicked implicit int is dead:

{ auto y = 1; /* `int` */ }
{ auto double y = 1; /* `double` */ }
{ auto y = 1.0; /* `double` */ }
{ auto int y = v; /* `int` */ }
{ auto y = x(0); /* x(0)'s type */ }
{ auto( b ) y = a; /* b's type */ }
{ auto y = X()*Y(); /* X()*Y()'s type */ }
{ auto( X()*Y() ) operator()(Y value); /* X()*Y()'s type */ }

struct B : a {
B(){}
B(int A):a(A)(){}
};
struct D : auto B {
// B's non-default special members are treated as for D's default
// ones: the compiler will if necessary implicitly declare and
// define constructors and assignment operators that match B's
// user-declared ones: if `D(int)` isn't declared here, the compiler
// will generate `D(int __1) : B(__1) {}`
};

That covers `typeof`, and `let` or `declare`.

I really really like your idea of using object identifiers for scoping.
That's .. that's .. obvious. Simple.

==

Sure, while I'm babbling, why not differ with Dennis Ritchie? He posted
a deadpan disavowal of `static` a while ago, and I think he was too
harsh: `static` is really simple: something about the name that would
ordinarily be determined at link or runtime is determined right there in
the source. There's only one possibility in each case: for filescope,
visibility; for block scope, lifetime; and for members, object
association. Right? Or should I not have skipped lunch?

==

Another wishlist item: run Koenig lookup on the results of reference
conversions, so I can write

template< class T > class PostIncr
{
public:
operator T & ( ) {return t;}
T * operator& ( ) {return &t;}
~ PostIncr( ) {++t;}
private:
T & t;
friend class T;
PostIncr( T & r ):t( r ){}
/*prohibited:*/
PostIncr();PostIncr(PostIncr&);T&operator=(PostIncr&);
};

and `PostIncr<T> operator++(int) {return *this;}` and forget about it. I
believe this would also exactly satisfy the requirements for an
overloaded `operator.()` without the special-case ugliness on what not
to delegate:

struct delegator
{
void format(Drive &);
operator slave & ();
};

and if (delegator *) p.swap(q) isn't found, treat slave as an associated
class. I suspect this also satisfies the request for properties.

==

And, PLEASE, permit `explicit` on conversion operators. There's really
no excuse for the "just use this kludge that fails when you need it"
response.

Jim

Ben Liddicott

unread,
Dec 28, 2000, 11:33:16 AM12/28/00
to
In article <3A4369E3...@dresdner-bank.com>,
James Kanze <James...@dresdner-bank.com> wrote:

> Ben Liddicott wrote:
>
> > Non-returning control paths are evil. They should be forbidden.
>
> Then most of the programs I have ever written are evil, because *most*
> of them have the basic pattern:
>
> initializeEverything() ;
> for ( ; ; ) {
> handleAnEvent() ;
> }
>
> You can write a return statement after the loop, but it's still not
> going to return.

That is indeed evil. Good OS's and toolkits allow you to write:

int main()
{
initializeEverything();
while(shouldContinue())
handleAnEvent();
cleanupEverything();
return 0;
}
return 0;

> I've been mainly active in real time, process control applications,
> but this is also the basic code for an OS. And since your
> applications are just functions (with the name "main") called by the
> OS, in the end, your code only returns so far, too:-).

As long as the side effects return as far as the user...

> (I'm joking, of course. But I still use assertions, and an assertion
> failure doesn't return -- it calls abort.)

I assume you want it to abort under these circumstances (I assume some
watchdog instantly restarts it). For my own work, logging a
warning/error and continuing/throwing an exception is more usual. And
of course, break into the debugger if it is a debug build.

Cheers,
Ben Liddicott


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

ka...@gabi-soft.de

unread,
Jan 2, 2001, 12:07:46 PM1/2/01
to
Ben Liddicott <ben.li...@bencat.demon.co.uk> writes:

|> In article <3A4369E3...@dresdner-bank.com>,
|> James Kanze <James...@dresdner-bank.com> wrote:
|> > Ben Liddicott wrote:

|> > > Non-returning control paths are evil. They should be forbidden.

|> > Then most of the programs I have ever written are evil, because *most*
|> > of them have the basic pattern:

|> > initializeEverything() ;
|> > for ( ; ; ) {
|> > handleAnEvent() ;
|> > }

|> > You can write a return statement after the loop, but it's still not
|> > going to return.

|> That is indeed evil. Good OS's and toolkits allow you to write:

|> int main()
|> {
|> initializeEverything();
|> while(shouldContinue())
|> handleAnEvent();
|> cleanupEverything();
|> return 0;
|> }
|> return 0;

Sure, they allow you to. My whole point is that you don't want to. The
programs I write don't terminate. Ever. Except, of course, when the
machine is rebooted.

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James W. Walker

unread,
Jan 3, 2001, 8:04:02 AM1/3/01
to
In article <3A41DADE...@dresdner-bank.com>, James Kanze
<James...@dresdner-bank.com> wrote:

> > You seem to forget that program exit codes are an essential feature
> > of Unix, which is what C was designed for. Even DOS has a clumsy way
> > for checking them.
>
> As does every other OS I've ever heard of.

Ever heard of Mac OS? It has no way of checking exit codes.

James Kanze

unread,
Jan 4, 2001, 9:14:19 AM1/4/01
to
"James W. Walker" wrote:

> In article <3A41DADE...@dresdner-bank.com>, James Kanze
> <James...@dresdner-bank.com> wrote:

> > > You seem to forget that program exit codes are an essential feature
> > > of Unix, which is what C was designed for. Even DOS has a clumsy way
> > > for checking them.

> > As does every other OS I've ever heard of.

> Ever heard of Mac OS? It has no way of checking exit codes.

I've never used it, no. So how do you write makefiles? Job scripts?
Or any of the many other cases where a program is *not* invoked by a
human, using the graphic interface?

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

Pete Becker

unread,
Jan 4, 2001, 10:29:16 AM1/4/01
to
James Kanze wrote:
>
> "James W. Walker" wrote:
>
> > In article <3A41DADE...@dresdner-bank.com>, James Kanze
> > <James...@dresdner-bank.com> wrote:
>
> > > > You seem to forget that program exit codes are an essential feature
> > > > of Unix, which is what C was designed for. Even DOS has a clumsy way
> > > > for checking them.
>
> > > As does every other OS I've ever heard of.
>
> > Ever heard of Mac OS? It has no way of checking exit codes.
>
> I've never used it, no. So how do you write makefiles? Job scripts?
> Or any of the many other cases where a program is *not* invoked by a
> human, using the graphic interface?
>

Back when I was doing Mac development you used MPW (Macintosh
Programmer's Workbench), which gave you a command-line shell with
Unix-like capabilities, including program exit codes.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Contributing Editor, C/C++ Users Journal (http://www.cuj.com)

Ron Natalie

unread,
Jan 4, 2001, 10:29:53 AM1/4/01
to

James Kanze wrote:

>
> I've never used it, no. So how do you write makefiles? Job scripts?
> Or any of the many other cases where a program is *not* invoked by a
> human, using the graphic interface?
>

And what does it do when a program dies abnormally?

AllanW

unread,
Jan 4, 2001, 6:10:55 PM1/4/01
to
In article <020120011855168915%j...@scriptthing.com>,

"James W. Walker" <j...@scriptthing.com> wrote:
> In article <3A41DADE...@dresdner-bank.com>, James Kanze
> <James...@dresdner-bank.com> wrote:
>
> > > You seem to forget that program exit codes are an
> > > essential feature of Unix, which is what C was
> > > designed for. Even DOS has a clumsy way for
> > > checking them.
> >
> > As does every other OS I've ever heard of.
>
> Ever heard of Mac OS? It has no way of checking exit codes.

Forgive me, but it seems as if you're advocating this position:

If the feature isn't needed on EVERY SINGLE OPERATING
SYSTEM, then NONE OF THEM should ever be allowed to
use it.

I'm certain that isn't what you really meant, because it
isn't a reasonable position, and I'm sure you're reasonable.

--
All...@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

AllanW

unread,
Jan 5, 2001, 7:08:02 AM1/5/01
to

> "Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:
> > 7) Loop Labels
> > ==========================

sieme...@my-deja.com wrote:
> Looks like it could be useful.
>
> But why not just use goto for break?
> And maybe remove continue from the language?

The keyword continue is very important in the language. Consider
the null statement, which is just a statement delimiter with no
statement before it:

// Lowest power of 2 greater than or equal to x
int i;
for (i=1; i<x; i+=i)
; // NULL statement

Here we show a valid use of the null statement, but most uses
are simply mistakes:

// Count the number of positive integers less than 10
int count=0;
for (int i=1; i<10; ++i); // OOPS
++count; // Only executes once!

Here, the semicolen after the for() statement is a legal null
statement, so there is no way for the compiler to warn you
that the increment of count is not in the loop body. Therefore,
the program claims that there is only 1 positive integer less
than 10.

This problem bit me not long ago. I had a postcondition loop:
do {
// About 1/4 page of code goes here
} while (ask("Want to keep going?"));
We decided to ask the user before even the first time that
the loop executes, so I changed it to a precondition loop.
while (ask("Want to keep going?")) {
// About 1/4 page of code goes here
} while (ask("Want to keep going?"));
As you can easily see in this highly-simplified version,
I forgot to change the last line of the do loop. But this
syntax is completely legal C++ code. The result was that
once the user said "NO", it would ask the same question
again -- and keep asking (without doing anything useful)
until the user said "NO" again!

Null statements should generate a warning. (Ideally they
should be banned, but this would break too much existing
code.) The null statement isn't needed, because continue
fits the bill quite nicely:

// Lowest power of 2 greater than or equal to x
int i;
for (i=1; i<x; i+=i)
continue;

When most C++ programmers adopt this style, language vendors
will give us a way to emit warnings for null statements, and
then I for one will be happy.


> > 8) Function Forwarding.
> > ==========================

> I don't get it.
>
> But const derivation could be good
>
> class Derived : public const Base {

Presumably, no non-const members of Base could ever be
accessed. Or, perhaps they could while Derived is being
constructed, but not after that. Either way, why have a
base class if you can't change it's state? When would you
ever use this? Wouldn't a const member variable be just
as good?

class Derived {
public:
const Base b;


> > 9) More operators.
> > ==========================

> Maybe we could change the editor so that we can draw integral signs
> and treble clefs, and overload these too :).

Technically, we can use these symbols in C++ programs today. In fact,
you can even do this on Ascii-only systems, by spelling out Unicode
characters in hexidecimal, using i.e. \U12345678 and \u1234 (or is it
\U1234 and \u12345678? I forget...)

But are integral signs and treble clefs valid in identifier names?
I don't have my copy of the standard handy, but offhand I'm guessing
that they are not. Still, if you can find the Unicode symbol for a
treble clef, you can print it with code similar to
std::cout << "\U12345678" << std::endl;

As for using these symbols in operator names, what's wrong with
integral(arglist) and trebleclef(arglist) ?
Remember the first rule of operator overloading is, if the meaning of
the overloaded operator isn't obvious, then give the function a name
instead of an operator.

Or should we take Dr. Stroustroup's tounge-in-cheek suggestion of
overloading "operator space" literally?

James W. Walker

unread,
Jan 5, 2001, 7:08:23 AM1/5/01
to
In article <932uro$631$1...@nnrp1.deja.com>, AllanW <all...@my-deja.com>
wrote:

> > Ever heard of Mac OS? It has no way of checking exit codes.
>
> Forgive me, but it seems as if you're advocating this position:
>
> If the feature isn't needed on EVERY SINGLE OPERATING
> SYSTEM, then NONE OF THEM should ever be allowed to
> use it.
>
> I'm certain that isn't what you really meant, because it
> isn't a reasonable position, and I'm sure you're reasonable.

I didn't particularly mean to advocate anything, I was just responding
to Mr. Kanze's statement that he couldn't think of any OS where you
couldn't check the exit code.

Now, if I were to advocate a position, I would agree with the original
poster of this thread:

> void main() // This should be allowed.

I certainly wouldn't say that int main() should be disallowed.

Mitch Adler

unread,
Jan 5, 2001, 7:08:53 AM1/5/01
to
In article <3A548BFB...@spamcop.net>, Ron Natalie
<r...@spamcop.net> wrote:

>James Kanze wrote:
>
>>
>> I've never used it, no. So how do you write makefiles? Job scripts?
>> Or any of the many other cases where a program is *not* invoked by a
>> human, using the graphic interface?
>>
>And what does it do when a program dies abnormally?

It brings up a dialog and informs the user of what it knows about the
program dying.

Typically, 'Word unexpectedly quit due to a type 2 error' (when it has
an address error). But these are more equivalent to core dumping than
non-zero exit conditions.

What you're really getting at is that MacOS doesn't provide a way to
send a number to the user when you fail but don't crash.

Application developers have to consider how to communicate those errors
to the user directly.

Usually some interface, like a dialog, is ues and the error case is
presented in words that a user can understand (though many applications
have a fall back geneiric dialog with cryptic message interface).

Some errors, of course, like running low on memory, are trickier than
others to be able to communicate to the user.

Mitch

------------------------------------------------------------------------
Mitch Adler "There are people in the world who
Intelligent Paradigm do not love their fellow human beings,
Mi...@mitch.org and I hate people like that."
Mi...@IntelligentParadigm.com - Tom Lehrer

AllanW

unread,
Jan 5, 2001, 8:50:07 AM1/5/01
to

> "RCN News Server" <mh...@acm.org> wrote in message
> > Actually, I like defining my own implementation of
> > operators for a class. I'd take this extension one
> > step further and allow the programmer to define
> > their own unary, binary, and tertiary operators, e.g.
> >
> > int operator mod(int lhs, int rhs);
> > int operator "<==>" (int lhs, int rhs); // Because
> > // I arbitrarily prefer <==> to <=>
> >
> > At least one problem with this would be how do you
> > specify the operator precedence. Of course this
> > extension has even less chance of making it into
> > the standard than yours does :-(.
>
"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:
> Curiously I have developed a way to define unary and
> binary operators in C++. It's nasty, but it works:
>
> (4 * cosine 1.23) + (3.5 raised_to 5.8)
>
> does what you'd expect.

I've tried and tried to figure out how to do this. I've
already given up making it "work" in any reasonable sense,
and I've tried to write something that makes it even
compile. So far, all I've come up with are

1. Bury the whole thing in a comment or in a literal string, or

2. Macro definitions written specifically to make it compile
right, such as

#define cosine 1 +
#define raised_to *

Even then, we have to assume that the above snippet is simply
an expression, used within a larger statement such as

double x =
(4 * cosine 1.23) + (3.5 raised_to 5.8)
;

So let's be clear. Are you saying that you're able to
write code which will allow C++ code like this:

double a;
std::cin >> a;
std::cout << "Square root is " << (a raised_to 0.5)
<< " and cube is " << (a raised_to 3.0)
<< ", but cosine is " << (cosine a);

to not only be legal syntax, but to work correctly?

(Parenthesis used around both expressions, because at this
point I don't care if we can make operator precedence
convenient or not; I'm just astonished that this is
possible at all!)

Please post a sample of this technique. Could you show me
how to implement a trivial unary operator, such as "abs",
and a trivial binary operator, such as "plus"?

Thanks very much!

--
All...@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Thomas Engelmeier

unread,
Jan 5, 2001, 9:09:34 AM1/5/01
to
In article <3A54504C...@dresdner-bank.com>, James Kanze
<James...@dresdner-bank.com> wrote:

> > Ever heard of Mac OS? It has no way of checking exit codes.
>
> I've never used it, no. So how do you write makefiles? Job scripts?
> Or any of the many other cases where a program is *not* invoked by a
> human, using the graphic interface?

Use an event mechanismn (AppleEvents), kind of OS supported messages
with nested, typed data including an typed result and / or error code.

Makefiles? nearly noone uses them on MacOS - besides MPW, an Unix
commandline environment with a CLI and return code interface, and nShell.

Ron Natalie

unread,
Jan 5, 2001, 10:05:47 PM1/5/01
to


>
> Use an event mechanismn (AppleEvents), kind of OS supported messages
> with nested, typed data including an typed result and / or error code.

Do not confuse the value passed to "exit" or returned by main with the
necessity of the OS to return a value to a shell. In a purely windowing
environment, the run time might look somethin like:


void StartEnvironment() {
InitializeStatics();
exit(main());
}

void exit(int i) {
if(i != EXIT_SUCCESS) {
PopUpDialogBox("This program terminated with error %d", i);
}
ReallyExitTHeProgram();

Ben Liddicott

unread,
Jan 7, 2001, 9:37:55 AM1/7/01
to
"AllanW" <all...@my-deja.com> wrote in message
news:933318$9qk$1...@nnrp1.deja.com...

>
> > "RCN News Server" <mh...@acm.org> wrote in message


This is of course Evil (TM) because it pollutes the namespace. Not
recommended for Real Life (TM).

It works by overloading another operator, taking the actual type and
another do-nothing type that exists only for the type information that it
contains. Note that the precedence can be adjusted by overloading
different operators. I've used % for unary, and <<,>> for binary.

Below I've defined cosine, cmp and pwr. The cmp operator is a qsort-type
comparison, like the operator<=> I was proposing. The others are fairly
self-explanatory.

/////////////////////////////////
// main.cpp
//
#include <stdio.h>
#include <math.h>

// Unary operator cosine. Uses operator%:
struct _cosine_type_{};
#define cosine _cosine_type_()%
template<class T> T operator %(const _cosine_type_&, T t){return cos(t);};

// Binary operators are harder. They will work like this:
// arg1 op_name arg2
// Expands to:
// arg1 << _op_name_type() >> arg2


// First some template helpers for binary operators:
// this type transfers the LHS to make it available in
// the implementing function.
template <class T, class OP> struct _op_intermediate
{
_op_intermediate(T& rt):_rt(rt){};
T& _rt;
};

// now define two operator << to perform the cmp between them
// This one transfers the LHS to the other one.
template<class T1,class OP> _op_intermediate<T1, OP> operator << (T1&
rt1, OP&)
{
return _op_intermediate<T1,OP>(rt1);
}


// This one does the work

// Define cmp operator (returns -1 if lhs<rhs,
// 0 if lhs==rhs, 1 if lhs>rhs)
// This type just provides an anchor in the type system to describe
// the operator.
struct _cmp_type_{};
#define cmp << _cmp_type_() >>
template<class T1, class T2> int operator >> (_op_intermediate<T1,
_cmp_type_>&rct1, T2& rt2)
{
T1&rt1 = rct1._rt;
if(rt1 < rt2)
return -1;
if(rt1 == rt2)
return 0;
if(rt1 > rt2)
return 1;
return 2;
}

// define pwr operator
struct _pwr_type_{};
#define pwr <<_pwr_type_()>>
template<class T1, class T2> double operator >> (_op_intermediate<T1,
_pwr_type_>&rct1, T2& rt2)
{
return pow((double)rct1._rt,(double)rt2);
}

int main(int argc, char* argv[])
{
//
printf("1 cmp 2 yields %d\n", 1 cmp 2);
printf("5 pow 3 yields %g\n", 5 pwr 3);

printf("cos 1.567 yields %g\n", cosine 1.567);
printf("cos 1 yields %g\n", cosine 1);
return 0;
}


>
> Thanks very much!

S'a pleasure.

Cheers,
Ben Liddicott

James Kanze

unread,
Jan 8, 2001, 7:11:37 AM1/8/01
to
Thomas Engelmeier wrote:

> In article <3A54504C...@dresdner-bank.com>, James Kanze
> <James...@dresdner-bank.com> wrote:

> > > Ever heard of Mac OS? It has no way of checking exit codes.

> > I've never used it, no. So how do you write makefiles? Job
> > scripts? Or any of the many other cases where a program is *not*
> > invoked by a human, using the graphic interface?

> Use an event mechanismn (AppleEvents), kind of OS supported messages
> with nested, typed data including an typed result and / or error
> code.

Which I would expect to be hidden from me by the compiler run-time, at
least in the case where it is actually being used to pass a return
code.

> Makefiles? nearly noone uses them on MacOS - besides MPW, an Unix
> commandline environment with a CLI and return code interface, and
> nShell.

My point is simply that on all but the simplest systems, there are a
lot of jobs which are done by chaining programs together. Whether the
"language" in which the chain of programs is defined is called make,
shell, or JCL is really irrelevent. And on most systems, at least
some of these chains will be invoked automatically, at a fixed time,
or during start-up or shutdown, or whatever. It is thus a basic
necessity that a program can communicate back to whatever invoked it
in some form or another. From your description, Mac OS uses a more
general mechanism than most. In C/C++, however, the language
definition says that calling exit or returning from main somehow
returns a value to the calling environment; this is the standard
mechanism. A conforming implementation for Mac OS will thus convert a
call to exit or a return from main into the appropriate communications
mechanism (perhaps conditionally, if it has a means of knowing whether
someone is listening).

--
James Kanze mailto:ka...@gabi-soft.de
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627

AllanW

unread,
Jan 9, 2001, 6:52:17 PM1/9/01
to
"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:

> This is of course Evil (TM) because it pollutes the namespace. Not
> recommended for Real Life (TM).
>

Wow. That's the strangest thing I've ever seen in C++. I am
in shock.

Thanks for posting the technique. I think I'll lie down now.

--
All...@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Anatoli Tubman

unread,
Jan 10, 2001, 7:32:43 AM1/10/01
to
In article <978829333.12261.0...@news.demon.co.uk>,

"Ben Liddicott" <ben.li...@bencat.demon.co.uk> wrote:
> It works by overloading another operator, taking the actual type and
> another do-nothing type that exists only for the type information that
it
> contains. Note that the precedence can be adjusted by overloading
> different operators. I've used % for unary, and <<,>> for binary.

Hey, I invented this! Pay me royalties, or else... er... don't pay
me royalties.

http://www.deja.com/=dnc/getdoc.xp?AN=495295852

(Binary ops only, and you can add "#define pow *POW*" if you feel like
it, but otherwise it's pretty much the same)

Jokes aside, why there's no central repository for little tricks like
this?
--
Regards
Anatoli (anatoli<at>ptc<dot>com) opinions aren't


Sent via Deja.com
http://www.deja.com/

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

0 new messages