From: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Subject: Re:  Give me safe C++
Organization: MAXTAL P/L C/- University Computing Centre, Sydney
Date: Sun, 20 Dec 1992 01:09:07 GMT

In article <716@ulogic.UUCP> hartman@ulogic.UUCP (Richard M. Hartman) writes:
>In article <1992Dec6.131757.7448@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
>>In article <1992Dec3.193006.5520@almserv.uucp> e3ubec@fnma.COM writes:
>>>
>>>     I agree. My implication was that if you don't like C++, then
>>>you should look for a language that does what you want.
>>
>>	If you are employed by a large firm you may not have any choice.
>>Many organisations may chose C++ because it is an ISO standard language.
>>(Well, it will be ...) Therefore, the C++ designers have a responsibility
>>to make it as decent as possible. For many programmers, C++ will be
>>the language they are required to use, not the one they are free to choose.
>
>Au contraire.  The responsibility is to make it as *useful* as
>possible.  Utility and safety are frequently at odds.  Look at
>the difference between Pascal (safe) and C (useful).  

	And even Pascal was not so safe, eg variant records.
>
>Safety (when not being enforced by the language) is to a large
>extent (IMHO) a matter of good programming practices.  

	To some extent, yes. But safety enforced by the 
language is sometimes a good thing. For example, you would
probably agree that type-safe linkage was a Good Thing??
This is deliberately and strictly enforced by the compiler
(and linker).

	Have you lost something here? Yes, indeed, rapid
prototyping is much more difficult when routines in
parts of the code that never get called must still be
called with correct parameters.

	There are other times when enforcing something
is good because it allows automatic optimisation to be performed,
and often this also allow guarantees of correctness. For example,
the pascal for loop is guarranteed to termina, and the
control variable can always be put in a fast register.

>Like a
>seemingly ever-growing segment of the general populace, the cry
>comes "oh powers that be, protect us from ourselves", and thus
>we get laws requiring people to wear seatbelts.  It is no that
>I am against seatbelts (or safety), but I was perfectly capable
>of wearing a seatbelt before the law existed.  

	It is not so simple  Australia, which has a national
health scheme. Here the alternative "If you get hurt in a crash
and were'nt wearing a safety belt, we'll just let you die"
would not be considered politically palatable.

	Similarly, lots of kids got hurt in bicycle accidents.
Now its mandatory to wear a helmet. I didnt wear one until
I had to. Was saving those kids from brain damage such a bad thing?

>Likewise, to remove some of the "sharp
>edges" from C and C++ would be to gut them of half of their power
>and usefulness.  

	No one is talking about preventing you stuffing
up your software :-) The issue is more to make you declare
publically and loudly when you do so, so others reading
your code will know what you have done.

>>	This doesn't mean we should not provide facilities in C++
>>for writing programs which can be checked for safety by the compiler
>>or run-time system, merely that we should not remove or fail to add
>>unsafe features which have other advantages.
>
>Wait a minute.  If you add (or retain) an "unsafe feature" you
>are defeating your own point!  An unsafe feature is an unsafe 
>feature, no matter how you slice it.

	No, my point was poorly expressed. I am considering
adding 'variants', a form of secure union in which it is
impossible to access the wrong component.

	variant V [V1, V2] v=V1(2);
	select(v){
	type(V1 v1) { ... }
	type(V2 v2) { ... }
	};

Here you simply cannot access the wrong type, unlike an ordinary
union. COmpletely safe.

What I'm saying is that 

	a) ordinary unions stay. 
  	   I'm not removing them just because they're not safe.
	b) variants are needed because they allow safety not available
	   using unions. They're also more efficient.

>
>
>>	In particular where commonly used unsafe idioms are actually
>>the bast available technique, we should look at what sort of language
>>extension would facilitate expression of the idiom in a safe way.
>
>But we would not change the language to outlaw the unsafe idiom?

	Well, in this case I would not, because the idiom for
variants is only ONE use of unions.

>Then the language is still unsafe.

	Yes, in this case. But lots of programs whose correctness
was uncertain in this area could not be written in such a way to
be absolutely certain that there were no errors. You wouldn't
*have* to do this, of course.

	The 'variants' proposal makes it possible  for the compiler
to tell you if you stuff up, just like type-safe linkage.
Using unions means you have to verify every line of code by hand.

>
>>	A simple (??) language extension would allow static checking of
>>this method. The designers and users must chose if the added language
>>complexity is worth it. What do you think?
>>
>>	class PayRec;
>>	class ContractorRec;
>>	class DirectorRec;
>>	variant PayRec [EmployeeRec, ContractorRec, DirectorRec];
>>
>>	PayRec* P;
>>
>>	for(int i=0; i<nP; ++i)
>>	{
>>		cout << P[i]->name; // common field
>>		select(P[i]) // type sensitive  code below
>>		{
>>			type(EmployeeRec *E) { ... }
>>			type(ContractorRec *C) { ... }
>>			type(DirectorRec *D) { ...}
>>		}
>>	}
>
>With no language extensions, this seems equivilant to what you
>have proposed (note: off the top of my head, incomplete, uncompiled 
>example follows -- standard disclaimers apply):
>
>class PayRec {
>	public:
>		enum PayRecType { Employee, Contractor, Director };

>class EmployeeRec : public PayRec {
>...
>};

	Here is where your example fails. How do you know in advance
to derive EmployeeRec from PayRec?

	In the case of a union or variant, thats is done
after EmployeeRec is locked away in the library.

	You example is more or less correct (except you forgot
to downcast) in the sense that it works.
You will note that your code is not secure.
There is no reason to use virtual functions or a common
base here, no inheritance or other relationship exists
between these types.

	The equivalent idiom is to use

	struct PayRec {
		enum {Employee, Contractor, Director} tag;
		union {
			Employee E;
			Contractor C;
			Director D;
		};
	};

and a switch, which doesnt require the downcast (which incidentally
you forgot), and can be done after Employee, Contractor and Director
have been closed off and locked away.

Both this method and yours, however suffer from the
problem of being unsafe, and messy to code. It much easier
to say

	variant PayRec [Employee, Contractor, Director];

isnt it?

-- 
;----------------------------------------------------------------------
        JOHN (MAX) SKALLER,         maxtal@extro.ucc.su.oz.au
	Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Newsgroups: comp.lang.c++