Boost Workshop at OOPSLA 2004

A

Alf P. Steinbach

* Gabriel Dos Reis:
| | > "Andrei Alexandrescu \(See Website for Email\)"
| >
| > | | > | > "Andrei Alexandrescu wrote:
| > | > [...]
| > | > > Maybe "export" which is so broken and so useless and so abusive that
| > its
| > | > > implementers have developed Stockholm syndrome during the long years
| > | > > that
| > | > > took them to implement it?
| > | >
| > | > How is "export" useless and broken?
| > | >
| > | > Have you used it for any project? I find it very pleasant
| > | > to work with in practice.
| > |
| > | Haven't used export, and not because I didn't wanna.
| >
| > Very interesting.
|
| Well, it's very banal really. I just only had the chance to use compilers
| that don't implement export.

What I found very interesting is not the fact that you used compilers
that don't implement export. What I found interesting is that you
made such strong statements based on no actual experience, as you
confessed. I'm not saying it is bad. Just very interesting.

In this case the "no actual experience" is very relevant; it says that no
compilers available to Andrei A. for project work, implement the feature.

So for all practical purposes the feature must be useless to him.

It certainly is 100% useless to me and anybody I know: we don't have it,
and note that this argument is from lack of experience... ;-)

It's 2004.

The Standard was published in 1998.
 
R

Rob Williscroft

tom_usenet wrote in in
comp.lang.c++.moderated:
It is necessary for export though.

int helper(); //internal to definition.cpp

export template<class T>
void f()
{
helper(); //want to lookup in definition context!
}

That doesn't work without two-phase name lookup.

Two-phase lookup does far more than is nessacery though.
All that needs to be done is that the declaration of helper is
remebered during instantiation, there is no need to exclude
overloads (*) that come from the instantiators (**) context.

*) Doesn't apply with the given example, but might for helper( T )
for example.

**) My apologies for making up words, but its hard to remember all the
Standard terms for all this.
I don't think two
phase name lookup is vital otherwise, since if the inclusion model is
used, names used in the template definitions can be made visible
simply by putting the definitions before the point of instantiation
(as is usually the case anyway).

The determinate code is a secondary issue, and I think a rare problem;

We have *very* different experiences :)
impl namespaces are generally employed to make sure internal template
gubbins won't be replaced by stuff from the point of instantiation.


It's also about allowing the compiler to pre-parse and syntax check
templates even if they aren't instantiated.

Which is about writing determinate code is it not ?
I don't think it is a
common problem that someone passes something that evaluates to a
static member where a type was expected! template and typename are
annoying at best, and give people new to templates unnecessary (if
export isn't used) headaches.

I agree they are annoying, particularly ".template", there has to be
a better solution:

(* off the top of my head *)

template < typename T >
struct some_class_template
{
template:

/* type must be a typename in *all* specialization's
*/
typename type;

/* get must be a template member-function */
template <> get();

public:

/* specialization things */
};

But we've got what we've got, and I for one think its better
than the pre-standard: "I've no idea what this code does, lets
instantiate it and see".
This is the case even with two phase lookup, although I agree that
there is slightly less freedom for the template to change meaning at
instantiation time.

Its a catch 22, templates are supposed to change meaning, but in an
orderly fashion, the typename and .template cruft aside I think the
committee sucsefully found the middle ground.
But I really don't think that this was a common
cause of problems, compared to the errors people get through two-phase
name lookup related issues, was it?

It was for me, but its entirly possible my experiences wern't typical.

Rob.
 
W

Walter

Gabriel Dos Reis said:
(e-mail address removed) (Jerry Coffin) writes:
| So, if you'd prefer, I'd rephrase the question: as I recall, it's
| claimed that EDG put something like three man-years of labor into
| implementing export, and that's not all it takes to implement it
| either.

But duing the period EDG implemented export, they also implemented a
complete Java front-end. It is not like when they were implementing
export, that was the only thing they were doing.


Daveed Vandevoorde wrote 2002-06-08 in this group:
"As a point of data, it took EDG nearly two years to implement export.
During those two years,
most of our time was spent on export proper; the remaining time was spent on
other stuff (e.g., GNU C compatibility, bug fixes, etc.). Had we not
implemented export, we would have been able to
do many other interesting things and our response to improvement requests
would have been (even :) better."

and:

in 2004-02-05 in microsoft.public.vc.stl:
"There are three implementors or export (the EDG employees):
I am one of them. I, myself, _am_ claiming that it can be used
that way."

so 3 man-years looks right. Certainly, other vendors can learn from EDG, and
Daveed has shown a willingness to help, and this may reduce the time
necessary. So 2 man-years for someone already competent with the internals
of a C++ compiler is not an unreasonable figure.
 
A

Andrei Alexandrescu \(See Website for Email\)

"Andrei Alexandrescu (See Website for Email)"
Next we think, how about accepting any number of arguments. So we write:

$define min(token a, b $rest c) {
min(b, min(a, c))
}

$define min(a, b $rest c) {
min(a, min(b, c))
}

Sorry, I saw this problem when proofreading my post---I always proofread
after I post :eek:D.

The above could recurse forever when a and b are both tokens. I meant:

$define min(token a, b $rest c) {
min(b, min(a, c))
}

$define min(a, token b $rest c) {
min(a, min(b, c))
}

$define min(a, b $rest c) {
min(a, min(b, c))
}


Andrei
 
B

Bo Persson

Hyman Rosen said:
Ans pray tell what massive improvements did we see from the vendors who
didn't implement export?

Managed Extensions, and C++/CLR. Plus the D language. :)

The resources were obviously available, but somehow the priorities were
not what one could expect.


Bo Persson
 
W

Walter

Hyman Rosen said:
Ans pray tell what massive improvements did we see from the vendors who
didn't implement export?

Microsoft did C++/CLI, for example. Your argument makes sense if C++
compilers are otherwise perfect, merely lacking export, and the
implementation engineers would otherwise just go on vacation for 2 years
<g>. I know that the list of improvements people want in Digital Mars C++
gets added to nearly daily. People want faster compiles, faster generated
code, better debugging, more targets, more platforms, more libraries, etc.
 
W

Walter

I'm not sure I understand this. Do you mean that in something like:

template< typename T >
void
f( T const& t )
{
g( t ) ;
}

g will be looked up in the context of the template definition, where the
actual type of its parameter is not known? And if so, what about:

template< typename Base >
class Derived : public Base
{
public:
void f()
{
this->g() ;
}
} ;

?

I'd say that templates must have the concept of dependent names, which
are looked up at the point of instantiation.

Think of it this way. In your first example, the argument for T (let's call
it arg) is looked up in the scope of the instantiation. Then, the scope of
the definition of f is loaded. The equivalent of:

typedef arg T;

is executed, which declares T to be of type arg, and the T is installed in
the scope of instantiation. Then, the semantic analysis of f happens in the
scope of the instantiation. T is found using normal lookup rules. It works
just like a function call does, except that the "parameter passing" into the
definition scope happens at compile time rather than run time. The analogous
happens with Base in the second example.
When people argue against two-phase lookup in C++, they are saying first
of all that all names should be considered dependent. And of course,
that dependent name lookup should work exactly like any other name
lookup, and not use special rules.

C++ tries to emulate this behavior with the two-phase lookup rules. But it's
hashed up - did you know you cannot declare a local with the same name as a
template parameter? It follows weird rules like that that are all its own.
 
T

tom_usenet

Two-phase lookup does far more than is nessacery though.
All that needs to be done is that the declaration of helper is
remebered during instantiation, there is no need to exclude
overloads (*) that come from the instantiators (**) context.

You are basically saying that name lookup could occur uniformly in
both the definition and instantiation contexts (with the contexts
merged), rather than with different rules in the two contexts as is
the case with current two phase name lookup rules. This lookup would
presumably all occur only when the template was instantiated (hence
"typename" would not necessarily be needed). This would be a possible,
but unnamed namespaces and static functions and variables add
complication. e.g.

namespace
{
int helper(); //internal to definition.cpp
}

export template<class T>
void f()
{
helper(); //want to lookup in definition context!
}

The usual fact that there are no name clashes in the anonymous
namespace would no longer hold, since the instantiation context might
also have a helper function. Making the call ambiguous would be
unhelpful, completely defeating the point of anonymous namespaces in
the first place.

One way around the problem would be to ignore names from anonymous
namespaces in the instantiation context, but what if the types used to
instantiate the template are from anonymous namespaces (which is
perfectly legal, since such names have external linkage).

Two phase name lookup solves these problems quite well, but these
problems don't occur at all in the inclusion model.
*) Doesn't apply with the given example, but might for helper( T )
for example.

helper(T) wouldn't be excluded under the current rules.
Which is about writing determinate code is it not ?

I think it's mostly about catching errors (usually just typos)
earlier, so it isn't a user of a template who finds the problem, but
the developer.

Tom
 
M

Michiel Salters

[ ... ]
And yet, they shot down Herb's proposal to remove it, 28 in favor of
keeping it, 8 against.

That's not too surprising, at least to me. First of all, removing a
keyword, feature, etc., from a language is a major step, and the
majority of the committee would have to be convinced that there was a
_major_ benefit from doing so before it would pass.

True. The benefit would be only to vendors who hadn't implemented it,
and the benefit would be that they could also claim compliance.
The reality is that most of them clearly consider the current
situation perectly acceptable: the standard requires export, but
virtually everybody ignores the requirement.

True, in a implementation sense. Marketing & Sales ca't ignore it,
they must sell a compiler as "ISO minus export".
That's not a major surprise, at least to me. It appears to me that
compiler vendors mostly fall into two camps: those who have already
implemented export, and those who have no plan to do so.

Actually, I remember a finer distinction. Some vendors shipped
their compilers with older EDG frontends, but were considering
newer versions. Others (can't remember for sure) may have shipped
an export-capable version, but with export disabled. (because they
were still evaluating?) That was a camp which was certainly
considering export.
Those who've already implemented export are obviously motivated to
keep it.

Those who haven't mostly don't seem to care and have no plans to
implement it anyway.

The only vendors to whom it would be a major issue would be those who
have not implemented it, but figure they'll have to do so if it
remains in the standard. The vote more or less confirms my opinion
that this group is quite small.

Market pressure doesn't happen overnight.
The cost isn't primarily to the vendors -- it's to the users. The big
problem is that export is just the beginning of the proverbial
slippery slope.

Which slope? A slope to adding new features? I don't think so, just
have a look at the various numerical proposals. For the users? Don't
think so, most of them will deal with export only when they use a
library. Library writers will have to deal with export, but that's OK:
they reap the benefits, and on average they're more competent in
dealing with the problems of export (look at the boost library writers)
If full compliance appears unachievable, or at least totally
unrealistic, then they're left to their own judgement about what
features to leave out. In this case, those last few features they'd
have implemented for full compliance are likely to be left out.

The result is that for most people, not only is export itself
unusable, but (if they care at all about portability) quite a few
other features are rendered unusable as well.

Actually, there are saner ways to decide what to include in version X+1
Goals could be:
* compile MC++ without workarounds
* compile current boost without workarounds
* compile all standard-compliant code without "export"
I'd agree, to some extent -- it just happens that in an inclusion
model, the effects of two-phase name lookup seem relatively natural,
but in an export model they start to seem quite unnatural.

I've found that I could adjust to the effects. Basically, when you
take back one step, it's program hygieine. Don't hand out pointers
to private members, don't hand out functions using implementation
types .

Michiel Salters
 
A

Andrei Alexandrescu \(See Website for Email\)

Gabriel Dos Reis said:
"Andrei Alexandrescu \(See Website for Email\)"

[...]

| For example, let's think of writing a nice "min" macro. It should avoid
| double evaluation by distinguishing atomic tokens (identifiers or
integral
| constants) from other expressions:
|
| $define min(token a, token b) {
| (a < b ? a : b)
| }

By the end of the day, you may rediscover C++ templates... ;-p

Not if this time you read my entire post :eek:D. (And the correction, too.)

The post was meant as an illustration of a syntactic transformation that
reorders an arbitrary-length list of arguments, be they identifiers,
numbers, or more complex expressions, into a combination of function calls
and inline operators. An optimizer could have done that, but it's a very
particular optimization that depends on the semantics of min (ordering - if
min(a, b) == a and min(b, c) == b, then min(a, c) == a).

Andrei
 
K

kanze

Hyman Rosen said:
Walter wrote:
Ans pray tell what massive improvements did we see from the vendors
who didn't implement export?

It's also interesting to note that the one vendor who does implement
export is also the only (or at least was the first) one to implement all
of the new name lookup rules, and a number of other features.

FWIW: the one vendor to implement export also has some of the best
support for legacy code, with options to support several different
models of template instantiation.

To add to it, it would be difficult to find a firm which contributed
more to the standards effort -- expressed as a percentage of total
resources, I suspect that it would be impossible.

On the other hand, I've never seen any advertising from that vendor;
that seems to be one thing they economize on.

Maybe if some other vendors would invest more in the technology, and
less in advertising...
 
D

Daniel R. James

Paul Mensonides said:
Even so, the
ability to process tokens individually, regardless of the type of preprocessing
token, is far more important than any of those, because with that ability you
can make interpreters for any syntax that you like--including advanced
domain-specific languages. (For example, consider a parser generator that
operates directly on grammar productions rather than encoded grammar
productions.) Such an ability would promote C++ to a near intentional
environment.

One of the things I've been doing with the preprocessor is
implementing simple domain-specific languages. For Paul this example
will very basic, but it might interest Andrei.

I've implemented an alternative version of scope guard, using the
proprocessor to implement 'named parameters' which let's you write
something like:

void User::AddFriend(User& newFriend)
{
friends_.push_back(&newFriend);
SCOPEGUARD(guard,
using(UserCont, friends_)
on_failure(friends_.pop_back())
);
pDB_->AddFriend(GetName(), newFriend.GetName());
guard.dismiss();
}

That's an example from Andrei's original article, rewritten. Another
example:

FILE* fp=fopen("file.txt", "r");
SCOPEGUARD(guard,
using(FILE*, fp)
finally(fclose(fp))
);

You can have 'finally', 'on_failure' and 'on_success' actions, and
multiple 'using' statements. There's also some very basic syntax
checking, so that error messages aren't too bad. But they can
certainly be improved.

The code is available at:

http://www.calamity.org.uk/code/scope_guard.tar.gz

It requires boost and works on gcc, borland and visual c++ 6.5.

The implementation is very messy, but I think a lot of it can be
cleaned up and some of it factored out into libraries.

With a C99 preprocessor, and typeof/decltype it could be greatly
improved. The implementation would be a bit simpler and you wouldn't
have to specify the types in the using statements. It's not really
tested, so there are probably lots of bugs. I haven't done anything to
avoid name collisions either.

As far as domain specific languages go, the techniques used here to
implement the named parameters can be extended for more complex
languages, although the lack of recursion makes things tricky. It can
be used to parse any alphanumeric tokens, they don't have to be
function-style. I believe that Paul Mensonides has done implemented
similiar but much more sophisticated mini-languages as part of Chaos.

Daniel
 
G

Gabriel Dos Reis

| | > "Andrei Alexandrescu \(See Website for Email\)"
| >
| > [...]
| >
| > | For example, let's think of writing a nice "min" macro. It should avoid
| > | double evaluation by distinguishing atomic tokens (identifiers or
| > integral
| > | constants) from other expressions:
| > |
| > | $define min(token a, token b) {
| > | (a < b ? a : b)
| > | }
| >
| > By the end of the day, you may rediscover C++ templates... ;-p
|
| Not if this time you read my entire post :eek:D. (And the correction, too.)

I read your entire message. I did not find it appropriate to quote
about forty lines just add one. Which is why I kept the quote to a
minimum. Not an indication that I did not read past those lines.
As for the corrections, it showed up only after another around -- when I
already replied. Next time, make sure that you post the right tinhg ;-/

| The post was meant as an illustration of a syntactic transformation that
| reorders an arbitrary-length list of arguments, be they identifiers,
| numbers, or more complex expressions, into a combination of function calls
| and inline operators. An optimizer could have done that, but it's a very
| particular optimization that depends on the semantics of min (ordering - if
| min(a, b) == a and min(b, c) == b, then min(a, c) == a).

The key point of my message was that I would not be surprised if by
the time you think you have designed what you're looking for, you did
not just redicosver C++ templates, with a checking-system or concepts
that just include languinstic distinctions like Token and such.
I conjecture that only the syntax will differ (i.e. your "$").
But hey, that would not be the first time -- I just saw another
presentation last week on the very same topic (but with C as base
language not C++).
 
W

Walter

On the other hand, I've never seen any advertising from that vendor;
that seems to be one thing they economize on.

Maybe if some other vendors would invest more in the technology, and
less in advertising...

How much would you estimate Digital Mars spends on advertising? <g>
 
H

Hyman Rosen

Walter said:
Microsoft did C++/CLI, for example.

So instead of making their C++ standard-compliant, they used the
time saved by not implementing export to create a different language.
OK, I'm puzzled.
I know that the list of improvements people want in Digital Mars C++
gets added to nearly daily.

Yes. Does the list of improvements made get added to at the same rate
as well?
 
L

llewelly

The cost isn't primarily to the vendors -- it's to the users. The big
problem is that export is just the beginning of the proverbial
slippery slope. If full compliance appears achievable, most vendors
will try to achieve it, even if it means implementing a few things
don't really value.
[snip]

However - it seems several of those who've announced no intent to
implement export are nonetheless implementing everything else. So
I don't think we are sliding down that slippery slope.
If full compliance appears unachievable, or at least totally
unrealistic, then they're left to their own judgement about what
features to leave out. In this case, those last few features they'd
have implemented for full compliance are likely to be left out.

The result is that for most people, not only is export itself
unusable, but (if they care at all about portability) quite a few
other features are rendered unusable as well.

Actually, I expect within a few more years, just about everything
execpt export will be portable.
[ ... ]
I think most of those effects come not from export but from two-phase
lookup.

I'd agree, to some extent -- it just happens that in an inclusion
model, the effects of two-phase name lookup seem relatively natural,
but in an export model they start to seem quite unnatural.
[snip]

I don't know about that. I haven't used it, but I suspect it will
boil down to be a lot like the overloading rules - strange and
complex when examined in detail, with some infamous surprises -
but in practice, doing what most people expect most of the time.
 
L

llewelly


Like export, whether or not it is an improvement is in dispute, and
it's no use to those who desire portability. Or haven't you been
paying attention here lately?
 
L

llewelly

Bo Persson said:
Managed Extensions, and C++/CLR. Plus the D language. :)
[snip]

Much like export, these are of questionable benefit to those who need
portable C++ .
 
L

llewelly

Walter said:
Is export really the only improvement you want out of your existing C++
compiler?

No. But the relativist analysis has been beat to death in the past,
so I thought I'd experiment with an absolutist angle.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,269
Latest member
vinaykumar_nevatia23

Latest Threads

Top