Topic: Proposal for default scope


Author: dwr@cci632.cci.com (Donald W. Rouse II)
Date: Fri, 8 Jan 1993 17:36:54 GMT
Raw View
In article <1993Jan8.044714.2027@qualcomm.com> greg@qualcom.qualcomm.com (Greg Noel) writes:
[...]
>The semantics would be that all names defined in the scope would be visible
>within the scope (subject to the usual scoping/visibility rules, of course);
>names that were declared in the class description would be the only ones
>exported from the scope.  This would allow a helper function to be defined
>that had full access to the class private members, but still be type-safe,
>since the only way to access the helper functions would be from within the
>scope and the only way to enter the scope would be via the class interface.
>
>That is,
> class Class {
> public:  int func1();
> };
> Class:: {
>  int helper() { /* ... */ }
>  int func1() { /* code including calls to helper() */ }
> }
>Since helper() is not declared in the class, it is not exported from the
>scope, while func1() is declared in the class, so it is exported in the
>normal fashion.
>

You can accomplish the same thing with
 class Class {
 private: static int helper ();
 public:  int func1();
 };
although you don't get the syntactic sugar.




Author: greg@harvey.qualcomm.com (Greg Noel)
Date: Fri, 8 Jan 1993 22:58:29 GMT
Raw View
Donald W. Rouse II <dwr@cci632.cci.com> writes:
>You can accomplish the same thing with
> class Class {
> private: static int helper ();
> public:  int func1();
> };
>although you don't get the syntactic sugar.

You miss my point.  I specifically want to be able to use a type-safe
helper function that _isn't_mentioned_in_the_class_header_.  That is, the
function is _not_ part of the interface, it's part of the implementation.  A
helper function in the class header is visible, even if it is not accessible,
and can cause an ambiguity under derivation.

Another way of saying this is that there's no reason to declare names that
are part of the implementation in the class header.  If the implementation
is changed, helper functions may be added, changed, or dropped, but as long
as the _interface_ is unchanged, clients of the interface shouldn't need to
be changed.

It also permits multiple implementations of the same interface, which you
could select among based on whatever criteria you wished: speed of operation,
space efficiency, precision of result, freedom from bugs, NIH, ....  If the
implementation functions are fixed as part of the interface, this is not
always possible.
--
-- Greg Noel, Unix Guru         greg@qualcomm.com  or  greg@noel.cts.com




Author: cok@acadia.Kodak.COM (David Cok)
Date: Mon, 11 Jan 93 15:36:02 GMT
Raw View
In article <1993Jan8.044714.2027@qualcomm.com> greg@qualcom.qualcomm.com (Greg Noel) writes:
>
>That is,
> class Class {
> public:  int func1();
> };
> Class:: {
>  int helper() { /* ... */ }
>  int func1() { /* code including calls to helper() */ }
> }
>Since helper() is not declared in the class, it is not exported from the
>scope, while func1() is declared in the class, so it is exported in the
>normal fashion.
>

I agree fully with your desire to provide helper functions with access to
a class which do not appear in the class declaration and thus do not
cause recompilation when they are introduced or removed.  This is how I
do it, sticking to existing C++.  It's not as good as having language
facilities to add helper functions into a class without affecting the
header file, but for the moment it is adequate.  The drawbacks are
introduction of another class name (which is publically visible), the
need for qualification of the helper functions, and being careful about
derived classes of Class when used in Class_helper.

Class.h:

class Class {
 friend class Class_helper;
 private: void func_private();
 public: int func1();
};


Class.C:

#include "Class.h"

class Class_helper {
 friend class Class;
private:
 static int helper() { ... }
 static int helper2(Class* c) { c->func_private(); ... }
};

typedef Class_helper Ch; // abbreviation
static Class_helper CH; // just for convenience -- see usage examples below

void Class::func_private() { ... }

int Class::func1() {
 Class_helper::helper(); // take your pick of these three alternatives
 Ch::helper();
 CH.helper();

 Ch::helper2(this);
}


It would be nice to be able to make Class_helper a nested class within Class
while still declaring it in Class.C; but if that were made possible, I imagine
that the problem which gave rise to this programming idiom could be fixed
directly.

One can also derive Class_helper from Class to get at Class's member functions
directly.  Then helper2 does not need to be static and does not need an
argument, but there would need to be a conversion from Class* to Class_helper,
so there is not a lot of gain.

David R. Cok
Eastman Kodak Company
cok@Kodak.COM




Author: mkohtala@lesti.hut.fi (Marko Kohtala)
Date: 4 Jan 93 00:52:54 GMT
Raw View
While writing the implementations to classes, I have often missed the
possibility to define a default scope like below:

class Class {
  int var;
  int func1();
  int func2();
};

Class::{ // This is just syntactic sugar to enclose the implementation
  int var;
  int func1()
  {
    /* ... */
  }
  int func2()
  {
    /* ... */
  }
}

This would be treated as

class Class {
  static int var;
  int func1();
  int func2();
};

int Class::var;
int Class::func1()
{
  /* ... */
}
int Class::func2()
{
  /* ... */
}

The point being, that the identifiers to define are searched from the
specified scope and if not found, reported as not being members of
Class.

Especially in the case of nested classes this can make the source much
more readable and easier to write and maintain.

This idea could be extended to apply with compound statements, in
which case any unmatched identifiers should be searched for in
enclosing scopes. Also operators `.' and `->' should be implemented in
addition to `::' to be able to access instance members:

Class::{ /* statement list */ }
 The statements in the list could access by default the static members
 of the Class or in member functions the ancestor Class members. Of
 course, if the referenced variable is not a member, it is searched
 for in enclosing scope.

Class_var.{ /* statement list */ }
Class_ptr->{ /* statement list */ }

 These would access the members in the class instance specified.

I am not really a C++ language expert, so I do not know if there will
be any conflicts with these additions to the language. At least, if
there are no conflicts, I think they should be quite easy to implement
after the details have been well specified (which I have not done, as
you can see).

Please, tell me if it is possible to include this in the language.
--
---
Marko Kohtala - INTERNET:Marko.Kohtala@hut.fi, mkohtala@otax.tky.hut.fi
Student at (not representative of) the Helsinki University of Technology




Author: greg@qualcom.qualcomm.com (Greg Noel)
Date: Fri, 8 Jan 1993 04:47:14 GMT
Raw View
In article <mkohtala.726108774@vipunen.hut.fi> Marko.Kohtala@hut.fi suggests
the use of Class::{ /* ... */ } as syntactic sugar so that class members
could be defined in the scope without the need to explicitly put the class
prefix on each member.  He argues that this would make the code easier to
write and maintain.

His example is that
>
>Class::{
>  int var;
>  int func1() { /* ... */ }
>}
>
>... would be treated as
>
>int Class::var;
>int Class::func1() { /* ... */ }

I don't know if I agree with that reason, but I would like to see something
like this as a clean way to allow ``helper functions'' in the implementation
of the class.  This particular syntax has the advantage of being intuitive,
since ``Class::'' already means ``open the class scope in this context'' in
other places.

The semantics would be that all names defined in the scope would be visible
within the scope (subject to the usual scoping/visibility rules, of course);
names that were declared in the class description would be the only ones
exported from the scope.  This would allow a helper function to be defined
that had full access to the class private members, but still be type-safe,
since the only way to access the helper functions would be from within the
scope and the only way to enter the scope would be via the class interface.

That is,
 class Class {
 public:  int func1();
 };
 Class:: {
  int helper() { /* ... */ }
  int func1() { /* code including calls to helper() */ }
 }
Since helper() is not declared in the class, it is not exported from the
scope, while func1() is declared in the class, so it is exported in the
normal fashion.

I like it.  It's a way of sneaking up on modules/packages without adding
any new tokens to the language.

It does have the disadvantage that it makes the language larger.  On the
other hand, it would seem to eliminate the desire, expressed by several
people, for nested functions.  Such nested functions would usually be
helper functions in the implementation of a class, so by being able to
expand the class context to include non-nested functions would provide
an efficient solution.

So what do other people think?  It may be (probably is?) too late to
include this in the current C++ standardization effort, but if there is
some consensus that this syntax is reasonable, it might be possible to
nudge some vendors to try it as an extension.  (If it isn't too late,
how would I go about proposing it to the standards committee?)

If you grant that helper functions are needed, but don't like this idea
because it adds to the size of the language, an alternative would be to
take something that is syntactically legal but semantically forbidden and
define semantics for it.  I have thought about
 static /* type */ Class::Helper( /* params */) { /* ... */ }
which currently has no semantics (class functions cannot be defined as
static) and treat it as if it were declared (at file scope) as a private
member of the class.  It would only be accessible to members and friends
within the same file, so it too should be type-safe.
--
-- Greg Noel, Unix Guru         greg@qualcomm.com  or  greg@noel.cts.com




Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Fri, 8 Jan 1993 06:44:03 GMT
Raw View
greg@qualcom.qualcomm.com (Greg Noel) writes:

>In article <mkohtala.726108774@vipunen.hut.fi> Marko.Kohtala@hut.fi suggests
>the use of Class::{ /* ... */ } as syntactic sugar so that class members
>could be defined in the scope without the need to explicitly put the class
>prefix on each member.  He argues that this would make the code easier to
>write and maintain.
[...]
>It does have the disadvantage that it makes the language larger.  On the
>other hand, it would seem to eliminate the desire, expressed by several
>people, for nested functions.  Such nested functions would usually be
>helper functions in the implementation of a class, so by being able to
>expand the class context to include non-nested functions would provide
>an efficient solution.

Many people seem to think that the purpose of nested functions is purely
as encapsulation, a sort of code organization/modularization feature.
While it is true that they do support this form of encapsulation, the
real reason that they are useful is their access to parameters and local
variables, and the fact that their addresses can be passed to any function
that just expects a function parameter.

If a local function never has its address taken, then it does not use
the full power of nested functions.

--
Fergus Henderson             fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!