Topic: selectany / inline data
Author: allan_w@my-dejanews.com (Allan W)
Date: Wed, 7 May 2003 09:33:38 +0000 (UTC) Raw View
> allan w@my-dejanews.com (Allan W) writes:
> |> Maybe this would work better?
> |> goto (strcmp(a,b)) less than, equal to, greater than;
kanze@alex.gabi-soft.fr (James Kanze) wrote
> It's an idea. Since goto cannot be presently followed by a (, it
> can't break any legal code.
>
> But it doesn't solve the real problem: spaghetti.
I'll agree that the new 3-way switch or goto would be of use in the
next obfuscated C contest (presuming they allow C++). But that doesn't
mean it isn't useful. You could just as easily argue that the current
if or if/else isn't needed, because we can do the same thing with switch
and (almost always) the trinary operator. (You could also do the same
thing with for and while, but that's just showing off.)
I think that the essence of our distinct viewpoints boils down to this:
> The goal was to have exactly one way of expressing each of the major
> structures (selection, looping, assignment and procedure call). Given
> that goal, the solution is obvious: add enough options to the syntax
> to express whatever is needed:-).
Right or wrong, clearly this was NOT the intent of the whole C++
committee, of Bjarne Stroustrup, of the C committee, of Kernigan and
Ritchie, etc.
The goal is interesting. With fewer ways to express the same algorithm,
programmers might make fewer errors, which might be easier to catch in
code reviews, the compiler would be easier to write and might do a
better job of optimizing, analysis and documentation tools would be
easier to create, etc., etc.
On the other hand, I've had experience with one language (*) that works
this way. It was one of the worst years of my life; ten years later, I
still haven't quite recovered.
(*) The language was CSP (Cross Systems Program), IBM's attempt at a 4GL.
To be fair, this is my only real experience with a 4GL; perhaps others
don't suck so much.
> |> Virtual functions and such reduce the need for switch statements,
> |> but they are still a vitally important part of the language, IMHO.
>
> They == switch statements, I presume. (My understanding of English
> grammar is that in such cases, the antecedant of "they" would be the
> subject of the clause preceding the but.)
Hmm, perhaps not my most poetic work. I meant to say: Virtual functions
reduce the need for switch statements, but they don't make switch
statements totally obsolete. Switch statements are a vital part of the
language. In any given program, it would be possible to replace
switch statements with chained if/else statements -- but it would be
harder to write, read, and maintain. Switch statements help the C++
language to remain expressive.
> I agree. [The switch statement is] not like goto; I still use
> them in specific cases. But while the current syntax has some
> major flaws, it's not as if we cannot live with it.
I wish there was a way to create break-less switches without breaking
existing code. I doubt that there is, unless we introduce a new keyword.
> |> > Failing that (and I really don't think it worth the bother), I
> |> > wouldn't oppose a standard template function sign, with the
> |> > semantics:
>
> |> > template< typename T >
> |> > int
> |> > sign( T op1 , T op2 )
> |> > {
> |> > return op1 < op2 ? -1 : op2 < op1 : 1 ? 0 ;
> |> > }
>
> |> (In namespace std, I'm sure you meant.)
>
> I'm not sure. If it is to be viewed as an essential part of switch,
> then perhaps it should be handled like operator new (which is in the
> global namespace). No strong opinions, frankly.
You yourself added the phrase "standard template function sign." I
don't see any reason why it wouldn't go into namespace std. Furthermore,
this approach is less likely to break existing code.
> |> Standardizing this might improve the likelihood of some compilers
> |> optimizing it's use in switch() statements with the obvious three
> |> cases.
>
> Perhaps. The C standard went out of its way to make verifying
> implementations legal. But I haven't seen any. But you're probable
> right: if it is standardized, people will use it, and if people use
> it, compilers will think of how to optimize it.
Yes, that's what I meant.
> |> Even if it doesn't get any special optimization, I still see it
> |> being quite useful:
>
> |> float my abs(float x) { return x * std::sign(x); }
>
> Which would probably be slower (and less readable) than the classic
> implementation.
It's probably either slower or the same speed, yes. And I agree that
some (many?) programmers would find it harder to read, but some
mathemeticians might even find it easier to read.
> Anyway, I do think that there is enough reasonable use to propose it
> as an addition to the library.
Thank you.
> Other than that, while the rest of the
> above has an intellectual interest to me, I don't find any of it worth
> the effort necessary for standardization, and I certainly don't have
> the time myself to follow through with it.
I understand.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 7 May 2003 17:11:20 +0000 (UTC) Raw View
allan_w@my-dejanews.com (Allan W) wrote in message
news:<7f2735a5.0305061403.2d0290e2@posting.google.com>...
> > allan w@my-dejanews.com (Allan W) writes:
> > |> Maybe this would work better?
> > |> goto (strcmp(a,b)) less than, equal to, greater than;
> kanze@alex.gabi-soft.fr (James Kanze) wrote
> > It's an idea. Since goto cannot be presently followed by a (, it
> > can't break any legal code.
> > But it doesn't solve the real problem: spaghetti.
> I'll agree that the new 3-way switch or goto would be of use in the
> next obfuscated C contest (presuming they allow C++). But that doesn't
> mean it isn't useful. You could just as easily argue that the current
> if or if/else isn't needed, because we can do the same thing with
> switch and (almost always) the trinary operator. (You could also do
> the same thing with for and while, but that's just showing off.)
I'm not saying that it has no use. Just that it doesn't seem useful
enough to justify the effort of adding it to the language.
> I think that the essence of our distinct viewpoints boils down to
> this:
> > The goal was to have exactly one way of expressing each of the major
> > structures (selection, looping, assignment and procedure call).
> > Given that goal, the solution is obvious: add enough options to the
> > syntax to express whatever is needed:-).
> Right or wrong, clearly this was NOT the intent of the whole C++
> committee, of Bjarne Stroustrup, of the C committee, of Kernigan and
> Ritchie, etc.
No. It was my goal in designing an experimental language. I wanted to
see what the implications were, not necessarily develope something
useful.
> The goal is interesting. With fewer ways to express the same
> algorithm, programmers might make fewer errors, which might be easier
> to catch in code reviews, the compiler would be easier to write and
> might do a better job of optimizing, analysis and documentation tools
> would be easier to create, etc., etc.
> On the other hand, I've had experience with one language (*) that
> works this way. It was one of the worst years of my life; ten years
> later, I still haven't quite recovered.
Well, I don't know that my language was that great:-).
> (*) The language was CSP (Cross Systems Program), IBM's attempt at a
> 4GL. To be fair, this is my only real experience with a 4GL; perhaps
> others don't suck so much.
> > |> Virtual functions and such reduce the need for switch
> > |> statements, but they are still a vitally important part of the
> > |> language, IMHO.
> > They == switch statements, I presume. (My understanding of English
> > grammar is that in such cases, the antecedant of "they" would be the
> > subject of the clause preceding the but.)
> Hmm, perhaps not my most poetic work. I meant to say: Virtual
> functions reduce the need for switch statements, but they don't make
> switch statements totally obsolete. Switch statements are a vital part
> of the language. In any given program, it would be possible to replace
> switch statements with chained if/else statements -- but it would be
> harder to write, read, and maintain. Switch statements help the C++
> language to remain expressive.
To which I agree. I still use switch from time to time.
> > I agree. [The switch statement is] not like goto; I still use them
> > in specific cases. But while the current syntax has some major
> > flaws, it's not as if we cannot live with it.
> I wish there was a way to create break-less switches without breaking
> existing code. I doubt that there is, unless we introduce a new
> keyword.
I would like what I would call a working switch statement, in which each
case was a block (or a single instruction, which could be a compound
instruction). Like the three way go to, however, I don't think that the
benefits are enough to justify the effort.
> > |> > Failing that (and I really don't think it worth the bother), I
> > |> > wouldn't oppose a standard template function sign, with the
> > |> > semantics:
> > |> > template< typename T >
> > |> > int
> > |> > sign( T op1 , T op2 )
> > |> > {
> > |> > return op1 < op2 ? -1 : op2 < op1 : 1 ? 0 ;
> > |> > }
> > |> (In namespace std, I'm sure you meant.)
> > I'm not sure. If it is to be viewed as an essential part of switch,
> > then perhaps it should be handled like operator new (which is in the
> > global namespace). No strong opinions, frankly.
> You yourself added the phrase "standard template function sign." I
> don't see any reason why it wouldn't go into namespace std.
> Furthermore, this approach is less likely to break existing code.
I wrote "standard template function" because I was considering a
function which would be part of the standard, and which is a template.
As I say, I have no strong opinions about the issue, but I suspect that
logically, you're right, and that it goes in std::.
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T l. : +33 (0)1 30 23 45 16
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: do-not-spam-ben.hutchings@businesswebsoftware.com (Ben Hutchings)
Date: Wed, 7 May 2003 17:54:41 +0000 (UTC) Raw View
In article <7f2735a5.0305061403.2d0290e2@posting.google.com>, Allan W wrote:
> kanze@alex.gabi-soft.fr (James Kanze) wrote
<snip>
>> I agree. [The switch statement is] not like goto; I still use
>> them in specific cases. But while the current syntax has some
>> major flaws, it's not as if we cannot live with it.
>
> I wish there was a way to create break-less switches without breaking
> existing code. I doubt that there is, unless we introduce a new keyword.
<snip>
There's no need for a new keyword when there are so many tokens that could
be (ab)used after switch instead of an open-parenthesis. Let me suggest
the "switch++" statement. :-)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pasa@lib.hu ("Balog Pal")
Date: Wed, 7 May 2003 21:58:16 +0000 (UTC) Raw View
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D MODERATOR'S COMMENT:=20
Please wrap lines at <78 columns.
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D END OF MODERATOR'S COMMENT
"James Kanze" <kanze@alex.gabi-soft.fr> wrote in message news:867k9ghsuc.=
fsf@alex.gabi-soft.fr...
|> Order is indeed a problem. Serious problem that hits. And one that
|> IMO shall be covered ASAP. But It is an unrelated issue.
>It's not. Once you allow dynamic initialization, you have order of
initialization problems.
By 'unrelated' I meant it's a problem that will supposedly be solved on i=
ts own route. And that solution will cover this instance of the problem. =
=20
|> > The current rules guarantee that the initialization will occur
|> > before the first use after main of anything in the translation
|> > unit that contains the definition. What does that mean here?
|> I see no problem in implementing the order to make the
|> initialisatoion before anythng that follows the object. =20
>In every compilation unit in which it is included? What do you do in
>the case of conflicts?
There are no conflicts with the 'before' case.=20
|> But you're right, another thing can contradict the current order
|> rules: that the initialisation happens _after_ anything that is
|> before this object in the translation unit. But I think is more
|> like a theoretucal problem, and can be covered by ODR. (If it's
|> not clear what I mean, please just read on. )
Let's have module A; objects encountered as a11, a12, i1, i2, b11, b12. =
And module B, with objects a21, a22, i1, i2, b21, b22. i1 and i2 are t=
he 'inline' objects.
The linker will see modules A then B, and generates a list of initialiser=
s a11, a12, i1, i2, b11, b12, a21, a22, b21, b22. For B then A, it will=
be a21, a22, i1, i2, b21, b22, a11, a12, b11, b12.
Note, that i* is initialised before _any_ bXX whatever you do. Any object=
that appears _after_ an inline will find it surely initialised by the ti=
me of it's own init. i1 is inited either at its own place in order (it =
it is the first module having it) or it is inited well before the first i=
tem in this module (for the other case).
The problematic case can be the init of i itself. Suppose i1 is dependent=
on a11. Or i2 dependent on i1. But for those cases you must really fi=
ght to shoot yourself in the leg. Like using extern i1; int one module a=
nd inline i1 in another. If that is considered a dangerous case, it =
can be promoted from general ODR issue to one diagnosed at compile time. =
(The compiler can see the contradicting declarations as it can catch ext=
ern/static now.)
>The problem isn't generating the code or getting just one version
>linked in. The proble is when to call it.
And what that problem? Call it at the natural place for the first instan=
ce, discard the others. Or I could even accept the trick used for scoped=
statics using a flag.=20
>The current rules define order within a compilation unit. And there
>must be a single definition, so it is in a specific compilation unit.
>Your extension allows the same initialization to be specified in
>several compilation units. With perhaps a conflicting order.
IMHO for any practical use you get all the init guarantees one may want. =
Certainly if the ony acceptable aim is 'nothing can be chaged a bit' tha=
t is not possible to achieve, but that prevents any progress, does it?
>It probably isn't a killer problem. But it is an issue which has to
>be addressed. Addressing it takes work, even if there were a trivial
>solution. And to date, I've yet to see any benefits which would
>accrue from such work.
I think the solution IS on that trivial level.=20
And I see the benefit in removing forced redundancy for redular objects. =
And tons of hassle for templates, that want a static member.
And finally letting go the const->static hack is a benefit in my eyes too=
.=20
>First, it would be nice if you'd talk about things everyone could
>understand. I have no idea what you mean by selectany; it certainly
>isn't part of my compiler technology vocabulary. From your
>description, I think it works vaguely something like Fortran named
>common blocks. In which case, there's nothing new about it.
DOH. I thought I'm clear enough with the examples, also everypne can acce=
ss more info from MSDN. Here's whet MS says on selectany:
- ------------------
selectany
Microsoft Specific =AE
__declspec( selectany ) declarator
This attribute tells the compiler that the declared global data item is a=
pick-any COMDAT (a packaged function). At link time, if multiple definit=
ions of COMDAT are seen, the linker picks one and discards the rest. See =
linker option /OPT:REF (Optimizations). If the linker option /OPT:REF is =
selected, then COMDAT elimination will occur to remove all the unreferenc=
ed data items in the linker output.
A global data item can normally be initialized only once in an EXE or DLL=
project. This attribute can be used in initializing global data defined =
by headers, when the same header appears in more than one source file. Th=
is attribute is available in both the C and C++ compilers.
Note This attribute can only be applied to the actual initialization of g=
lobal data items that are externally visible.
END Microsoft Specific
Example
This code shows how to use the selectany attribute:
//Correct - x1 is initialized and externally visible=20
__declspec(selectany) int x1=3D1;
//Incorrect - const is by default static in C++, so=20
//x2 is not visible externally (This is OK in C, since
//const is not by default static in C)
const __declspec(selectany) int x2 =3D2;
//Correct - x3 is extern const, so externally visible
extern const __declspec(selectany) int x3=3D3;
//Correct - x4 is extern const, so it is externally visible
extern const int x4;
const __declspec(selectany) int x4=3D4;
//Incorrect - __declspec(selectany) is applied to the uninitialized
//declaration of x5
extern __declspec(selectany) int x5;
- ------------------
>What extension? MS allows static const floating point to be
>initialized in the class?
The old versions I actually use doesn't even allow to init an int. :-/=20
As you see MS' selectany is for namespace scoped stuff.=20
But what is the difference between a class static and a namespace data ob=
ject? I see no difference but the scope of the identifier. Having one m=
echansm implemented why not use it anywhere it can be used?=20
|> Well, let's see what we have now:
|> // .h file:
|> extern Object o; // extern no possible init here
|> const Object co("foo");=20
|> // .cpp file:
|> Object o("foo");
|> Using what I propose, we could write:
|> //.h file
|> inline Object o("foo");
|> inline const Object co("foo");
|> The original version works only because C++ used a trick making
|> const default to static. So using that we'll have a private copy
|> of co in every unit. Hopefully everyone RTFM and do not think
|> their address are unique. Sure, the compiler will just opt away
|> the object it it can.
|> The inline one is a regular object with external linkage. The
|> whole program will have exactly one. Just similar way we have
|> template functions and inline functions.
>And when does initialization take place?
As described above. Do you see any problem with the most natural way th=
e linkers arrange the order?=20
The important issue is that objects coming _after_ the definition shall n=
ever encounter a not yet inited object. That is achieved.=20
|> It is allowed to see the definition multiple times in a single
|> translation unit. (That is not the case for const int x=3D1; stuff!
|> ) Certainly the same thing can be used in a class:
>Nobody is denying any of this. The question is mainly one of when
>initialization takes place.
Well?
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Fri, 2 May 2003 17:48:14 +0000 (UTC) Raw View
> kanze@gabi-soft.de (James Kanze) wrote
> > > I'm not really sure what you are proposing now. Fortran named
> > > common blocks in C++? Let's also add equivalence and arithmetic
> > > goto's and make it really fun.
> allan_w@my-dejanews.com (Allan W) wrote
> > I'm sure you weren't serious when you wrote this.
kanze@gabi-soft.de (James Kanze) wrote
> I presumed that the irony would have been evident enough even without a
> smilye.
It was.
> > But think again about arithmetic gotos. We already have functions like
> > strcmp() that either return negative, positive, or zero to represent
> > three different results. Currently, if you wish to branch three ways
> > for the three cases, you either need to call strcmp() twice, or store
> > the result in a named variable.
>
> > int result = strcmp(a,b);
> > if (result<0) { /* ... */ }
> > else if (result>0) { /* ... */ }
> > else { /* ... equal ... */ }
>
> > Note that switch() doesn't help, because (in two cases out of 3) we
> > don't have specific return values -- just signs.
>
> That's an arithmetic if, not the arithmetic goto that I mentioned.
My mistake. It's been a long time since I used Fortran.
> > Arithmetic gotos could improve this. With today's optimizing
> > compilers, I'm not sure if we could improve generated code or
> > not... but we certainly could improve source code readibility if we
> > were allowed to write 3-way branches like this.
>
> > What would it look like? Obviously the Fortran syntax wouldn't be
> > helpful as-is, because C++ code doesn't have line numbers.
>
> Fortran doesn't have line numbers. It has labels, just like C/C++.
> With the difference that the syntax for a label was [1-9][0-9]*.
I knew that what I called "line numbers" did not, in fact, number
every line... I guess I used the wrong name for them, but I was in
fact referring to labels.
> > 1. We could use labels:
> > if (strcmp(a,b)) less_than, equal_to, greater_than;
> > // Does a "goto" to one of these labels
> > This might present parser problems, if it isn't immediately obvious
> > that less_than, equal_to, and greater_than are all "goto" targets.
>
> It's not obvious at all. What you have written is already legal C/C++,
> with well defined semantics.
Unless, of course, less_than, equal_to, and greater_than aren't
rvalues.
Maybe this would work better?
goto (strcmp(a,b)) less_than, equal_to, greater_than;
> > 2. Or maybe just the presence of certain symbols after the if
> > condition:
> > if (strcmp(a,b)) < { /* ... less-than ... */ }
> > == { /* ... equal ... */ }
> > > { /* ... greater-than ... */ }
>
> > Although I can imagine problems where people assume they could use,
> > for instance, != or <= (there is no need for this 'cause existing if()
> > could create such conditions).
>
> This is interesting. At present, there is no way a legal program can
> contain a '<' as the first token after the closing ) of the if block.
Nor ==. I'm not sure about >.
The problems that I mentioned would be with comprehension by humans,
not parsing by the compiler.
> > 3. Or we could simply expand switch() to allow ranges:
> > switch (strcmp(a,b)) {
> > case 0: /* ... equal ... */ break;
> > case <0: /* ... less-than ... */ break;
> > case >0: /* ... greater-than ... */ break;
> > }
> > I am aware of a workaround for this that works now:
>
> > inline int threeway(int value) { return (value<0)?-1 : (value>0)?1 :0; }
> > // ...
> > switch (threeway(strcmp(a,b))) {
> > case 0: /* ... equal ... */ break;
> > case -1: /* ... less-than ... */ break;
> > case 1: /* ... greater-than ... */ break;
> > }
>
> > But this is non-obvious and inconvenient.
>
> Non-obvious, because it isn't part of the standard. It seems less
> non-obvious than a function remove that doesn't remove anything, or a
> set that is in fact a balanced tree:-). Or the fact that modulo types
> are spelled "unsigned".
Very good points.
> (Note that Fortran has a standard function with
> exactly the semantics of threeway. It's called sign.)
Ah yes... it's coming back to me now.
> IMHO, if we want to do anything along these lines, we could start by
> creating a new replacement for switch. The one time I designed a
> language, it had only one conditional statement, select, with two
> variants :
>
> select <expr>
> {case <relop> <expr>[ , case <relop> <expr>]... ':'
> <statement_list> }...
> otherwise <statement_list>
> end
>
> or
>
> select
> { case <expr>[ ',' case <expr> ]... ':'
> <statement_list> }...
> otherwise <statement_list>
> end
>
> In the first case, the <relop> could be omitted, in which case, it
> defaulted to equals. This allowed things like:
>
> Classical switch:
>
> select var
> case 0, case 1:
> something() ;
> case 2:
> somethingElse() ;
> end
>
> Three way switch:
>
> select var
> case > 0: ...
> case == 0 : ...
> case < 0: ...
> end
>
> Chained if's:
>
> select
> case a > b : ...
> case x < y : ...
> otherwise ...
> end
>
> and many other variants.
Quite elegant; extremely expressive, and very flexible.
Suppose for a moment that we didn't want a new keyword 'select'. I
think we could use almost exactly this syntax, except that we would
still need to use break statements. The existing switch statement
would them become a special case of the new switch statement.
(The new switch would no doubt be called the Kanze switch, at least
informally.)
> Personally, I don't think switch et al. is important enough in C++ to
> bother with correcting it, but if we did, I would envisage something
> like the above.
Virtual functions and such reduce the need for switch statements, but
they are still a vitally important part of the language, IMHO.
> Failing that (and I really don't think it worth the
> bother), I wouldn't oppose a standard template function sign, with the
> semantics:
>
> template< typename T >
> int
> sign( T op1 , T op2 )
> {
> return op1 < op2 ? -1 : op2 < op1 : 1 ? 0 ;
> }
(In namespace std, I'm sure you meant.)
Standardizing this might improve the likelihood of some compilers
optimizing it's use in switch() statements with the obvious three
cases.
Even if it doesn't get any special optimization, I still see it
being quite useful:
float my_abs(float x) { return x * std::sign(x); }
or:
// Usage: calc(a,b,'P') returns a+b
// calc(a,b,'M') returns a-b
// Assumptions: 'M' < 'N' < 'P'
int calc(int a, int b, char op) {
return a + std::sign(op-'N')*b;
}
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@alex.gabi-soft.fr (James Kanze)
Date: Sun, 4 May 2003 21:16:00 +0000 (UTC) Raw View
allan_w@my-dejanews.com (Allan W) writes:
[...]
|> > > 1. We could use labels:
|> > > if (strcmp(a,b)) less_than, equal_to, greater_than;
|> > > // Does a "goto" to one of these labels
|> > > This might present parser problems, if it isn't immediately
|> > > obvious that less_than, equal_to, and greater_than are all
|> > > "goto" targets.
|> > It's not obvious at all. What you have written is already legal C/=
C++,
|> > with well defined semantics.
|> Unless, of course, less_than, equal_to, and greater_than aren't
|> rvalues.
True. I guess it is rather uncommon for people to use the same names
for labels and for variables. Although to tell the truth, I wouldn't
really know. I don't think I've ever used a label in C or C++ code.
|> Maybe this would work better?
|> goto (strcmp(a,b)) less_than, equal_to, greater_than;
It's an idea. Since goto cannot be presently followed by a (, it
can't break any legal code.
But it doesn't solve the real problem: spaghetti.
|> > > 2. Or maybe just the presence of certain symbols after the if
|> > > condition:
|> > > if (strcmp(a,b)) < { /* ... less-than ... */ }
|> > > =3D=3D { /* ... equal ... */ }
|> > > > { /* ... greater-than ... */ }
|> > > Although I can imagine problems where people assume they could
|> > > use, for instance, !=3D or <=3D (there is no need for this 'cause
|> > > existing if() could create such conditions).
|> > This is interesting. At present, there is no way a legal
|> > program can contain a '<' as the first token after the closing )
|> > of the if block.
|> Nor =3D=3D. I'm not sure about >.
I suspect that > is less likely than <. But we'd better verify all of
the oddities in templates.
|> The problems that I mentioned would be with comprehension by
|> humans, not parsing by the compiler.
|> > > 3. Or we could simply expand switch() to allow ranges:
|> > > switch (strcmp(a,b)) {
|> > > case 0: /* ... equal ... */ break;
|> > > case <0: /* ... less-than ... */ break;
|> > > case >0: /* ... greater-than ... */ break;
|> > > }
|> > > I am aware of a workaround for this that works now:
|> > > inline int threeway(int value) { return (value<0)?-1 : (value=
>0)?1 :0; }
|> > > // ...
|> > > switch (threeway(strcmp(a,b))) {
|> > > case 0: /* ... equal ... */ break;
|> > > case -1: /* ... less-than ... */ break;
|> > > case 1: /* ... greater-than ... */ break;
|> > > }
|> > > But this is non-obvious and inconvenient.
|> > Non-obvious, because it isn't part of the standard. It seems
|> > less non-obvious than a function remove that doesn't remove
|> > anything, or a set that is in fact a balanced tree:-). Or the
|> > fact that modulo types are spelled "unsigned".
|> Very good points.
|> > (Note that Fortran has a standard function with exactly the
|> > semantics of threeway. It's called sign.)
|> Ah yes... it's coming back to me now.
|> > IMHO, if we want to do anything along these lines, we could
|> > start by creating a new replacement for switch. The one time I
|> > designed a language, it had only one conditional statement,
|> > select, with two variants :
|> > select <expr>=20
|> > {case <relop> <expr>[ , case <relop> <expr>]... ':'
|> > <statement_list> }...
|> > otherwise <statement_list>
|> > end
|> > or
|> > select
|> > { case <expr>[ ',' case <expr> ]... ':'
|> > <statement_list> }...
|> > otherwise <statement_list>
|> > end
|> > In the first case, the <relop> could be omitted, in which case,
|> > it defaulted to equals. This allowed things like:
|> > Classical switch:
|> > select var
|> > case 0, case 1:
|> > something() ;
|> > case 2:
|> > somethingElse() ;
|> > end
|> > Three way switch:
|> >=20
|> > select var
|> > case > 0: ...
|> > case =3D=3D 0 : ...
|> > case < 0: ...
|> > end
|> > Chained if's:
|> >=20
|> > select
|> > case a > b : ...
|> > case x < y : ...
|> > otherwise ...
|> > end
|> > and many other variants.
|> Quite elegant; extremely expressive, and very flexible.
The goal was to have exactly one way of expressing each of the major
structures (selection, looping, assignment and procedure call). Given
that goal, the solution is obvious: add enough options to the syntax
to express whatever is needed:-).
|> Suppose for a moment that we didn't want a new keyword 'select'. I
|> think we could use almost exactly this syntax, except that we
|> would still need to use break statements. The existing switch
|> statement would them become a special case of the new switch
|> statement.
And otherwise would be default:-). Quite frankly, while I think it's
doable, I'm very dubious as to whether it is worth the effort. (If I
were to invest any effort in something along these lines, it would be
making switch work correctly, without the need of break. But I find
that the current situation can be lived with, and that there are even
more important issues to be solved.)
|> (The new switch would no doubt be called the Kanze switch, at
|> least informally.)
|> > Personally, I don't think switch et al. is important enough in
|> > C++ to bother with correcting it, but if we did, I would
|> > envisage something like the above.
|> Virtual functions and such reduce the need for switch statements,
|> but they are still a vitally important part of the language, IMHO.
They =3D=3D switch statements, I presume. (My understanding of English
grammar is that in such cases, the antecedant of "they" would be the
subject of the clause preceding the but.)
I agree. It's not like goto; I still use them in specific cases. But
while the current syntax has some major flaws, it's not as if we
cannot live with it.
|> > Failing that (and I really don't think it worth the bother), I
|> > wouldn't oppose a standard template function sign, with the
|> > semantics:
|> > template< typename T >
|> > int
|> > sign( T op1 , T op2 )
|> > {
|> > return op1 < op2 ? -1 : op2 < op1 : 1 ? 0 ;
|> > }
|> (In namespace std, I'm sure you meant.)
I'm not sure. If it is to be viewed as an essential part of switch,
then perhaps it should be handled like operator new (which is in the
global namespace). No strong opinions, frankly.
|> Standardizing this might improve the likelihood of some compilers
|> optimizing it's use in switch() statements with the obvious three
|> cases.
Perhaps. The C standard went out of its way to make verifying
implementations legal. But I haven't seen any. But you're probable
right: if it is standardized, people will use it, and if people use
it, compilers will think of how to optimize it.
|> Even if it doesn't get any special optimization, I still see it
|> being quite useful:
|> float my_abs(float x) { return x * std::sign(x); }
Which would probably be slower (and less readable) than the classic
implementation.
|> or:
|> // Usage: calc(a,b,'P') returns a+b
|> // calc(a,b,'M') returns a-b
|> // Assumptions: 'M' < 'N' < 'P'
|> int calc(int a, int b, char op) {
|> return a + std::sign(op-'N')*b;
|> }
Again, I find a more obvious implementation more readable. The real
use remains a three way switch.
Anyway, I do think that there is enough reasonable use to propose it
as an addition to the library. Other than that, while the rest of the
above has an intellectual interest to me, I don't find any of it worth
the effort necessary for standardization, and I certainly don't have
the time myself to follow through with it.
--=20
James Kanze mailto:kanze@gabi-soft.fr
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France Tel. +33 1 41 89 80 93
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 30 Apr 2003 18:44:46 +0000 (UTC) Raw View
allan_w@my-dejanews.com (Allan W) wrote in message
news:<7f2735a5.0304261728.6cb40c40@posting.google.com>...
> > pasa@lib.hu ("Balog Pal") wrote
> > > I'd guess we could even reuse keyword 'inline' instead of
> > > inventing new syntax.
> kanze@gabi-soft.de (James Kanze) wrote
> > I'm not really sure what you are proposing now. Fortran named
> > common blocks in C++? Let's also add equivalence and arithmetic
> > goto's and make it really fun.
> I'm sure you weren't serious when you wrote this.
I presumed that the irony would have been evident enough even without a
smilye.
> Furthermore, I hardly see a need for Fortran common blocks in C++ --
> we already have superior ways to share data between compilation units.
We have pointer arithmetic. That allows everything you could do with
Fortran common blocks and equivalent. Sort of, at least; Fortran
guaranteed that sizeof( float ) == sizeof( int ), so you were at least
guaranteed correct alignment.
> But think again about arithmetic gotos. We already have functions like
> strcmp() that either return negative, positive, or zero to represent
> three different results. Currently, if you wish to branch three ways
> for the three cases, you either need to call strcmp() twice, or store
> the result in a named variable.
> int result = strcmp(a,b);
> if (result<0) { /* ... */ }
> else if (result>0) { /* ... */ }
> else { /* ... equal ... */ }
> Note that switch() doesn't help, because (in two cases out of 3) we
> don't have specific return values -- just signs.
That's an arithmetic if, not the arithmetic goto that I mentioned.
> Arithmetic gotos could improve this. With today's optimizing
> compilers, I'm not sure if we could improve generated code or
> not... but we certainly could improve source code readibility if we
> were allowed to write 3-way branches like this.
> What would it look like? Obviously the Fortran syntax wouldn't be
> helpful as-is, because C++ code doesn't have line numbers.
Fortran doesn't have line numbers. It has labels, just like C/C++.
With the difference that the syntax for a label was [1-9][0-9]*.
> 1. We could use labels:
> if (strcmp(a,b)) less_than, equal_to, greater_than;
> // Does a "goto" to one of these labels
> This might present parser problems, if it isn't immediately obvious
> that less_than, equal_to, and greater_than are all "goto" targets.
It's not obvious at all. What you have written is already legal C/C++,
with well defined semantics.
> 2. Or maybe just the presence of certain symbols after the if
> condition:
> if (strcmp(a,b)) < { /* ... less-than ... */ }
> == { /* ... equal ... */ }
> > { /* ... greater-than ... */ }
> Although I can imagine problems where people assume they could use,
> for instance, != or <= (there is no need for this 'cause existing if()
> could create such conditions).
This is interesting. At present, there is no way a legal program can
contain a '<' as the first token after the closing ) of the if block.
> 3. Or we could simply expand switch() to allow ranges:
> switch (strcmp(a,b)) {
> case 0: /* ... equal ... */ break;
> case <0: /* ... less-than ... */ break;
> case >0: /* ... greater-than ... */ break;
> }
> I am aware of a workaround for this that works now:
> inline int threeway(int value) { return (value<0)?-1 : (value>0)?1 :0; }
> // ...
> switch (threeway(strcmp(a,b))) {
> case 0: /* ... equal ... */ break;
> case -1: /* ... less-than ... */ break;
> case 1: /* ... greater-than ... */ break;
> }
> But this is non-obvious and inconvenient.
Non-obvious, because it isn't part of the standard. It seems less
non-obvious than a function remove that doesn't remove anything, or a
set that is in fact a balanced tree:-). Or the fact that modulo types
are spelled "unsigned". (Note that Fortran has a standard function with
exactly the semantics of threeway. It's called sign.)
IMHO, if we want to do anything along these lines, we could start by
creating a new replacement for switch. The one time I designed a
language, it had only one conditional statement, select, with two
variants :
select <expr>
{case <relop> <expr>[ , case <relop> <expr>]... ':'
<statement_list> }...
otherwise <statement_list>
end
or
select
{ case <expr>[ ',' case <expr> ]... ':'
<statement_list> }...
otherwise <statement_list>
end
In the first case, the <relop> could be omitted, in which case, it
defaulted to equals. This allowed things like:
Classical switch:
select var
case 0, case 1:
something() ;
case 2:
somethingElse() ;
end
Three way switch:
select var
case > 0: ...
case == 0 : ...
case < 0: ...
end
Chained if's:
select
case a > b : ...
case x < y : ...
otherwise ...
end
and many other variants.
Personally, I don't think switch et al. is important enough in C++ to
bother with correcting it, but if we did, I would envisage something
like the above. Failing that (and I really don't think it worth the
bother), I wouldn't oppose a standard template function sign, with the
semantics:
template< typename T >
int
sign( T op1 , T op2 )
{
return op1 < op2 ? -1 : op2 < op1 : 1 ? 0 ;
}
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T l. : +33 (0)1 30 23 45 16
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pasa@lib.hu ("Balog Pal")
Date: Sun, 27 Apr 2003 04:31:40 +0000 (UTC) Raw View
"James Kanze" <kanze@gabi-soft.de> wrote in message news:d6651fb6.0304250438.5f5ccb0d@posting.google.com...
> > > cause probl mes with regards to the order of implementation. It
> > > is, I hope, evident that some restrictions are necessary.
>
> > What problems and why restrictions?
>
> Order of initialization problems, to begin with.
Order is indeed a problem. Serious problem that hits. And one that IMO shall be covered ASAP.
But It is an unrelated issue.
> A class definition will typically be repeated many times in the program,
> once in each translation unit which uses the class. Unlike static
> initialization, dynamic initialization takes place some time after
> program start-up.
That's all very true. But I see see it as a common case, covered by the ODR rule.
The original thread merely asked to define non-int consts inited with compile-time const expressions. There dynamic stuff, and order is irrelevant. I still can't see why int is special over a double there.
For objects initialised at runtime it can be stated, that result must be identical regardless any possible orders, and definitions be identical. (ONE definition really means all definitions shall be identical, isn't it.) IMHO the programmer can avoid the possible problems easily.
> The current rules guarantee that the initialization
> will occur before the first use after main of anything in the
> translation unit that contains the definition. What does that mean
> here?
I see no problem in implementing the order to make the initialisatoion before anythng that follows the object.
But you're right, another thing can contradict the current order rules: that the initialisation happens _after_ anything that is before this object in the translation unit.
But I think is more like a theoretucal problem, and can be covered by ODR.
(If it's not clear what I mean, please just read on. )
> > I had the impression the problem came from the linkers used then.
>
> I don't know where you got that impression? There is no fundamental
> difference between this and, say, a static variable in an inline
> function, from the linker point of view.
Well, I had in mind the situation some 15 years ago. I used mainly MASM and I recall I couldn't use comdat before version 5 or 6. I thought it was the linker's limitation, as emitting such records is trivial. But I could be mistaken even then, and my memory may just fail. ;-)
> I'm not sure what linker you are talking about? The earliest MS-DOS
> linkers used the Intel object format, which has most of the support
> needed, although it would take some tricky use of segments to get by
> without a pre- or post-linker. Early Unix linkers didn't, however.
That's cool. So we have the technology, let's use it for good -- finally.
> At any rate, the problem isn't the linker as such; the problem is
> deciding where to put the initialization code so that it only gets
> executed once, and that uses have some sort of means of ensuring
> initialization before use.
Writing my original post, I had in mind only static init, where this is not a problem at all. The only task is to mute the 'alredy defined in module...' errors.
Dynamic init is not so trivial, but we have the elemetnts to implement that too. The attached init entries must be COMDAT too, and the linker shall discard all but the first one encountered.
To me it looks pretty similar to discarding the superflous entries for the object itself.
> > MS has extension in form declspec( selectany ). It does exactly the
> > same as inlines (and templates). I just fail to see any difference
> > between common 'object module code' resulting function or object
> > definitions. And C++ already has the one definition rule, so the
> > common definitions will either all match (they will, using .h files),
> > or you have UB (likely specified to pick any random candidate).
>
> What you are describing sounds like a Fortran common block (which, of
> course, linkers have supported since there was Fortran). I've never
> seen a linker which didn't support it, going back to the mid-70's, at
> least, but I don't see where it is relevant to dynamic initialization.
And you're right. The original thread was about having class static constants with const initialisers, usable at compile time. I think that could be trivially covered using selectany -- and it shall not be restricted to class material, namespace objects could be handled similarly.
And I see no real problems extending it all the way, as to include the dynamic init too.
> > I'd welcome that selectany in the next standard. It exists for quite
> > a long period, information on problems and cost of implementation can
> > be easily queried.
>
> The standard doesn't impose anything with regards to the implementation.
It's common to hear on proposals "go, and convince some compiler writer to have it as extrension, then we take it seriously". MS has that extension. So it can be implemented, can be used.
> > I'd guess we could even reuse keyword 'inline' instead of inventing
> > new syntax.
>
> I'm not really sure what you are proposing now. Fortran named common
> blocks in C++? Let's also add equivalence and arithmetic goto's and
> make it really fun.
Well, let's see what we have now:
// .h file:
extern Object o; // extern no possible init here
const Object co("foo");
// .cpp file:
Object o("foo");
Using what I propose, we could write:
//.h file
inline Object o("foo");
inline const Object co("foo");
The original version works only because C++ used a trick making const default to static. So using that we'll have a private copy of co in every unit. Hopefully everyone RTFM and do not think their address are unique. Sure, the compiler will just opt away the object it it can.
The inline one is a regular object with external linkage. The whole program will have exactly one. Just similar way we have template functions and inline functions.
It is allowed to see the definition multiple times in a single translation unit. (That is not the case for const int x=1; stuff! )
Certainly the same thing can be used in a class:
class foo
{
inline static const float fPI = 3.14f;
static string s;
};
inline string foo::s("bar"); // Can be in header
Also with templates:
template<int N>
class c
{
inline static int myN = N; // no extra fuss needed
inline static const string myNstring = MakeString(N);
};
Now, James, is it really that idiotic? I hate nonnecessary redundancy in my programs, and all I got from it is bugs and problems. That extern + definition at one place is thing we do, having no other way. But I just see no point why carry that bag for another decade.
You know people still use preprocessor to define constants. For strings, to avoid multiplication, and having no support in a class. And even ints, for #define is benign to be encountered multiple times, and const int s not. Having a few named numbers here, and there it can soon drive you mad. The 'static' way was a band-aid. Now I'd see some real solution.
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@alex.gabi-soft.fr (James Kanze)
Date: Sun, 27 Apr 2003 17:28:36 +0000 (UTC) Raw View
pasa@lib.hu ("Balog Pal") writes:
|> "James Kanze" <kanze@gabi-soft.de> wrote in message
|> news:d6651fb6.0304250438.5f5ccb0d@posting.google.com...
|> > > > cause probl mes with regards to the order of
|> > > > implementation. It is, I hope, evident that some
|> > > > restrictions are necessary.
|> > > What problems and why restrictions?
|> > Order of initialization problems, to begin with.
|> Order is indeed a problem. Serious problem that hits. And one that
|> IMO shall be covered ASAP. But It is an unrelated issue.
It's not. Once you allow dynamic initialization, you have order of
initialization problems.
|> > A class definition will typically be repeated many times in the
|> > program, once in each translation unit which uses the class.
|> > Unlike static initialization, dynamic initialization takes place
|> > some time after program start-up.
|> That's all very true. But I see see it as a common case, covered
|> by the ODR rule.
|> The original thread merely asked to define non-int consts inited
|> with compile-time const expressions. There dynamic stuff, and
|> order is irrelevant. I still can't see why int is special over a
|> double there.
|> For objects initialised at runtime it can be stated, that result
|> must be identical regardless any possible orders, and definitions
|> be identical. (ONE definition really means all definitions shall
|> be identical, isn't it.) IMHO the programmer can avoid the
|> possible problems easily.
|> > The current rules guarantee that the initialization will occur
|> > before the first use after main of anything in the translation
|> > unit that contains the definition. What does that mean here?
|> I see no problem in implementing the order to make the
|> initialisatoion before anythng that follows the object. =20
In every compilation unit in which it is included? What do you do in
the case of conflicts?
|> But you're right, another thing can contradict the current order
|> rules: that the initialisation happens _after_ anything that is
|> before this object in the translation unit. But I think is more
|> like a theoretucal problem, and can be covered by ODR. (If it's
|> not clear what I mean, please just read on. )
|> > > I had the impression the problem came from the linkers used
|> > > then.
|> > I don't know where you got that impression? There is no
|> > fundamental difference between this and, say, a static variable
|> > in an inline function, from the linker point of view.
|> Well, I had in mind the situation some 15 years ago. I used
|> mainly MASM and I recall I couldn't use comdat before version 5 or
|> 6. I thought it was the linker's limitation, as emitting such
|> records is trivial. But I could be mistaken even then, and my
|> memory may just fail. ;-)
As I said, I have no idea what you mean by "comdat". The Intel
linker, and the Intel assembler, supported common since at least
1979. Microsoft had a Fortran compiler before they had C, and you
need something along these lines to link Fortran. (I threw out my
manuals for MASM ca. 1983 on my last move. Didn't think I'd be having
any use for them again:-), and they don't have the nostalgy value of
my old 1401 autocoder manuals.)
|> > I'm not sure what linker you are talking about? The earliest
|> > MS-DOS linkers used the Intel object format, which has most of
|> > the support needed, although it would take some tricky use of
|> > segments to get by without a pre- or post-linker. Early Unix
|> > linkers didn't, however.
|> That's cool. So we have the technology, let's use it for good --
|> finally.
|> > At any rate, the problem isn't the linker as such; the problem
|> > is deciding where to put the initialization code so that it only
|> > gets executed once, and that uses have some sort of means of
|> > ensuring initialization before use.
|> Writing my original post, I had in mind only static init, where
|> this is not a problem at all. The only task is to mute the 'alredy
|> defined in module...' errors.
|> Dynamic init is not so trivial, but we have the elemetnts to
|> implement that too. The attached init entries must be COMDAT too,
|> and the linker shall discard all but the first one encountered.
|> To me it looks pretty similar to discarding the superflous entries
|> for the object itself.
The problem isn't generating the code or getting just one version
linked in. The proble is when to call it.
The current rules define order within a compilation unit. And there
must be a single definition, so it is in a specific compilation unit.
Your extension allows the same initialization to be specified in
several compilation units. With perhaps a conflicting order.
It probably isn't a killer problem. But it is an issue which has to
be addressed. Addressing it takes work, even if there were a trivial
solution. And to date, I've yet to see any benefits which would
accrue from such work.
|> > > MS has extension in form declspec( selectany ). It does
|> > > exactly the same as inlines (and templates). I just fail to
|> > > see any difference between common 'object module code'
|> > > resulting function or object definitions. And C++ already has
|> > > the one definition rule, so the common definitions will either
|> > > all match (they will, using .h files), or you have UB (likely
|> > > specified to pick any random candidate).
|> > What you are describing sounds like a Fortran common block
|> > (which, of course, linkers have supported since there was
|> > Fortran). I've never seen a linker which didn't support it,
|> > going back to the mid-70's, at least, but I don't see where it
|> > is relevant to dynamic initialization.
|> And you're right. The original thread was about having class
|> static constants with const initialisers, usable at compile time.
|> I think that could be trivially covered using selectany -- and it
|> shall not be restricted to class material, namespace objects could
|> be handled similarly. And I see no real problems extending it all
|> the way, as to include the dynamic init too.
First, it would be nice if you'd talk about things everyone could
understand. I have no idea what you mean by selectany; it certainly
isn't part of my compiler technology vocabulary. From your
description, I think it works vaguely something like Fortran named
common blocks. In which case, there's nothing new about it.
|> > > I'd welcome that selectany in the next standard. It exists
|> > > for quite a long period, information on problems and cost of
|> > > implementation can be easily queried.
|> > The standard doesn't impose anything with regards to the
|> > implementation.
|> It's common to hear on proposals "go, and convince some compiler
|> writer to have it as extrension, then we take it seriously". MS
|> has that extension. So it can be implemented, can be used.
What extension? MS allows static const floating point to be
initialized in the class?
In this case, I think that most of the worries about implementation
concern cross compilers. And I'm not sure that they are founded. But
to be sure would require quite a bit of analysis -- floating point is
NOT integral.
|> > > I'd guess we could even reuse keyword 'inline' instead of
|> > > inventing new syntax.
|> > I'm not really sure what you are proposing now. Fortran named
|> > common blocks in C++? Let's also add equivalence and arithmetic
|> > goto's and make it really fun.
|> Well, let's see what we have now:
|> // .h file:
|> extern Object o; // extern no possible init here
|> const Object co("foo");=20
|> // .cpp file:
|> Object o("foo");
|> Using what I propose, we could write:
|> //.h file
|> inline Object o("foo");
|> inline const Object co("foo");
|> The original version works only because C++ used a trick making
|> const default to static. So using that we'll have a private copy
|> of co in every unit. Hopefully everyone RTFM and do not think
|> their address are unique. Sure, the compiler will just opt away
|> the object it it can.
|> The inline one is a regular object with external linkage. The
|> whole program will have exactly one. Just similar way we have
|> template functions and inline functions.
And when does initialization take place?
|> It is allowed to see the definition multiple times in a single
|> translation unit. (That is not the case for const int x=3D1; stuff!
|> ) Certainly the same thing can be used in a class:
Nobody is denying any of this. The question is mainly one of when
initialization takes place.
--=20
James Kanze mailto:kanze@gabi-soft.fr
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France Tel. +33 1 41 89 80 93
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: allan_w@my-dejanews.com (Allan W)
Date: Mon, 28 Apr 2003 03:10:19 +0000 (UTC) Raw View
> pasa@lib.hu ("Balog Pal") wrote
> > I'd guess we could even reuse keyword 'inline' instead of inventing
> > new syntax.
kanze@gabi-soft.de (James Kanze) wrote
> I'm not really sure what you are proposing now. Fortran named common
> blocks in C++? Let's also add equivalence and arithmetic goto's and
> make it really fun.
I'm sure you weren't serious when you wrote this. Furthermore, I
hardly see a need for Fortran common blocks in C++ -- we already
have superior ways to share data between compilation units.
But think again about arithmetic gotos. We already have functions
like strcmp() that either return negative, positive, or zero to
represent three different results. Currently, if you wish to branch
three ways for the three cases, you either need to call strcmp()
twice, or store the result in a named variable.
int result = strcmp(a,b);
if (result<0) { /* ... */ }
else if (result>0) { /* ... */ }
else { /* ... equal ... */ }
Note that switch() doesn't help, because (in two cases out of 3) we
don't have specific return values -- just signs.
Arithmetic gotos could improve this. With today's optimizing compilers,
I'm not sure if we could improve generated code or not... but we
certainly could improve source code readibility if we were allowed to
write 3-way branches like this.
What would it look like? Obviously the Fortran syntax wouldn't be
helpful as-is, because C++ code doesn't have line numbers.
1. We could use labels:
if (strcmp(a,b)) less_than, equal_to, greater_than;
// Does a "goto" to one of these labels
This might present parser problems, if it isn't immediately obvious
that less_than, equal_to, and greater_than are all "goto" targets.
2. Or maybe just the presence of certain symbols after the if condition:
if (strcmp(a,b)) < { /* ... less-than ... */ }
== { /* ... equal ... */ }
> { /* ... greater-than ... */ }
Although I can imagine problems where people assume they could use,
for instance, != or <= (there is no need for this 'cause existing if()
could create such conditions).
3. Or we could simply expand switch() to allow ranges:
switch (strcmp(a,b)) {
case 0: /* ... equal ... */ break;
case <0: /* ... less-than ... */ break;
case >0: /* ... greater-than ... */ break;
}
I am aware of a workaround for this that works now:
inline int threeway(int value) { return (value<0)?-1 : (value>0)?1 :0; }
// ...
switch (threeway(strcmp(a,b))) {
case 0: /* ... equal ... */ break;
case -1: /* ... less-than ... */ break;
case 1: /* ... greater-than ... */ break;
}
But this is non-obvious and inconvenient.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Fri, 25 Apr 2003 19:16:57 +0000 (UTC) Raw View
pasa@lib.hu ("Balog Pal") wrote in message
news:<3ea74700@andromeda.datanet.hu>...
> "James Kanze" <kanze@gabi-soft.de> wrote in message news:d6651fb6.0304230
> 323.76442381@posting.google.com...
> > struct A
> > {
> > static MyClass const a( "a string", aDouble, anIntFunction(
> ) ) ;
> > } ;
> > cause probl mes with regards to the order of implementation. It
> > is, I hope, evident that some restrictions are necessary.
> What problems and why restrictions?
Order of initialization problems, to begin with.
A class definition will typically be repeated many times in the program,
once in each translation unit which uses the class. Unlike static
initialization, dynamic initialization takes place some time after
program start-up. The current rules guarantee that the initialization
will occur before the first use after main of anything in the
translation unit that contains the definition. What does that mean
here?
> I had the impression the problem came from the linkers used then.
I don't know where you got that impression? There is no fundamental
difference between this and, say, a static variable in an inline
function, from the linker point of view. It does require something more
than what typical Unix linkers were capable of twenty years ago. Any
dynamic initialization does, and C++ implementations twenty years ago
used custom pre- or post-linkers to patch in the necessary
initializations.
> The C linker had PUBDEF and EXTDEF fields for external and publicizes
> symbols. That was enough for long. Then some features, like inline
> required COMDEFs. IIRC first times only functions were used that way,
> but once the linker had comdef support, it s tarted to spread to other
> items.
I'm not sure what linker you are talking about? The earliest MS-DOS
linkers used the Intel object format, which has most of the support
needed, although it would take some tricky use of segments to get by
without a pre- or post-linker. Early Unix linkers didn't, however.
Now that I think of it, maybe this is the reason behind the different
strategies adopted for templates early on. Unix implementations had a
prelinker, which could more or less easily be used to generate the
template instantiations, provided the compiler furnished the necessary
information. It would have been possible for an MS-DOS implementation,
however, to forgo such a prelinker. (I don't remember whether Zortech
actually did.) But of course, there was nothing in the linker which
would easily support templates. So they put everything in the
compiler. But I'm just guessing about this.
At any rate, the problem isn't the linker as such; the problem is
deciding where to put the initialization code so that it only gets
executed once, and that uses have some sort of means of ensuring
initialization before use.
> MS has extension in form declspec( selectany ). It does exactly the
> same as inlines (and templates). I just fail to see any difference
> between common 'object module code' resulting function or object
> definitions. And C++ already has the one definition rule, so the
> common definitions will either all match (they will, using .h files),
> or you have UB (likely specified to pick any random candidate).
What you are describing sounds like a Fortran common block (which, of
course, linkers have supported since there was Fortran). I've never
seen a linker which didn't support it, going back to the mid-70's, at
least, but I don't see where it is relevant to dynamic initialization.
(The Intel 8086 systems of 1979 definitly supported it, for example, as
did the Microsoft linker furnished with their C compiler, version 1.0,
in the early 80's.)
> I'd welcome that selectany in the next standard. It exists for quite
> a long period, information on problems and cost of implementation can
> be easily queried.
The standard doesn't impose anything with regards to the implementation.
> I'd guess we could even reuse keyword 'inline' instead of inventing
> new syntax.
I'm not really sure what you are proposing now. Fortran named common
blocks in C++? Let's also add equivalence and arithmetic goto's and
make it really fun.
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, T l. : +33 (0)1 30 23 45 16
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pasa@lib.hu ("Balog Pal")
Date: Thu, 24 Apr 2003 02:18:17 +0000 (UTC) Raw View
"James Kanze" <kanze@gabi-soft.de> wrote in message news:d6651fb6.0304230=
323.76442381@posting.google.com...
> struct A
> {
> static MyClass const a( "a string", aDouble, anIntFunction(=
) ) ;
> } ;
>=20
> cause probl=E8mes with regards to the order of implementation. It =
is,
> I hope, evident that some restrictions are necessary.
What problems and why restrictions?
I had the impression the problem came from the linkers used then. The C l=
inker had PUBDEF and EXTDEF fields for external and publicizes symbols. T=
hat was enough for long.=20
Then some features, like inline required COMDEFs. IIRC first times only f=
unctions were used that way, but once the linker had comdef support, it s=
tarted to spread to other items.=20
MS has extension in form __declspec( selectany ). It does exactly the sam=
e as inlines (and templates).=20
I just fail to see any difference between common 'object module code' res=
ulting function or object definitions. And C++ already has the one defi=
nition rule, so the common definitions will either all match (they will, =
using .h files), or you have UB (likely specified to pick any random cand=
idate).=20
I'd welcome that selectany in the next standard. It exists for quite a=
long period, information on problems and cost of implementation can be e=
asily queried.
I'd guess we could even reuse keyword 'inline' instead of inventing new s=
yntax.=20
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]