rpj@redcloud.cad.mcc.com (Rich Johns) (01/07/89)
In Stroustroup on page 275, section 8.5.1 it states: "No initializer can be specified for a static member, and it cannot be of a class with a constructor." This could mean two things(at least): 1) if a class has a constructor, that class may NOT have static members. 2) You cannot have a static data member which needs a constructor. After discussing this with someone, I am inclined to think number 2 is correct. As such are the following assumptions correct: a) a static data member is allowed, as long as: 1) the member does not require a constructor. 2) the member is private b) a static const data member is allowed, as long as: 1) the member does not require a constructor. 2) the member is private c) a static const data member CAN have an initial value. d) a static function member is not allowed. Rich Johns, MCC CAD Program | 3500 W. Balcones Center Dr., Austin, TX 78759 ARPA: johns@mcc.com | Phone: [512] 338-3714 UUCP: {uunet,harvard,gatech,pyramid}!cs.utexas.edu!milano!cadillac!johns
mball@cod.NOSC.MIL (Michael S. Ball) (01/07/89)
In article <701@cadillac.CAD.MCC.COM> rpj%cad@MCC.COM (Rich Johns) writes: > >In Stroustroup on page 275, section 8.5.1 it states: > > "No initializer can be specified for a static member, > and it cannot be of a class with a constructor." > >2) You cannot have a static data member which needs a > constructor. This is the correct interpretation. A type which has a constructor must be initialized, and there is no defining point for a static member where the compiler could put the initializer. > a) a static data member is allowed, as long as: > 1) the member does not require a constructor. > 2) the member is private There is no restriction on access. It can be public, protected or private. > b) a static const data member is allowed, as long as: Hard to see what use it is, except as a source of constant zero. usually constants must be initialized. > c) a static const data member CAN have an initial value. Only the default value of zero. > d) a static function member is not allowed. True. All of these answers apply to existing implementations of the language (cfront 1.2 ore equal). There were discussions of ways to change them at the USENIX workshop, so they should not be considered the last word. Mike Ball TauMetric Corporation
ark@alice.UUCP (Andrew Koenig) (01/07/89)
In article <701@cadillac.CAD.MCC.COM>, rpj@redcloud.cad.mcc.com (Rich Johns) writes: > In Stroustroup on page 275, section 8.5.1 it states: > > "No initializer can be specified for a static member, > and it cannot be of a class with a constructor." > This could mean two things(at least): > 1) if a class has a constructor, that class may NOT have > static members. > 2) You cannot have a static data member which needs a > constructor. (2) is correct. The reason for this is that the definition of a static data member appears as part of the class definition, which is generally replicated in several modules. If the member requires a constructor, that constructor would effectively be called in each module, thus initializing the member many times. > After discussing this with someone, I am inclined to > think number 2 is correct. As such are the following > assumptions correct: > a) a static data member is allowed, as long as: > 1) the member does not require a constructor. > 2) the member is private It doesn't have to be private. > b) a static const data member is allowed, as long as: > 1) the member does not require a constructor. > 2) the member is private It doesn't have to be private. > c) a static const data member CAN have an initial value. Yes indeed. > d) a static function member is not allowed. It would make sense, wouldn't it? class Widget { static int n; public: Widget() { n++; /* other stuff */ } ~Widget() { n--; /* other stuff */ } static int count() { return n; } /* other stuff */ }; This is an example of a Widget class that, among other things, counts how many Widgets there are in the universe. Thus if I say Widget x; cout << x.count() << "\n"; it prints 1 (unless there are other Widgets I didn't mention). Of course if there aren't any Widgets at all I can't use this notation to count them, but I should be able to call Widget::count. Anyway, it's an interesting idea, but not presently implemented. -- --Andrew Koenig ark@europa.att.com
schmidt@glacier.ics.uci.edu (Doug Schmidt) (01/08/89)
In article <1354@cod.NOSC.MIL> mball@cod.nosc.mil.UUCP (Michael S. Ball) writes: >In article <701@cadillac.CAD.MCC.COM> rpj%cad@MCC.COM (Rich Johns) writes: >> c) a static const data member CAN have an initial value. > >Only the default value of zero. > I was under the impression ( after reading some postings here and from experimenting with cfront 1.2 ) that a static const data member CAN have an initial value. As proof by existence ;-), try this out on cfront 1.2.1: ---------------------------------------- class foo { public: static const int i = 100; int a [ i ]; foo ( ) { ; } }; main ( ) { foo f; printf ( "elements in f.a = %d\n", sizeof f.a / sizeof *f.a); // should print out 100 } ---------------------------------------- > >All of these answers apply to existing implementations of the language >(cfront 1.2 ore equal). There were discussions of ways to change them >at the USENIX workshop, so they should not be considered the last word. > I hope that this working example is not just a fluke, but is rather either a part ( or soon to be a part ) of the official definition of the language. Any comments? Doug -- schmidt@ics.uci.edu (ARPA) | Per me si va nella citta' dolente. office: (714) 856-4043 | Per me si va nell'eterno dolore. | Per me si va tra la perduta gente. | Lasciate ogni speranza o voi ch'entrate.
pcg@aber-cs.UUCP (Piercarlo Grandi) (01/08/89)
In article <8695@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: In article <701@cadillac.CAD.MCC.COM>, rpj@redcloud.cad.mcc.com (Rich Johns) writes: [ ... several sensible questions about static class members ... ] [ ... equally sensible replies to such questions, with an interesting comment on static function members ... ] Frankly I find this whole business of static members difficulties a bit disappointing. I think that initialized static members, initialized static const members and such are useuful concepts and ought to be allowed. I am aware, as it has been correctly observed, that initializing static members runs the risk, in a straightforward implementation, to have multiple initializations, because the class definition is included potentially several times in several source files. I can think of three solutions to this: [1] consider static members as de facto global variables (e.g. regard "C::m" as a kind of "C_m") and allow initialization of the member outside the class, away from the definition: class C { ... static int m; ... }; int C::m = 1; which resembles the current allowed syntax for defining member functions away from their declaration, outside the class definition. Note that the rationale for doing this in the case of procedure members is exactly equivalent to the rationale for allowing this for data members (avoiding replication). [2] sidestep the problem entirely, by using an import or export syntax and mechanism . This has several other advantages, some people (including myself) reckon. [3] add yet another kludgey wart to "bunch", or "collect", or whatever tools is used to reconcile the ideal of C++ global objects with the reality of existing linkers. In my reckoning, solution [1] does not address very well the case of static members of a type with constructors, solution [3] is inelegant, as all compromises are, and solution [2] works well, and only impacts C++ compilers, not linkers. There has been a discussion in this newsgroup in the past on the relative merits of an import/export mechanism to replace the current reliance on #include, and it was not very conclusive. Can I now add that the static members problem is one fair example where the wholesale replication of text implied by #include causes problems? As to the static procedure idea, this adds a new dimension to the discussion. C++ does not have metaclasses. It also does not have a proper way of defining class attributes, as opposed to instance attributes. The static function idea to me shows that a good way to add them to the language would be to say "static members of a class definition are members of the class object, not of any instance object of that class". A possible consequence could be to define "C::m" to be the syntax used to access members of the class object, and "C.m" to access members of an instance object. Consider the example by Andrew Koenig: class Widget { static int n; public: Widget() { n++; /* other stuff */ } ~Widget() { n--; /* other stuff */ } static int count() { return n; } /* other stuff */ }; [ ... ] Of course if there aren't any Widgets at all I can't use this notation to count them, but I should be able to call Widget::count. It seems to me fairly clear that "count" is a class/factory method, in Smalltalk/Objective C terminology. Now class methods ARE useful in Smalltalk, as factory methods are useful in Objective C. Under this interpretation, the problems with static data members acquire a new dimension: they really are members of the class object, and the difficulties with them are merely a reflection of the fact that in C++ there is no explicit or clear notion and support (yet) of a class object or metaclasses. This said I would not however explicitly introduce the notion of metaclass in C++, because it seems to me that it does not belong to a language where the environment is not expected to contain much (what I mean is that certainly a C++ compiler will implement metaclasses -- the symbol table entry for a class -- but then probably this compile time structure should not become in toto a runtime entity as well). It seems that extending Andrew Koenig's idea to say that C++ acquire a mechanism like static to achive something similar to the distinction between +/- members in Objective C is not, at first sight, a terribly bad suggestion, and would be sufficient. -- Piercarlo "Peter" Grandi | ARPA: pcg%cs.aber.ac.uk@nss.cs.ucl.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcvax!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk
pcg@aber-cs.UUCP (Piercarlo Grandi) (01/08/89)
[this is a repost of an article that did not get out a week ago because of net problems -- I think it is still useful] In article <8695@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: In article <701@cadillac.CAD.MCC.COM>, rpj@redcloud.cad.mcc.com (Rich Johns) writes: [ ... several sensible questions about static class members ... ] [ ... equally sensible replies to such questions, with an interesting comment on static function members ... ] Frankly I find this whole business of static members difficulties a bit disappointing. I think that initialized static members, initialized static const members and such are useuful concepts and ought to be allowed. I know that initializing static members, as it has been correctly observed, runs the risk, in a straightforward implementation, to have multiple initializations, because the class definition is included potentially several times in several source files. I can think of three solutions to this (some other proposal was voiced in some C++ conference but I don't yet have the proceedings to look it up): [1] consider static members as de facto global variables (e.g. regard "C::m" as a kind of "C_m") and allow initialization of the member outside the class, away from the definition: class C { ... static int m; ... }; int C::m = 1; which resembles the current allowed syntax for defining member functions away from their declaration, outside the class definition. Note that the rationale for doing this in the case of procedure members is exactly equivalent to the rationale for allowing this for data members (avoiding replication). [2] sidestep the problem entirely, by using an import or export syntax and mechanism . This has several other advantages, some people (including myself) reckon. [3] add yet another kludgey wart to "bunch", or "collect", or whatever tools is used to reconcile the ideal of C++ global objects with the reality of existing linkers. In my reckoning, solution [1] does not address very well the case of static members of a type with constructors, solution [3] is inelegant, as all compromises are, and solution [2] works well, and only impacts C++ compilers, not linkers. There has been a discussion in this newsgroup in the past on the relative merits of an import/export mechanism to replace the current reliance on #include, and it was not very conclusive. Can I now add that the static members problem is one fair example where the wholesale replication of text implied by #include causes problems? As to the static procedure idea, this adds a new dimension to the discussion. C++ does not have metaclasses. It also does not have a proper way of defining class attributes, as opposed to instance attributes. The static function idea to me shows that a good way to add them to the language would be to say "static members of a class definition are members of the class object, not of any instance object of that class". A possible consequence could be to define "C::m" to be the syntax used to access members of the class object, and "C.m" to access members of an instance object. Consider the example by Andrew Koenig: class Widget { static int n; public: Widget() { n++; /* other stuff */ } ~Widget() { n--; /* other stuff */ } static int count() { return n; } /* other stuff */ }; [ ... ] Of course if there aren't any Widgets at all I can't use this notation to count them, but I should be able to call Widget::count. It seems to me fairly clear that "count" is a class/factory method, in Smalltalk/Objective C terminology. Now class methods ARE useful in Smalltalk, as factory methods are useful in Objective C. Under this interpretation, the problems with static data members acquire a new dimension: they really are members of the class object, and the difficulties with them are merely a reflection of the fact that in C++ there is no explicit or clear notion and support (yet) of a class object or metaclasses. This said I would not however explicitly introduce the notion of metaclass in C++, because it seems to me that it does not belong to a language where the environment is not expected to contain much (what I mean is that certainly a C++ compiler will implement metaclasses -- the symbol table entry for a class -- but then probably this compile time structure should not become in toto a runtime entity as well). It seems that extending Andrew Koenig's idea to say that C++ acquire a mechanism like static to achive something similar to the distinction between +/- members in Objective C is not, at first sight, a terribly bad suggestion, and would be sufficient. -- Piercarlo "Peter" Grandi | ARPA: pcg%cs.aber.ac.uk@nss.cs.ucl.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcvax!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk -- Piercarlo "Peter" Grandi | ARPA: pcg%cs.aber.ac.uk@nss.cs.ucl.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcvax!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk
mball@cod.NOSC.MIL (Michael S. Ball) (01/09/89)
In article <3381@paris.ics.uci.edu> Doug Schmidt <schmidt@glacier.ics.uci.edu> writes: >I hope that this working example is not just a fluke, but is rather >either a part ( or soon to be a part ) of the official definition >of the language. Sorry, but it is a fluke. Cfront may let it through (all programs have bugs) but many C compilers won't (or at least their linkers won't.) A variable initialized in more than one file is not legal in C, and many systems simply bomb on linking, since the compiler can't tell. The C++ language definite explicitly disallows it. The syntax for the feature that was proposed at the USENIX workshop was nothing like this. I'm not going to speculate further on what might get into the language. There are enough rumors and misconceptions flying about as it is. -Mike Ball- TauMetric Corporation (619)275-6381
jima@hplsla.HP.COM (Jim Adcock) (01/10/89)
I guess I'm confused by some of this conversation. Are some people missing the fact that static members are shared by all objects of a class?
bs@alice.UUCP (Bjarne Stroustrup) (01/16/89)
I'm sorry I haven't commented on the discussion on static members before. I have been busy. Release 2.0 will provide two new features related to static members: (1) static member functions, and (2) initialization of static members both have been mentioned in comp.lang.c++ before. I believe that the idea of static member functions originate with Jonathan Shopiro. Unfortunately, I don't know who first proposed the way of for initializing static members we adopted; Andrew Koenig brought it to my attention, but he couldn't remember who gave it to him. Both ideas were presented and discussed at the implementors workshop at the Denver C++ conference. 1: static member functions The reason for static members is to reduce the number of global names, to make it obvious which class objects belong, and to be able to apply the access control rules to names of objects and values that are not replicated one per object. This is a boon for library providers in that it avoids polluting the global name space and thereby allow easier writing of library code and safer use of multiple libraries. It was observed that these reasons applied for functions as well as for objects and the absence of static functions has been commented on repeatedly over the years. It was observed that MOST of the names a library provider wants local are in fact function names. it was observed that nonportable code, such as ((X*)0)->f(); was used to simulate static member functions (this ``trick'' is a time bomb because it will fail under some implementations of dynamic linking). We now have a facility that is logically equivalent to Modula2's qualified export and marginally more efficient than usual member function calls: class X { // ... static f(); }; f(); // error (unless there really is a global function f()) X::f(); // fine 2: initialization of static data members In earlier cfronts it was possible to have static data members, but not possible to explicitly initialize such static members. The original reference manual clearly states this limitation. This limitation means that it is impossible to have static members of classes and types that require initialization. This have been reported as a serious problem many times (about twice a month) and often as a bug by both novice and experienced users. The solution is simply to remove the restriction and allow initialization exactly as is done for member functions. For example: struct s { static const a; static X b; // ... int f(); } const s::a = 7; X s::b(1,2); int s::f() { return a; } About the time of the release of 2.0, I'll post a summary of new features and short descriptions of each.
schmidt@pompe.ics.uci.edu (Doug Schmidt) (01/16/89)
In article <8770@alice.UUCP> bs@alice.UUCP (Bjarne Stroustrup) writes: [ a useful summary of new C++ features leading to increased data abstraction and more complete information hiding ] Now that C++ provides more control over class data and function members isn't it time to consider adding control over the visibility of type declaration abstractions as well? For example, whenever I present the advantages of C++ to an Ada proponent, the discussion inevitably turns to C++'s lack of proper nesting for type declarations. The Ada advocates claim that this makes it difficult to control the name space of large programs, especially when combined with the use of many header files and multiple programmers. For example, it would be nice to be able to reuse the names of auxiliary ``helper'' types within the same include file, e.g.: ---------------------------------------- // file search_structure.h class Binary_Tree { private: class Node { // node for a binary tree private: int Item; Node *Left; Node *Right; public: Node(int New_Item); }; public: Binary_Tree(); Insert(int Item); Find(int Item); }; class Linked_List { private: class Node { // node for a linked list int Item; Node *Next; }; public: Linked_List(); Insert(int Item); Find(int Item); }; ---------------------------------------- Now, I realize that for small examples like this, the proper choice of names trivially disambiguates the different types and solves the problem. However, for very large programs, it requires a great deal of effort to keep the type namespace from getting cluttered. It would be nice if the language supported this explicitly, rather than relying upon individuals to keep track of the administrivia. I suppose one reason this isn't already implemented is due to the fact that it might break existing C programs. However, a). This has precedence, in that the proposed changes to the visibility of enumerated types declared inside structs and classes in C++ will break old C programs. I'm specifically referring to Lippman and Moo's paper from 1988 C++ USENIX Workshop. b). It would be ashame not to permit this feature, since it seems orthogonal with the data and function abstraction mentioned previously. Perhaps a reasonable solution would overload the concept of ``static'' even further, allowing lexical (a.k.a. ``static'') structure and class nestings by prepending the keyword static in front of the keywords, like this: ---------------------------------------- class Binary_Tree { private: static class Node { // only visible within the proper nesting level private: public: }; public: }; //.. same as before ---------------------------------------- Actually, cfront 1.2.1 already accepts this program (perhaps erroneously!?!). Are there other problems with this scheme that I'm overlooking? thanks, Doug Schmidt -- schmidt@ics.uci.edu (ARPA) | Per me si va nella citta' dolente. office: (714) 856-4043 | Per me si va nell'eterno dolore. | Per me si va tra la perduta gente. | Lasciate ogni speranza o voi ch'entrate.
jss@hector.UUCP (Jerry Schwarz) (01/17/89)
In article <4258@paris.ics.uci.edu> Doug Schmidt <schmidt@pompe.ics.uci.edu> writes: > >Now that C++ provides more control over class data and function >members isn't it time to consider adding control over the visibility >of type declaration abstractions as well? It would clearly be desirable and it has been suggested many times in the past. > > I suppose one reason this isn't already implemented is due to the >fact that it might break existing C programs. However, > Possibly, but this is a minor consideration. The main reason, I believe, is parsing. It is non-trivial to write a C++ grammar when you can count on the lexer to distinguish type identifiers from ordinary identifiers. (There are several cases, for example, where the distinction between an expression and a declaration is tricky) It is almost impossible if you can't. But its hard to get the lexer to understand scoping. Jerry Schwarz AT&T Bell Labs, Murray Hill
kt@msor.UUCP (Keith Tizzard) (05/23/89)
Can anyone please help to explain a sentence in Stroustrup's reference manual. On page 275 section 8.5.1 STATIC MEMBERS the last sentence states: "No initializer can be specified for a static member, and it cannot be of a class with a constructor." Two points arise: 1 the meaning of the piece after the comma is not clear to me - does it really mean that if I provide a constructor for a class then I cannot have a static member variable in that class? Zortech C++ appears to allow it - is it in error? 2 I understand the first part of the sentence but why does this restriction exist? -- Keith Tizzard MSOR Dept, University of Exeter, Streatham Court, EXETER EX4 4PU, UK tel: (+44) 0392 264463 email: kt@msor.exeter.ac.uk kt@msor.UUCP
ark@alice.UUCP (Andrew Koenig) (05/24/89)
In article <360@msor0.UUCP>, kt@msor.UUCP (Keith Tizzard) writes: > "No initializer can be specified for a static member, and it cannot > be of a class with a constructor." > 1 the meaning of the piece after the comma is not clear to me - > does it really mean that if I provide a constructor for a class > then I cannot have a static member variable in that class? No. It means that if T is a class with a constructor, no static members of a class may be of type T. Example: class T { public: T(); }; class S { public: static T t; // illegal }; This will change in C++ 2.0; the example above will be legal but S::t will have to be defined explicitly somewhere in the program: T S::t; The reason for requiring a separate definition is that the declaration of class S may be compiled several times in separate source files; requiring a single definition is the only way to cope with the various linkers out there. -- --Andrew Koenig ark@europa.att.com