From: mccauleyba@vax1.bham.ac.uk (Brian McCauley)
Subject: Re: Two things: typeof() and exceptions
Date: Mon, 16 Nov 1992 20:20:36 GMT
Organization: University of Birmingham

In article <MCGRANT.92Nov15134127@rascals.stanford.edu>, mcgrant@rascals.stanford.edu (Michael C. Grant) writes:
> 
> First of all, I'm disappointed that the typeof() operator suggestion did 
> not generate much discussion, save a couple of e-mail messages. Don't you
> think that it would extend the utility of templates?
typeof() is a good idea mostly but not exclusively in templates.

IMHO we should always think carefully before adding a new token to
the language after all some poor sod will have used it as a symbol.
It would not detract from the readability to use class() instead.

There is a presedent for using the token `class' in this way:
  `template<class T>' "class" meaning "T is a symbol of type class"
  `class(xxx)' "class" meaning "Convert xxx to a value of type class"

The parenthises would have to be manatory to keep the grammer simple
(possible?) to parse.

> template <class T> class Foo {    ---> <double>     <complex>
>         T data;                   ---> double data; complex data;
>         typeof(abs(T)) norm;      ---> double norm; double norm;
> }                                 --->
> One person pointed out that, in my example,
> that it must be considered that abs(const T&) should be a possible
> substitution as well (thought the tone of his message was that he
> didn't think it was necessary). Well, I agree that abs(const T&) should
> be considered by typeof(abs(T)), since standard overloading would
> consider it, but perhaps then the syntax is a bit confusing.

An important question is just what goes inside the parenthises? Is it
something with a sytax that is already used in the language? Methinks that
`abs(T)' is not. I don't think this creates an impossible situation for 
the parser but it certainly doesn't make life easy for it because the thing
given inside the parentises of abs() may be either an expression or
a type. If it is a type it denotes a generic expression of that type
and should be subjected to the same type conversion rules as would be
an expression. (This answers the question about what happens if abs(const T&) 
is actually defined).
eg.
  Blob blob;
  int foo(long,class(blob)); // int foo(long,Blob);
  class(foo(int,const volatile Blob)) a; // int a
  const class(foo(a,blob)) b; //const int b
  class(foo(1,Blob)) c; //even let us mix up the 2 syntaxes! 

As with `sizeof()' I think class() must be compile time only and hence cannot
virtual.
  Base *p=new Derived;
  class(*p) *q; // q must be Base* _not_ Derived* 

BTW `class(abs)' is indeterminate. 

> Secondly, I was reading the reference manual for Dylan (Apple's new OO
> language) and I noticed something that was pretty hot in the exception-
> handling domain. Basically, in any given procedure you can define a set
> of instructions that are guaranteed to be executed even if the rest of
> the procedure is terminated early due to an exception. Currently in C++,
> automatic variables are destroyed as the stack is unwound. But, with 
> a set of 'unwind' statements in a function, I could destroy all of the
> variables I allocated on the heap as well.
Yes? In C++ this is written thus:

void foo() {
  try { /* body of function */ }
  catch (...) { /* unwinding code */ throw; }
}

I'm sure the answer to your question can't be that simple so perhaps you'd
better explain again.

BTW you can opt for the "industrial strength pointer" way of doing things
which roughly goes like this:

template<class T> Ptr {
  struct InnerBit {
    T* ptr;
    int ref;
    InnerBit(p) : ptr(p), references(1) {}
    ~InnerBit() { delete ptr; };
  };
  InnerBit* ptr;
  cutlink() {if (ptr&&!--ptr->ref) delete ptr;} 
public:
  operator T*() {return ptr->ptr;}
  T() : p(NULL) {}
  T(T* p) : ptr(new InnerBit(p)) {}
  ~T() {cutlink();}
  T(const T& p) ptr(p.ptr) :{ if (ptr) ptr->ref++;}
  T& operator = (const T& p) {cutlink(); (ptr=p.ptr)->ref++;}
  T* operator ->() {return *this;} // see discussion on -> in this news group
}

(I've not checked this code since I haven't a complier to hand so you'll
have to excuse typos :-> )

An object allocated by:

Ptr<Blob> p = new Blob;

is automatically deleted once all the "industial strength pointers" that
refer to it have been deleted. Obviously you must be careful not to mix in
any non-industial strength pointers.

> If I had the Dylan manual with me I'd give you the exact syntax and
> description. But, if you understand that last paragraph, please
> comment! Note that that behavior could be simulated by defining a 
> class local to that function that contains in its destructor all of
> the said 'unwinid' statements. Then, when that class is destroyed by
> the stack-unwinding procedure it would give the desired effect. But,
> since exceptions haven't been implemented on a wide basis yet perhaps
> the Dylan model can be considered.
Actually the local class won't work in the general case because the
destructor is not in the scope of the function so it can't get at your
autos.
-- 
    \\   ( )    No Bullshit!     |  Email: B.A.McCauley@bham.ac.uk   
 .  _\\__[oo        from         |  Voice: +44 21 471 3789 (home)
.__/  \\ /\@    /~)  /~[   /\/[  |    Fax: +44 21 625 2175 (work)
.  l___\\      /~~) /~~[  /   [  |  Snail: 197 Harborne Lane,
 # ll  l\\    ~~~~ ~   ~ ~    ~  |         Birmingham, B29 6SS, UK
###LL  LL\\   (Brian McCauley)   |   ICBM: 52.5N 1.9W
Newsgroups: comp.lang.c++