f



generic programming and functional languages

Generic programming is receiving more attention now-a-days. I am new to
functional programming, and I came to know that Haskell supports
polymorphic procedures and polytypes. Can somebody provide more
information on that or point me to some references/resources? I am also
looking at implementation details: is it that the implementation of
parametric polymorphism in functional languages a compile-time
mechanism (like C++)?  

-Ganesh

0
sgganesh (28)
4/14/2005 6:39:22 AM
comp.lang.functional 2791 articles. 0 followers. Post Follow

217 Replies
1056 Views

Similar Articles

[PageSpeed] 22

Ganesh,

> Generic programming is receiving more attention now-a-days. I am new to
> functional programming, and I came to know that Haskell supports
> polymorphic procedures and polytypes. Can somebody provide more
> information on that or point me to some references/resources? I am also
> looking at implementation details: is it that the implementation of
> parametric polymorphism in functional languages a compile-time
> mechanism (like C++)?

It should be noted that the term 'generic programming' is actually a bit
overloaded: in the object-oriented world the term is usuallly used to
refer to programming with parametric polymorphism. In functional languages
like Haskell and ML parametric polymorphism is kind of taken for granted.
In these languages, the term 'generic programming' tends to be used for
language extensions that go beyond conventional forms of polymorphism.
Examples of these include structural polymorphism as implemented by PolyP
[1] and Generic Haskell [2], and the 'Scrap Your Boilerplate' approach.

I understand that it is non-generic---i.e., parametric---polymorphism you
are interested in. As said the parametric polymorphism is really pretty
basic in Haskell; therefore, any tutorial on the language is likely to
cover the subject; see, for example, Bird [3] or Hudak [4].

In Haskell (and ML) parameteric polymorphism is
definitely a compile-time mechanism. However, a comparison to templates in
C++ does not really hold, for AFAIK most C++ compilers do not perform
direct
checks on code containing template syntax, but rather desugar it before
processing. In Haskell, parametric polymorphism takes a much more
prominent position. Extensions for higher-ranked polymorphism even allow
polymorphic functions to be treated as first-class citizens.

Haskell programs are statically typed. That is, all type checks are
performed at compile time, and, consequently, types play no role at run
time. Implementation details thus mostly involve type checking and type
inference. If you would like to delve into the theory, I can recommend
Pierce's text book [5].

HTH,

Stefan

[1] http://www.cs.chalmers.se/~patrikj/poly/polyp/

[2] http://www.generic-haskell.org

[3] Richard Bird. Introduction to Functional Programming using Haskell.
Prentice Hall Europe, London, second edition, 1998.

[4] Paul Hudak. The Haskell School of Expression, Learning Functional
Programming Through Multimedia. Cambridge University Press, Cambridge,
2000.

[5] Benjamin C. Pierce. Types and Programming Languages. MIT Press,
Cambridge, Massachusetts, 2002.

0
sholderm (22)
4/14/2005 7:15:06 AM
sgganesh@gmail.com writes:

> Generic programming is receiving more attention now-a-days. I am new to
> functional programming, and I came to know that Haskell supports
> polymorphic procedures and polytypes. Can somebody provide more
> information on that or point me to some references/resources? I am also
> looking at implementation details: is it that the implementation of
> parametric polymorphism in functional languages a compile-time
> mechanism (like C++)?  

I'll add a bit to Stefans excellent overview regarding the last point:
In functional languages, parametric polymorphism is always
type-checked (or inferred) at compile time, as Stefan said.  However,
the code can be implemented in several ways:

 - The most common way is to use the same code for all instances of
   the type.  This requires data to be of uniform size, so all values
   that do not fit a register are "boxed" by putting them in memory
   and just passing a pointer.  This is usually done always, not just
   at calls to polymorphic functions, so there is no extra overhead in
   calling a polymorphic function, though there is a general overhead
   in maintaining the uniform representation overall.  This is similar
   to the way generics are implemented in Java, where it is restricted
   (IIRC) to object types, as these have a uniform representation.

 - Some implementations (e.g., MLTon) use C++-like compile-time
   instantiation of polymorphic functions to all the types at which
   they are used.  This allows specialization to values of different
   size etc. and does not require an overall uniform representation.
   It can, however, require many nearly-identical copies of the same
   code for different types.  Unlike C++, most functional languages
   prohibit polymrphic recursion, so the number of instances is
   guaranteed to be finite (though it can be very large).

Note that this difference is of implementation, not of language.  The
same language can, and indeed often do, implement polymorphic types
differently in different compilers.  Likewise, you will see the same
language compiled to bytecode or native code in different compilers.

        Torben

0
torbenm265 (288)
4/14/2005 7:49:30 AM
Wow! that was an excellent overview.

>>It should be noted that the term 'generic programming' is actually a
bit
>>overloaded: in the object-oriented world the term is usuallly used to

>>refer to programming with parametric polymorphism.

Yes, I was referring to that, and that provided by dynamic languages
like Smalltalk.

>> In functional languages
>>like Haskell and ML parametric polymorphism is kind of taken for
granted.
Why?

>>In these languages, the term 'generic programming' tends to be used
for
>>language extensions that go beyond conventional forms of
polymorphism.
Can you elaborate on that. Few examples on how it is unconventional?
Can it be implemented in OO languages like Smalltalk/C++? If not why?


>>Examples of these include structural polymorphism as implemented by
PolyP
>>[1] and Generic Haskell [2], and the 'Scrap Your Boilerplate'
approach.
I'm yet to go through the links. Can you explain me what is structural
polymorphism?

>>I understand that it is non-generic---i.e., parametric---polymorphism
you
>>are interested in.

I am interested in generic programming in general, but my knowledge is
limited to parametric types (as in C++) and dynamic typing (as in
Smalltalk).

>> As said the parametric polymorphism is really pretty
>>basic in Haskell; therefore, any tutorial on the language is likely
to
>>cover the subject; see, for example, Bird [3] or Hudak [4].

Why is that you consider as very basic? The ability to create
polymorphic functions/types and type inference seems to be pretty good
in Haskell. If I compare Haskell generics to that of .NET generics/Java
generics, the latter's support is trivial.

>> However, a comparison to templates in C++ does not really hold, for
AFAIK most >> C++ compilers do not perform direct checks on code
containing template syntax,
>> but rather desugar it before processing.
Which compilers you are referring to? Direct checks for non-dependent
types (ie those types that doesnt depend on template type parameters)
is made when a template is defined and checking for dependent types are
done when the template is instantiated. C++ infact enfoces direct
checks, but in two phases.

>>Haskell programs are statically typed. That is, all type checks are
>>performed at compile time, and, consequently, types play no role at
run
>>time.

Does it mean that the objects don't have runtime type information
associated with them?

-Ganesh

0
sgganesh (28)
4/14/2005 8:33:40 AM
>>This is similar  to the way generics are implemented in Java, where
it is restricted
>>   (IIRC) to object types, as these have a uniform representation.
I am not sure about this. AFAIK, in Java, the parameteric types are
provided for type-safety,
and the parameterization information is lost after compilation is done;
this is done for maintaining
backward compatibility with older versions of Java where generics was
not supported.

>> Unlike C++, most functional languages
>>    prohibit polymrphic recursion, so the number of instances is
>>    guaranteed to be finite (though it can be very large).

Why is there this limitation? Polymorphic recursion allows for new
advances (for C++) in
doing "meta-programming", and is this not possible with parametric
polymorphism with 
functional languages? 

-Ganesh

0
sgganesh (28)
4/14/2005 8:44:44 AM
sgganesh@gmail.com wrote:
>>>As said the parametric polymorphism is really pretty
>>>basic in Haskell; therefore, any tutorial on the language is likely to
>>>cover the subject; see, for example, Bird [3] or Hudak [4].
> 
> Why is that you consider as very basic? The ability to create
> polymorphic functions/types and type inference seems to be pretty good
> in Haskell. If I compare Haskell generics to that of .NET generics/Java
> generics, the latter's support is trivial.

It's "basic" in the sense that
a) it has very simple syntax and
b) there are no special caveats associated with it.

For example, Java's generics have a lot of syntactic sugar associated 
with them, and compile-time checks sometimes fail to catch typing errors 
(i.e the type system is "consistent").

I know of no OO language with a consistent static type system. (Which 
says a lot about the amount of typing knowledge in the ranks of OO 
language designers... note that the Generic Java extension were done by 
type system experts, but they had to remain compatible with what exists, 
so I don't expect that this is really type-safe.)

>>> However, a comparison to templates in C++ does not really hold,
>>> for AFAIK most C++ compilers do not perform direct checks on code
>>>  containing template syntax, but rather desugar it before
>>> processing.
> 
> Which compilers you are referring to? Direct checks for non-dependent
>  types (ie those types that doesnt depend on template type
> parameters) is made when a template is defined and checking for
> dependent types are done when the template is instantiated. C++
> infact enfoces direct checks, but in two phases.

Type-parametric code in Haskell or ML can be type-checked in isolation.

For C++, such code cannot be type-checked unless it is instantiated with 
parameter values.

That's a direct consequence of C++ templates being Turing-complete. In 
other words, in C++ templates, you can specify *any* kind of computation 
to be executed at compile time (though that may be quite tricky), while 
in typical FPLs, the parametric type system is carefully constrained to 
be statically checkable (and hence not Turing-complete).

Note that there's a little white lie involved. C++ templates would be 
Turing-complete if it were not restricted - I think there's a maximum 
instantiation depth of about 16. So you get the worst of both worlds - 
lack of static checkability and an (admittedly very loose) limit on what 
you can do with templates.

One thing that I'd like to see in FPL parametricity is the ability to 
instantiate with values. I'd really like to write types like

   vector_space 'num_dimensions 'coordinate_type

which is possible in C++ (i.e. vector_space<<3, real>>) but not in 
typical FPLs. (Main reason probably being that this would require 
differentiation between compile-time and run-time evaluation. Today's 
FPLs typically don't differentiate, leaving it to the compiler to decide 
what can be precompiled and what can't - nailing down in a language spec 
which expressions are guaranteed to evaluate at compile time and hence 
are suitable as type parameters creates language design and compiler 
implementation constraints that are difficult to change afterwards.)

>>> Haskell programs are statically typed. That is, all type checks
>>> are performed at compile time, and, consequently, types play no
>>> role at run time.
> 
> Does it mean that the objects don't have runtime type information 
> associated with them?

It wouldn't be needed to implement a run-time system.
In practice, many implementations choose to associate type information 
anyway, for other reasons. For example, garbage collection *can* be done 
without type information, but it becomes an order of magnitude more 
complex and difficult.

Regards,
Jo
0
jo427 (1164)
4/14/2005 10:48:06 AM
sgganesh@gmail.com writes:

> >>This is similar  to the way generics are implemented in Java, where
> it is restricted
> >>   (IIRC) to object types, as these have a uniform representation.
> I am not sure about this. AFAIK, in Java, the parameteric types are
> provided for type-safety,
> and the parameterization information is lost after compilation is done;
> this is done for maintaining
> backward compatibility with older versions of Java where generics was
> not supported.

Parameterization is indeed lost, but no specialized copies of generic
functions/methods are made, so generic data has to be uniform.  DUe to
backwards compatibility (as you mention), they are hence limited to
types that already have uniform representation, namely objects (that
are represented as pointers to heap-allocated structures).
Furthermore, since the JVM doesn't know about generics, arguments to
generic functions have type "object" and results are explicitly
downcast to their original type.
 
> >> Unlike C++, most functional languages
> >>    prohibit polymrphic recursion, so the number of instances is
> >>    guaranteed to be finite (though it can be very large).
> 
> Why is there this limitation? Polymorphic recursion allows for new
> advances (for C++) in
> doing "meta-programming", and is this not possible with parametric
> polymorphism with 
> functional languages? 

Most functional languages use type inference, and this is undecidable
in the presense of polymorphic recursion.  Some functional languages
allow polymorphic recursion if the polymorphic type is specified, as
checking is then decidable.  If you don't specialize polymorphic
functions, it is no problem if there is a statically unbounded number
of instances, as the same code is used for all.  If instances are
specialized at compile-time, as in C++, compilation may not terminate.

C++ programmers have, apparently, learnt to accept nontermination of
compilation, so you could argue that functional programmers should
also do so, and open up for unrestricted polymorphic recursion.

However, one can argue that meta-programming as used in C++ is better
done with a two-level language, where you can simply annotate certain
functions to be executed at compile-time.  There are type systems that
ensure type-safety of such meta-functions _before_ they are applied
(unlike in C++, where type-checking is postponed until all templates
are instantiated).

You can also do some degree of type-safe meta-programming with
Haskell-style type classes, basically by encoding the meta-information
as "phantom types", types that are only used to control the
meta-programming but are not actually used for any values.

        Torben
0
torbenm265 (288)
4/14/2005 11:38:04 AM
Joachim Durchholz wrote:
> 
> For example, Java's generics have a lot of syntactic sugar associated 
> with them,

If it were just "sugar" then you didn't have to care, but it's the basic 
syntax that is annoyingly heavy-weight. Plus, lack of type inference 
forces you to use it all over the place.

> and compile-time checks sometimes fail to catch typing errors 
> (i.e the type system is "consistent").

s/consistent/inconsistent/

> Type-parametric code in Haskell or ML can be type-checked in isolation.
> 
> For C++, such code cannot be type-checked unless it is instantiated with 
> parameter values.
> 
> That's a direct consequence of C++ templates being Turing-complete.

It's rather a consequence of templates simply being untyped (e.g. no 
signatures for template arguments).

> In practice, many implementations choose to associate type information 
> anyway, for other reasons.  For example, garbage collection *can* be done
> without type information, but it becomes an order of magnitude more 
> complex and difficult.

This is not correct. Actually, it's the other way round: type-directed 
GC is much more complicated. The argument *for* type-directed GC is the 
ability to have more efficient data representation. Unfortunately, the 
necessary overhead rarely pays off in practice. Consequently, very few 
systems use type-directed garbage collection.

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
4/14/2005 11:55:26 AM
>>For example, Java's generics have a lot of syntactic sugar associated

>>with them, and compile-time checks sometimes fail to catch typing
errors
>>(i.e the type system is "consistent").

I read [Benjamin C. Pierce. Types and Programming Languages. MIT Press,

Cambridge, Massachusetts, 2002], which also argues that type systems in
OO
languages are not consistent, but I found that its in extremely corner
cases (like that of
subtyping problem with ?: operator).

But I am not convinced that OO languages are really "bad" enough that
their type systems
are broken.

>>Type-parametric code in Haskell or ML can be type-checked in
isolation.
that is indeed surprising for me. How can you typecheck on a parametric
type without knowing
the type with which it would be instantiated with? Thats the reason why
C++ postpones the check
for operations on "dependent" names.

>> I think there's a maximum instantiation depth of about 16.
C++ standard requires a mininum of 256 instantiation depth (which is
quite enough for safe practical use).

>>(Main reason probably being that this would require
>>differentiation between compile-time and run-time evaluation. Today's

>>FPLs typically don't differentiate, leaving it to the compiler to
decide
>>what can be precompiled and what can't - nailing down in a language
spec
>>which expressions are guaranteed to evaluate at compile time and
hence
>>are suitable as type parameters creates language design and compiler
>>implementation constraints that are difficult to change afterwards.)

Why do you consider that they non-type arguments need to be a constant
expression?
It is true in case of C++, because, the template instantiation is a
compile-time mechanism.
In Ada generics, non-type arguments can indeed be variables. I don't
see why you can't
do the same in a functional lang. (but I don't know much about FP, so I
can't be sure).  

-Ganesh

0
sgganesh (28)
4/14/2005 12:58:19 PM
sgganesh@gmail.com wrote:

>>> For example, Java's generics have a lot of syntactic sugar
>>> associated with them, and compile-time checks sometimes fail to
>>> catch typing errors (i.e the type system is "inconsistent").
> 
> I read [Benjamin C. Pierce. Types and Programming Languages. MIT
> Press, Cambridge, Massachusetts, 2002], which also argues that type
> systems in OO languages are not consistent, but I found that its in
> extremely corner cases (like that of subtyping problem with ?:
> operator).
> 
> But I am not convinced that OO languages are really "bad" enough that
>  their type systems are broken.

There are two problems at work here.

One is that true subtype relationships are far rarer than one would
think, particularly if mutable data is involved.
For example, all Rectangles are Squares. If Rectangles and Squares are
immutable, then this is indeed true, but the subtype relationship does
*not* hold for the classes MutableRectangle (wich a setWidthHeight
function) and MutableSquare (which cannot be a subclass of
MutableRectangle because it has no way of implementing setWidthHeight -
it would either have to break the contract of setWidthHeight or its own
invariant).

The other is that many OO language designers are ignorant of the real
semantics of subtyping, and learn of holes in their type systems only
long after they have nailed the language semantics down. At that point,
language designers usually resort to run-time checking and exception
throwing, if they acknowledge the problem at all.

I have seen two cases here:

1) Covariance and contravariance. Most languages allow overriding a
function result with a subtype (which is sound), but some (most notably
Eiffel) allow overriding parameters as well (and that's unsound).

For a trivial example:

class foo {
   some_type attribute;
   virtual set_attribute (some_type new_value) {
     attribute = new_value;
   }
}

class foo2 inherit bar {
   some_subtype attribute;
   virtual set_attribute (some_subtype new_value) {
     attribute = new_value;
   }
}

Now say we have some code that uses 'foo', like this:

do_something (foo x)
   some_type value;
   // Some complicated computation that fills some_type
   foo.set_attribute (x);

then this is OK if do_something is passed in a parameter of type foo;
but if it gets an object of type foo2, that object wants to be set with
a value of type some_subtype, and do_something will most likely
miserably crash. (Or throw an exception. In neither case we have a
static type system.)

The gist of this all is that you effectively can't have a subtype with a
different mutable field. Which kills about 90% of all usable subtype
designs in my experience...

2) Parametricity
That's a very, very common type system design mistake. If type A is a
subtype of type B, i.e. A <: B, language designers seem to assume that
this implies array[A] <: array[B]. Again, this holds only if at least
one of array[] or A/B are immutable; if both are mutable, we get into
the same kind of trouble as in case 1. (It may even be that there are
cases where having one of array[] A/B mutable is enough to break type
safety. I haven't gone through the trouble of checking all cases here.)

>>> Type-parametric code in Haskell or ML can be type-checked in 
>>> isolation.
> that is indeed surprising for me. How can you typecheck on a 
> parametric type without knowing the type with which it would be 
> instantiated with? Thats the reason why C++ postpones the check for 
> operations on "dependent" names.

It's done :-))

I think it's mostly because FPLs tend to have far more uniform and
simple type systems. In particular, they support a very simple notion of
subtype if they have subtypes at all, and that makes things considerably
easier. (Most of what OO-style subtyping and dynamic binding does can be
done easily with higher-order functions, i.e. functions that can take
other functions as arguments, and that may return functions. And what
can't be done easily that way usually isn't really worth doing. That
said, I do miss some of the things that can be done in the OO way, but
it's not a serious loss - and definitely worth losing lots of typical OO
design problems.)

>>> I think there's a maximum instantiation depth of about 16.
> 
> C++ standard requires a mininum of 256 instantiation depth (which is 
> quite enough for safe practical use).

Ah, I wasn't sure about that.

Sure, it's enough for most practical uses. It's also enough to prevent
the C++ template system from being Turing-complete though.

E.g. without that restriction, it would have been possible to write
templates for vector spaces, and making sure that different numbers of
dimensions cause a compile-time error. Now we're effectively limited to
vector spaces with at most 256 dimensions (give or take a few depending
on exact circumstances).

>>> (Main reason probably being that this would require 
>>> differentiation between compile-time and run-time evaluation.
>>> Today's FPLs typically don't differentiate, leaving it to the
>>> compiler to decide what can be precompiled and what can't -
>>> nailing down in a language spec which expressions are guaranteed
>>> to evaluate at compile time and hence are suitable as type
>>> parameters creates language design and compiler implementation
>>> constraints that are difficult to change afterwards.)
> 
> Why do you consider that they non-type arguments need to be a
> constant expression?

Because the result of an instantiation can still be a type, which must
be statically checkable.

If I allow writing types that are evaluable only at run-time, the
compiler obviously can't statically check types.

For example, if I have

   a: array<<5, real>>
   b: array<<dims, real>>

where 'dims' is a variable that's filled from user input, the compiler
can't check whether a and b have the same type or not.

> It is true in case of C++, because, the template instantiation is a 
> compile-time mechanism. In Ada generics, non-type arguments can
> indeed be variables. I don't see why you can't do the same in a
> functional lang. (but I don't know much about FP, so I can't be
> sure).

It's a question of policy.

Actually I'm pretty sure that the expressions allowed in Ada generics
are limited to being compile-time evaluable. With some quite rigid
(conservative) restrictions of what can go into them. I'm not sure about
today's variant of Ada, but the '92 version was very, very limited here
- IIRC it was just arithmetic operators and a small set of functions
from the standard library (such as abs and sign). Most definitely no
user-written functions allowed there. (That would require the compiler 
to execute the user-written function to determine the value that would 
go into the function. In other words, the compiler would have to provide 
a complete execution environment as well, and if it's an imperative 
language, this would mean that the compiler would have to run in the 
same environment as the one it's compiling for... and *that* would mean 
that the Ada compiler would have to go into the embedded 
microcontrollers for which is was compiling - certainly not a realistic 
option. Things are easier for languages that don't have or strictly 
control side effects, because then the compiler can check that the 
user-defined function doesn't rely on external influences and run the 
thing in a sandbox; the worst that can happen is that the user function 
doesn't terminate, in which case the compiler can simply declare that 
the user function is in error. Simply aborting after a full CPU second 
would probably be good enough *gg*)

Regards,
Jo
0
jo427 (1164)
4/14/2005 2:16:46 PM
sgganesh@gmail.com wrote:
> 
> But I am not convinced that OO languages are really "bad" enough that
> their type systems are broken.

Unfortunately, there is no such thing as a mildly broken type system - 
it is either sound or it isn't.

>>>Type-parametric code in Haskell or ML can be type-checked in isolation.
 >
> that is indeed surprising for me. How can you typecheck on a parametric
> type without knowing
> the type with which it would be instantiated with?

Because either type checking is fully independent of the concrete type, 
or a mechanism like the type class constraints in Haskell provides all 
necessary information.

In C++, no type information is available at all about template 
parameters (they are fully abstract), still the body isn't independent 
from it (not even parsing!), so you loose. Note that generics in Java 
took a more reasonable approach here.

>>>I think there's a maximum instantiation depth of about 16.
> 
> C++ standard requires a mininum of 256 instantiation depth (which is
> quite enough for safe practical use).

The minimum requirement for recursive instantiation is 17 (see Annex B 
of the standard). And only recursion provides for actual computation.

> Why do you consider that they non-type arguments need to be a constant
> expression?
> It is true in case of C++, because, the template instantiation is a
> compile-time mechanism.

If type equivalence is dependent on these arguments, then they must be 
compile-time computable, otherwise the compiler wouldn't know what types 
are compatible. This is the case in C++.

Ada generics work more like (S)ML functors - you generate new instances 
from them *explicitly*, and all of them are considered different anyway. 
So the identity of types does not really depend on the concrete 
arguments (whether types or values).

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
4/14/2005 2:53:22 PM
torbenm@diku.dk (Torben �gidius Mogensen) writes:

>    Unlike C++, most functional languages prohibit polymrphic
>    recursion, so the number of instances is guaranteed to be finite
>    (though it can be very large).

It's the other way around. C++ doesn't allow polymorphic recursion and
its model of templates can't support this. Haskell allows it, as long
as the type is declared explicitly. OCaml and SML don't allow it but
they could be extended to allow it.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
4/14/2005 5:05:11 PM
Joachim Durchholz <jo@durchholz.org> writes:

> sgganesh@gmail.com wrote:
> > It is true in case of C++, because, the template instantiation is a
> > compile-time mechanism. In Ada generics, non-type arguments can
> > indeed be variables. I don't see why you can't do the same in a
> > functional lang. (but I don't know much about FP, so I can't be
> > sure).
> 
> It's a question of policy.
> 
> Actually I'm pretty sure that the expressions allowed in Ada generics
> are limited to being compile-time evaluable.

No, that's not true.  In Ada, one can pass run-time values to a generic.
They are evaluated at, well, run time as you might guess.

>... With some quite rigid
> (conservative) restrictions of what can go into them. I'm not sure about
> today's variant of Ada, but the '92 version was very, very limited
>here

There is no '92 version of Ada.  The first version was Ada 83, the
current version is Ada 95, and Ada 2005 is coming along.  All these
versions of the Ada language allow to pass dynamic values to a generic
package.

> - IIRC it was just arithmetic operators and a small set of functions
> from the standard library (such as abs and sign). Most definitely no
> user-written functions allowed there. (That would require the compiler
> to execute the user-written function to determine the value that would
> go into the function. In other words, the compiler would have to provide
> a complete execution environment as well, and if it's an imperative
> language, this would mean that the compiler would have to run in the
> same environment as the one it's compiling for... and *that* would mean
> that the Ada compiler would have to go into the embedded
> microcontrollers for which is was compiling - certainly not a realistic
> option. Things are easier for languages that don't have or strictly
> control side effects, because then the compiler can check that the
> user-defined function doesn't rely on external influences and run the
> thing in a sandbox; the worst that can happen is that the user function
> doesn't terminate, in which case the compiler can simply declare that
> the user function is in error. Simply aborting after a full CPU second
> would probably be good enough *gg*)

Yes, I agree that "Things are easier for languages that don't
have... side effects".

- Bob
0
bobduff (1543)
4/14/2005 11:39:33 PM
>>>>>I think there's a maximum instantiation depth of about 16.

>>> C++ standard requires a mininum of 256 instantiation depth (which
is
>>> quite enough for safe practical use).

>>The minimum requirement for recursive instantiation is 17 (see Annex
B
>>of the standard). And only recursion provides for actual computation.


Oops! I was wrong.

>>Ada generics work more like (S)ML functors - you generate new
instances
>>from them *explicitly*, and all of them are considered different
anyway.

The types of two instances of a generic unit for a same type/value
instantiated at runtime are
different! Isn't that bad; for example, I can't even assign or compare
directly since they are
of different types. 

-Ganesh

0
sgganesh (28)
4/15/2005 5:48:33 AM
> But I am not convinced that OO languages are really "bad" enough that

>  their type systems are broken.

>>I have seen two cases here:

I agree with both of them that they are flaws in the type system.

I have a question releated to the second case you pointed out:
For arrays and subtypes, in Java, it leads to throwing an exception in
case where we attempt
to assign a object of derived type to a array of a super class (which
leads to throwing an exception).
Is this a case of flaw in type system of Java? 

-Ganesh

0
sgganesh (28)
4/15/2005 6:01:04 AM
>>C++ doesn't allow polymorphic recursion and
>>its model of templates can't support this.
I thought polymorphic recursion means recursive template instantiation.
Is it not; in
that case, what is polymorphic recursion (sorry I am not familiar with
FP terminology)? 

-Ganesh

0
sgganesh (28)
4/15/2005 6:05:18 AM
Ganesh,

> I have a question releated to the second case you pointed out:
> For arrays and subtypes, in Java, it leads to throwing an exception in
> case where we attempt
> to assign a object of derived type to a array of a super class (which
> leads to throwing an exception).
> Is this a case of flaw in type system of Java?

It sure is. The support for generics in the .NET world is slightly better,
for it allows to define whether type parameters are covariant,
contravariant, or invariant; furthermore, the usage of these parameters
is checked accordingly. (This is implemented in the so-called Common Type
System, but
unfortunately not exposed in surface languages as C# and VB.)

A very accessible explanation of the problems with Java generics is
provided by Angelika Langer [1].

HTH,

Stefan

[1]
http://www.langer.camelot.de/Articles/Papers/JavaGenerics/ArraysInJavaGenerics.htm

0
sholderm (22)
4/15/2005 6:58:50 AM
Ganesh,

On 14 Apr 2005 sgganesh@gmail.com wrote:

> I thought polymorphic recursion means recursive template instantiation.
> Is it not; in
> that case, what is polymorphic recursion (sorry I am not familiar with
> FP terminology)?

Polymorphic recursion occurs when a polymorphic function is used
polymorphically within its own definition. Haskell allows
polymorphic-recursive functions, but only if those are decorated with
explicit type signatures.

Consider, for instance, the following---contrived---example:

  f a = let x = f False
            y = f 0
        in  a

(This is really just a complex way to define the identity function. ;))

In its own definition, f is applied to both a value of type Bool and a
numeric value: so, f is used polymorphically within its own defintion.
Hence, f exploits polymorphic recursion.

On its own, f would be rejected by a Haskell type checker. However, if we
add an explicit signature

  f :: a -> a

the program passed type checking.

HTH,

Stefan

0
sholderm (22)
4/15/2005 7:14:18 AM
Ganesh,

> I'm yet to go through the links. Can you explain me what is structural
> polymorphism?

The main idea is that one can define generic functions by induction over
the
structure of types. (Whereas 'normal', non-generic functions are defined
by induction on the structure of type.)

As an example, parametricity [1] states that it is not possible to define
a parameterically polymorphic function

  eq :: a -> a -> Bool

that checks equality of values for each type; such a function then can
only be constant or diverging.

In Generic Haskell [2], for instance, data types can be treated as if they
were defined in terms of only three basic types:

  data Unit     = Unit
  data Sum a b  = Inl a | Inr b
  data Prod a b = Prod a b

Types are now viewed as sums of products.

For instance the type of parametric lists

  data List a = Nil | Cons a (List a)

is viewed as

  type List' a = Sum Unit (Prod a (List a))

Generic functions are no defined by giving cases for only the three
special types:

  eq {| a :: * |}                             ::
    (eq {| a |}) => a -> a ->
Bool
  eq {| Unit |} Unit Unit                     =  True
  eq {| Sum a b |} (Inl a1) (Inl a2)          =  eq {| a |} a1 a2
  eq {| Sum a b |} (Inl a1) (Inr b2)          =  False
  eq {| Sum a b |} (Inr b1) (Inl a2)          =  False
  eq {| Sum a b |} (Inr b1) (Inr b2)          =  eq {| b |} b1 b2
  eq {| Prod a b |} (Prod a1 b1) (Prod a2 b2) =
    eq {| a |} a1 a2 && eq {| b |} b1 b2

Now we have a equality function that does work for (almost) all types.

Well, this really is a very short introduction to the subject, but I hope
you got the idea.

HTH,

Stefan

[1] http://homepages.inf.ed.ac.uk/wadler/topics/parametricity.html
[2] http://www.generic-haskell.org

0
sholderm (22)
4/15/2005 7:28:26 AM
sgganesh@gmail.com wrote:
> 
>>>Ada generics work more like (S)ML functors - you generate new instances
>>>from them *explicitly*, and all of them are considered different anyway.
> 
> The types of two instances of a generic unit for a same type/value
> instantiated at runtime are
> different! Isn't that bad; for example, I can't even assign or compare
> directly since they are of different types. 

In practice, it's not too much of a problem. You just have to share the 
instantiation between all clients that use it. In ML, the module system 
even provides sophisticated means to express this sharing across 
abstraction boundaries (but ML also has plain polymorphism, where you 
don't need explicit instantiation).

The C++ model certainly is somewhat more flexible, but you pay with a 
number of restrictions (like compile-time arguments only). Worse, in the 
face of separate compilation it leads to nasty problems with coherence 
(enforcement of the "one definition rule" in C++ speak). That lead to 
the addition of ad-hoc mechanisms for template "export" and explicit 
instantiation (effectively moving it towards the other model), but as of 
today, they still not solve these problems satisfactory, as far as I am 
aware of it.

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
4/15/2005 8:55:39 AM
sgganesh@gmail.com wrote:
> >>C++ doesn't allow polymorphic recursion and
> >>its model of templates can't support this.
> I thought polymorphic recursion means recursive template
instantiation.
> Is it not; in
> that case, what is polymorphic recursion (sorry I am not familiar
with
> FP terminology)?


In general there seems to be some terminological confusion.

As others have said:
"generics" as it is used in most OO situations usually refers to
parametric polymorphism
What OO people usually refer to as "polymorphism" is usually more
specifically refered to as subtype polymorphism or inclusion
polymorphism (of course, as others have mentioned, usually a "subclass"
relationship is used rather than subtype which causes issues)
"generics" as used in FP usually refers to things like polytypic
programming (as others have mentioned, see e.g. Generic Haskell)

Something no one seems to have explicitly mentioned:
What C++ templates provide is not parametric polymorphism; at best it
could be said to include parametric polymorphism as a subcase.  For
example, the template function
template <typename A> A min(A x,A y){ return x < y ? x : y; }
has (obviously) the (C++) type, template <typename A> A min(A,A); which
looks like min :: forall a.(a,a) -> a, which is definitely not the
case, the type is more like Haskell's min :: Ord a =>(a,a) -> a.
Essentially, min is not parametric in A (i.e. it lacks the
parametricity property), min will not work for any type but only those
that define operator< and even then the behavior will vary with the
definition of operator<.

Polymorphic recursion refers to calling a polymorphic function
recursively at a different type.  This can't be implemented as template
instantiation as it would correspond to an infinitely deep recursion.

0
ddarius (161)
4/15/2005 8:05:54 PM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> wrote:
>>>> C++ doesn't allow polymorphic recursion and its model of
>>>> templates can't support this.

and Darius wrote:
> Polymorphic recursion refers to calling a polymorphic function
> recursively at a different type.  This can't be implemented as template
> instantiation as it would correspond to an infinitely deep recursion.

I think the statement is too strong.  C++ doesn't support polymorphic
recursion for infinite type sequences.  However, there are some valid
programs that contain polymorphic recursion.  For example,

   template <typename T>
   void polymorphic(T x, T y) {
     if (x == y) {
       polymorphic("grumble", "mumble");
     }
   }
   
Ok, that's a bit contrived.  Here's a more likely (and more useful)
example:

   template <typename T>
   ostream& operator<<(ostream& out, const list<T>& list)
   {
      typename list<T>::const_iterator it(list.begin()), end(list.end());
      for (; it != end; it++)
          out << *it << ' ';
      return out;
   }

   list<list<int> > l;
   ...
   cout << l;

Here's an example that's actually invalid:

   template <typename T>
   int poly(T x) {
     if (false) {
        poly(list<T>());
     }
     return 0;
   }

Compare the similar(ly useless) Haskell function

  poly :: a -> Int
  poly x = let _ = poly [x] in 0 

which is allowed.

Jeremy.

0
jeremy63 (294)
4/15/2005 10:10:11 PM
Robert A Duff wrote:
> Joachim Durchholz <jo@durchholz.org> writes:
> 
>>sgganesh@gmail.com wrote:
>>
>>> It is true in case of C++, because, the template instantiation is
>>> a compile-time mechanism. In Ada generics, non-type arguments can
>>> indeed be variables. I don't see why you can't do the same in a 
>>> functional lang. (but I don't know much about FP, so I can't be 
>>> sure).
>> 
>> It's a question of policy.
>>
>> Actually I'm pretty sure that the expressions allowed in Ada
>> generics are limited to being compile-time evaluable.
> 
> No, that's not true.  In Ada, one can pass run-time values to a generic.
> They are evaluated at, well, run time as you might guess.

Non-type parameters if sgganesh is right.

(I overlooked that myself. My statements on restrictions over generic 
types were meant for type-relevant parameters, such as array index 
ranges, bounds for range types, or precisions for numeric non-integral 
types. Sorry for not making this clear from the outset.)

>>... With some quite rigid
>>(conservative) restrictions of what can go into them. I'm not sure about
>>today's variant of Ada, but the '92 version was very, very limited
>>here
> 
> There is no '92 version of Ada.  The first version was Ada 83, the
> current version is Ada 95, and Ada 2005 is coming along. 

Oh, right. I meant the '83 version.

Regards,
Jo
0
jo427 (1164)
4/16/2005 9:44:57 AM
sgganesh@gmail.com wrote:

>> But I am not convinced that OO languages are really "bad" enough
>> that their type systems are broken.
> 
>>>I have seen two cases here:
> 
> I agree with both of them that they are flaws in the type system.
> 
> I have a question releated to the second case you pointed out:
> For arrays and subtypes, in Java, it leads to throwing an exception in
> case where we attempt
> to assign a object of derived type to a array of a super class (which
> leads to throwing an exception).
> Is this a case of flaw in type system of Java? 

I haven't checked it myself, but I have heard reports that Java doesn't 
always throw exceptions when it should. If that's true, I consider that 
a flaw in Java's type system.

Throwing exceptions in itself is not a type system flaw, but it makes 
the type system less static. I think Java is more dynamic than it should be.

The typical OO type system flaws are a result of OO language designer 
having to pick one of three evils:
1) accepting an unsound (flawed) type system,
2) excluding the majority of subtyping opportunities,
3) or using a rather weak type system that relies on run-time checking 
and exceptions.
Most aim for (3), still get a certain amount of (2), and while trying to 
reconcile these two they also get a certain amount of (1). (The only OO 
language where I never heard about typing issues was Smalltalk. It 
immediately opted for (3) and whole-heartedly embraced it.)

I see a fourth solution: avoid mutable data. Point (2) almost vanishes, 
(1) can be fully done, and (3) can be reduced by at lest one order of 
magnitude, and all without straining the ingenuity of the language 
designer. Functional languages have shown what can be done with 
immutable data, with loss in efficiency only in borderline cases (and 
even these are being tackled right now).

(This all sounds as if OO could get away by simply adopting immutable 
data. The trouble is that it turns out that the core OO mechanism, 
dynamic binding, becomes far less valuable under an immutable regime. 
But that's something that the OO language community will find out on 
itself *evil grin*.)

Regards,
Jo
0
jo427 (1164)
4/16/2005 9:57:08 AM
Stefan Holdermans wrote:

> Consider, for instance, the following---contrived---example:
>
>   f a = let x = f False
>             y = f 0
>         in  a
>
> (This is really just a complex way to define the identity function.
;))
Isn't this a bad example a recursive polymorphism? None of the
variables in the let statement are used in the in statement so why
should the compiler even bother with the let statement?

0
4/16/2005 7:32:51 PM
Stefan Holdermans wrote:
>   f a = let x = f False
>             y = f 0
>         in  a
> 
> In its own definition, f is applied to both a value of type Bool and a
> numeric value: so, f is used polymorphically within its own defintion.
> Hence, f exploits polymorphic recursion.

The interesting thing about polymorphic recursion, though, is that a single 
function can be used at unboundedly many different types at run time. For 
example:

     -- I'm sure Chris Okasaki has a cleverer name for this datatype
     data ExpList a = ExpCons a (ExpList (a,a))

     -- example: ExpCons 1 (ExpCons (17,23) (ExpCons ((0,1),(42,666)) ...))
     --             :: ExpList Int

     indexExpList :: ExpList a -> Int -> a
     indexExpList (ExpCons x xs) n
       | n == 0  = x
       | odd n   = fst (indexExpList xs ((n-1) `div` 2))
       | even n  = snd (indexExpList xs ((n-2) `div` 2))

If you explicitly call indexExpList with type
(ExpList Char -> Int -> Char), it may, depending on the runtime value of the 
Int argument, call itself at (ExpList (Char,Char) -> Int -> (Char,Char)), 
(ExpList ((Char,Char),(Char,Char)) -> Int -> ((Char,Char),(Char,Char))), and 
so on indefinitely. This is impossible with C++'s template mechanism: the 
compiler would have to generate infinitely many versions of indexExpList.

-- Ben
0
4/20/2005 10:31:10 PM
Joachim Durchholz <jo@durchholz.org> writes:

> Robert A Duff wrote:
> > Joachim Durchholz <jo@durchholz.org> writes:
> >
> >>sgganesh@gmail.com wrote:
> >>
> >>> It is true in case of C++, because, the template instantiation is
> >>> a compile-time mechanism. In Ada generics, non-type arguments can
> >>> indeed be variables. I don't see why you can't do the same in a
> >>> functional lang. (but I don't know much about FP, so I can't be
> >>> sure).
> >> It's a question of policy.
> >>
> >> Actually I'm pretty sure that the expressions allowed in Ada
> >> generics are limited to being compile-time evaluable.
> > No, that's not true.  In Ada, one can pass run-time values to a
> > generic.
> > They are evaluated at, well, run time as you might guess.
> 
> Non-type parameters if sgganesh is right.
> 
> (I overlooked that myself. My statements on restrictions over generic
> types were meant for type-relevant parameters, such as array index
> ranges, bounds for range types, or precisions for numeric non-integral
> types. Sorry for not making this clear from the outset.)

I'm not sure exactly what you mean.  In Ada, bounds of arrays and
subranges of integer, enumeration, floating and fixed-point types can be
dynamic.  And you can pass this dynamic information to a generic unit.

Precisions of floating and fixed-point types are static.
(As in "type T is digits 6;" or "type T is delta 0.01;".)

> >>... With some quite rigid
> >>(conservative) restrictions of what can go into them. I'm not sure about
> >>today's variant of Ada, but the '92 version was very, very limited
> >>here
> > There is no '92 version of Ada.  The first version was Ada 83, the
> > current version is Ada 95, and Ada 2005 is coming along.
> 
> Oh, right. I meant the '83 version.

What I said above is true of that version, and still true in later
versions.

By the way, the next version is supposed to be finished this year, as
far as producing a new Reference Manual.  However, it's not clear
whether it will be Ada 2005 or 2006.  ISO take months to go from a
final version to an officially approved standard.  This process involvs
voting at several  levels of beurocracy.

- Bob

P.S. Sorry for chatting about Ada in a functional newsgroup.  ;-)
Just to say something relevant: I agree with sgganesh that
you could do similar things in a functional language.
0
bobduff (1543)
4/21/2005 4:04:35 PM
Joachim Durchholz <jo@durchholz.org> writes:

> sgganesh@gmail.com wrote:
> 
> >> But I am not convinced that OO languages are really "bad" enough
> >> that their type systems are broken.
> >
> >>>I have seen two cases here:
> > I agree with both of them that they are flaws in the type system.
> > I have a question releated to the second case you pointed out:
> > For arrays and subtypes, in Java, it leads to throwing an exception in
> > case where we attempt
> > to assign a object of derived type to a array of a super class (which
> > leads to throwing an exception).
> > Is this a case of flaw in type system of Java?
> 
> I haven't checked it myself, but I have heard reports that Java doesn't
> always throw exceptions when it should. If that's true, I consider that
> a flaw in Java's type system.

Not sure what you mean by "when it should".  One could argue that if
integer arithmetic overflows, it should throw an exception.  Java wraps
around instead.  If you're counting the number of widgets, wrap-around
arithmetic gives wrong answers.  Is that an example?

(Of course, one could also argue that arithmetic should be arbitrary
range.)

I believe the array case mentioned by sgganesh is caused by Java's lack
of generics (in the original version of Java, anyway).

> Throwing exceptions in itself is not a type system flaw, but it makes
> the type system less static. I think Java is more dynamic than it should
> be.

I agree.  But there will always be some "error" situations that can only
be detected dynamically, and the language has to do *something*: throw
an exception, return "bottom", return an arbitrary wrong answer...

> The typical OO type system flaws are a result of OO language designer
> having to pick one of three evils:
> 1) accepting an unsound (flawed) type system,
> 2) excluding the majority of subtyping opportunities,
> 3) or using a rather weak type system that relies on run-time checking
> and exceptions.
> Most aim for (3), still get a certain amount of (2), and while trying to
> reconcile these two they also get a certain amount of (1). (The only OO
> language where I never heard about typing issues was Smalltalk. It
> immediately opted for (3) and whole-heartedly embraced it.)

I think Java's type system is just as sound as Smalltalk's.
But then there are things that you can't do in the language.
(You can't very well write the garbage collector in the language
itself, if the language requires all arrays to be allocated
in a garbage-collected heap.)

> I see a fourth solution: avoid mutable data. Point (2) almost vanishes,
> (1) can be fully done, and (3) can be reduced by at lest one order of
> magnitude, and all without straining the ingenuity of the language
> designer. Functional languages have shown what can be done with
> immutable data, with loss in efficiency only in borderline cases (and
> even these are being tackled right now).
> 
> (This all sounds as if OO could get away by simply adopting immutable
> data. The trouble is that it turns out that the core OO mechanism,
> dynamic binding, becomes far less valuable under an immutable
> regime. But that's something that the OO language community will find
> out on itself *evil grin*.)

;-)

- Bob
0
bobduff (1543)
4/21/2005 4:14:48 PM
Robert A Duff wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
>>sgganesh@gmail.com wrote:
>>
>>
>>>>But I am not convinced that OO languages are really "bad" enough
>>>>that their type systems are broken.
>>>>>I have seen two cases here:
>>>
>>>I agree with both of them that they are flaws in the type system.
>>>I have a question releated to the second case you pointed out:
>>>For arrays and subtypes, in Java, it leads to throwing an exception in
>>>case where we attempt
>>>to assign a object of derived type to a array of a super class (which
>>>leads to throwing an exception).
>>>Is this a case of flaw in type system of Java?
>>
>>I haven't checked it myself, but I have heard reports that Java doesn't
>>always throw exceptions when it should. If that's true, I consider that
>>a flaw in Java's type system.
> 
> Not sure what you mean by "when it should".  One could argue that if
> integer arithmetic overflows, it should throw an exception.  Java wraps
> around instead.  If you're counting the number of widgets, wrap-around
> arithmetic gives wrong answers.  Is that an example?

No, not at all. This subthread is about type errors, i.e. values 
assigned to names that don't belong to the declared type of the name.

Whether integer arithmetic is wrap-around or not is just a question of 
what axioms are in use. Neither wrap-around nor exceptions are even near 
to the Real Thing (nor is unlimited-size arithmetic, in case anyone 
asks) - all fail to do proper integer arithmetic, though some will fail 
sooner or later.

> (Of course, one could also argue that arithmetic should be arbitrary
> range.)
> 
> I believe the array case mentioned by sgganesh is caused by Java's lack
> of generics (in the original version of Java, anyway).

Yes, but arrays are built-in generics, and their semantics is (AFAIK) 
unchanged. What I heard (really not more than a rumor, though it sounded 
quite convincing at that time) was that there was some type hole 
associated with arrays, and that rumor predates Generic Java by more 
than a year IIRC.

Again, I don't know any details, and forgot what keywords to feed to 
Google to find anything substantial. It's a rumor, and unfounded right 
now. I'd love to see somebody find evidence that supports or contradicts it.

>>Throwing exceptions in itself is not a type system flaw, but it makes
>>the type system less static. I think Java is more dynamic than it should
>>be.
> 
> I agree.  But there will always be some "error" situations that can only
> be detected dynamically, and the language has to do *something*: throw
> an exception, return "bottom", return an arbitrary wrong answer...

Well, arbitrary wrong answer is the worst of all alternatives.

Note that a Haskell function will never "return bottom". It's a 
theoretical construct, nothing that a Haskell program will ever return. 
If a value of bottom is ever constructed, the Haskell program will abort 
with an error (or throw an exception, which is a way of not returning a 
result - no, exceptions aren't considered a "result" in any meaningful 
sense in Haskell).

>>The typical OO type system flaws are a result of OO language designer
>>having to pick one of three evils:
>>1) accepting an unsound (flawed) type system,
>>2) excluding the majority of subtyping opportunities,
>>3) or using a rather weak type system that relies on run-time checking
>>and exceptions.
>>Most aim for (3), still get a certain amount of (2), and while trying to
>>reconcile these two they also get a certain amount of (1). (The only OO
>>language where I never heard about typing issues was Smalltalk. It
>>immediately opted for (3) and whole-heartedly embraced it.)
> 
> I think Java's type system is just as sound as Smalltalk's.

Given that Java's type system is 100% sound by virtue of its triviality, 
I'd be *very* surprised if that held. (Even dynamic types in Smalltalk 
aren't what most people think. The only useful way to define the type of 
a Smalltalk objects seems to be "the set of messages that it doesn't 
respond to with a #DoesNotUnderstand reply", and that's utterly 
unrelated to classes, though - of course - classes still create related 
types.)

> But then there are things that you can't do in the language.
> (You can't very well write the garbage collector in the language
> itself, if the language requires all arrays to be allocated
> in a garbage-collected heap.)

Not sure how that relates to typing.

Regards,
Jo
0
jo427 (1164)
4/21/2005 5:29:52 PM
Joachim Durchholz wrote:
> Whether integer arithmetic is wrap-around or not is just a question of 
> what axioms are in use. Neither wrap-around nor exceptions are even near 
> to the Real Thing (nor is unlimited-size arithmetic, in case anyone 
> asks) - all fail to do proper integer arithmetic, though some will fail 
> sooner or later.

Hmm, why does unlimited size arithmetic fail?  Because of the
limitations of computer memory?  Or something more insidious?


Matt
0
angagon (2)
4/21/2005 7:10:29 PM
Joachim Durchholz <jo@durchholz.org> writes:

> Robert A Duff wrote:
> 
> > Joachim Durchholz <jo@durchholz.org> writes:
> >
> >>sgganesh@gmail.com wrote:
> >>
> >>
> >>>>But I am not convinced that OO languages are really "bad" enough
> >>>>that their type systems are broken.
> >>>>>I have seen two cases here:
> >>>
> >>>I agree with both of them that they are flaws in the type system.
> >>>I have a question releated to the second case you pointed out:
> >>>For arrays and subtypes, in Java, it leads to throwing an exception in
> >>>case where we attempt
> >>>to assign a object of derived type to a array of a super class (which
> >>>leads to throwing an exception).
> >>>Is this a case of flaw in type system of Java?
> >>
> >>I haven't checked it myself, but I have heard reports that Java doesn't
> >>always throw exceptions when it should. If that's true, I consider that
> >>a flaw in Java's type system.
> > Not sure what you mean by "when it should".  One could argue that if
> > integer arithmetic overflows, it should throw an exception.  Java wraps
> > around instead.  If you're counting the number of widgets, wrap-around
> > arithmetic gives wrong answers.  Is that an example?
> 
> No, not at all. This subthread is about type errors, i.e. values
> assigned to names that don't belong to the declared type of the name.

It's very difficult to talk about these things, because there's no
standard terminology.  Every language has its own notion of "type".

Is divide-by-zero a "type error"?  Depends on which language we're
talking about.  But we're trying to talk about languages in general, and
there's no commonly agreed-upon (language independent) notion of "type".

It's easy to create a sound type system, if we have just one type.
The 'sh' language (I mean, Bourne shell in Unix) does that.
But it's not very useful, as a type system.

Sigh.

> Whether integer arithmetic is wrap-around or not is just a question of
> what axioms are in use.

OK, but it illustrates the fact that some type systems are more useful
than others.  We could define zero-divided-by-zero to always return 17.
It's well defined, but in practise, it hides bugs, by giving wrong
answers.  Better to raise an exception.

>... Neither wrap-around nor exceptions are even near
> to the Real Thing (nor is unlimited-size arithmetic, in case anyone
> asks) - all fail to do proper integer arithmetic, though some will fail
> sooner or later.

Indeed, but failing on numbers above 2**31-1 is very different from
failing on 2**(2**31), in practise.  That is, "out of memory" is very
different from an arbitrary hardware-oriented restriction.

> > (Of course, one could also argue that arithmetic should be arbitrary
> > range.)
> > I believe the array case mentioned by sgganesh is caused by Java's lack
> > of generics (in the original version of Java, anyway).
> 
> Yes, but arrays are built-in generics, and their semantics is (AFAIK)
> unchanged. What I heard (really not more than a rumor, though it sounded
> quite convincing at that time) was that there was some type hole
> associated with arrays, and that rumor predates Generic Java by more
> than a year IIRC.
> 
> Again, I don't know any details, and forgot what keywords to feed to
> Google to find anything substantial. It's a rumor, and unfounded right
> now. I'd love to see somebody find evidence that supports or contradicts
> it.

I'd like to know precisely what that unfounded rumor *is*.  Then some
Java expert could confirm or deny.  (Not me -- I'm not a Java expert, at
least not on the latest version of the language.)

> >>Throwing exceptions in itself is not a type system flaw, but it makes
> >>the type system less static. I think Java is more dynamic than it should
> >>be.
> > I agree.  But there will always be some "error" situations that can
> > only
> > be detected dynamically, and the language has to do *something*: throw
> > an exception, return "bottom", return an arbitrary wrong answer...
> 
> Well, arbitrary wrong answer is the worst of all alternatives.

Indeed.

> Note that a Haskell function will never "return bottom". It's a
> theoretical construct, nothing that a Haskell program will ever
> return. If a value of bottom is ever constructed, the Haskell program
> will abort with an error (or throw an exception, which is a way of not
> returning a result - no, exceptions aren't considered a "result" in any
> meaningful sense in Haskell).
> 
> >>The typical OO type system flaws are a result of OO language designer
> >>having to pick one of three evils:
> >>1) accepting an unsound (flawed) type system,
> >>2) excluding the majority of subtyping opportunities,
> >>3) or using a rather weak type system that relies on run-time checking
> >>and exceptions.
> >>Most aim for (3), still get a certain amount of (2), and while trying to
> >>reconcile these two they also get a certain amount of (1). (The only OO
> >>language where I never heard about typing issues was Smalltalk. It
> >>immediately opted for (3) and whole-heartedly embraced it.)
> > I think Java's type system is just as sound as Smalltalk's.
> 
> Given that Java's type system is 100% sound by virtue of its triviality,
> I'd be *very* surprised if that held. (Even dynamic types in Smalltalk
> aren't what most people think. The only useful way to define the type of
> a Smalltalk objects seems to be "the set of messages that it doesn't
> respond to with a #DoesNotUnderstand reply", and that's utterly
> unrelated to classes, though - of course - classes still create related
> types.)

Again, one way to understand Smalltalk's type system is that there's one
type (object), and the type system is sound in that respect (you can't
create pointers to junk bits, as you can in C).

> > But then there are things that you can't do in the language.
> > (You can't very well write the garbage collector in the language
> > itself, if the language requires all arrays to be allocated
> > in a garbage-collected heap.)
> 
> Not sure how that relates to typing.

You mentioned above, "1) accepting an unsound (flawed) type system".
Seems bad.  But I just meant to say that if you want to write a GC,
you pretty-much have to accept that.  I'm all for type checking, but I
don't know how to write a GC in a type-safe way (neither static nor
dynamic typing).

- Bob
0
bobduff (1543)
4/21/2005 8:23:10 PM
> 
> Yes, but arrays are built-in generics, and their semantics is (AFAIK) 
> unchanged. What I heard (really not more than a rumor, though it sounded 
> quite convincing at that time) was that there was some type hole 
> associated with arrays, and that rumor predates Generic Java by more 
> than a year IIRC.

A "type hole" associated with arrays : no contravariance ?
0
4/21/2005 10:37:50 PM
>>I believe the array case mentioned by sgganesh is caused by Java's
lack
>>of generics (in the original version of Java, anyway).

Might be I have to be specific about what I meant:

$ cat typedefect1.java

class A {}
class B extends A {}

class typedefect1 {
    public static void main(String [] s) {
        A arr[] = new B[10];
        arr[1] = new A();
   }
}

$ javac typedefect1.java
$ java typedefect1
Exception in thread "main" java.lang.ArrayStoreException
        at typedefect1.main(typedefect1.java:8)

$ cat typedefect2.java

interface CommonI {}

class X implements CommonI {}
class Y implements CommonI {}

class typedefect2 {
    public static void main(String [] s) {
        X x = new X();
        Y y = new Y();
        CommonI  ci = true ? x : y;
   }
}

$ javac typedefect2.java
typedefect2.java:11: incompatible types
found   : Y
required: X
        CommonI  ci = true ? x : y;
                           ^
1 error

There are many Gurus here, who understand type systems well,
can you confirm if these are typedefects in Java? For me, both appear
to be defects in type system of Java. 

-Ganesh

0
sgganesh (28)
4/22/2005 8:22:13 AM
Robert,

> I'd like to know precisely what that unfounded rumor *is*.  Then some
> Java expert could confirm or deny.  (Not me -- I'm not a Java expert, at
> least not on the latest version of the language.)

I think the previous poster was referring to Java arrays being covariant
instead of contravariant.

Arrays being covariant means that when T1 is a subtype of T2,

  T1 <: T2,

then T1[] is a subtype of T2,

  T1[] <: T2[].

For instance, because

  String <: Object,

we have

  String[] <: Object[].

This means that we can declare and initialize

  Object[] objs = new String[2];

and then, at compile time, it's perfectly legal to have

  objs[0] = new Object(); // run-time error

You can see why covariance is an undesirable property for the array type
constructor.

If arrays would behave contravariantly, there would be no problem. So

  T1 <: T2

would imply

  T2[] <: T1[]

and

  Object[] objs = new String[2]; // compile-time error

would not even be possible.

Furthermore, the we could have

  String[] strs = new Object[2];

which is perfectly safe but not possible now.

So, I don't think it's a "rumour", and I certainly don't think it's
"unfounded". But perhaps this was not the issue that the previous poster
was referring to.

HTH,

Stefan

0
sholderm (22)
4/22/2005 8:36:05 AM
Stefan Holdermans <sholderm@students.cs.uu.nl> writes:

> If arrays would behave contravariantly, there would be no problem.
[...]
> Furthermore, the we could have
>
>   String[] strs = new Object[2];
>
> which is perfectly safe but not possible now.

It's not safe. strs[0] would not be guaranteed to be a string if you
filled the array while it was seen as an object array.

Mutable arrays are by their nature invariant. But this choice for Java
would make impossible to write code which works for any array whose
element type is a subtype of T. By moving some checks to run time it
gains expressiveness: its type system is too weak to express this kind
of polymorphism, so it prefers to distinguish correct from incorrect
at run time than to disallow both.

Probably a better solution would be to support quantifiers over type
variables. This would complicate the type system and it would still be
sometimes too weak, but it would allow to express a large enough class
of programs that the "hole" could be removed. Perhaps generics now
allow this, I'm not familiar enough with their details.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
4/22/2005 9:46:07 AM
Marcin,

> Probably a better solution would be to support quantifiers over type
> variables. This would complicate the type system and it would still be
> sometimes too weak, but it would allow to express a large enough class
> of programs that the "hole" could be removed. Perhaps generics now
> allow this, I'm not familiar enough with their details.

I'm not sure how it's implemented in Java, but I do know that Microsoft's
CTS supports polarities for type variables; they are not available in
source languages like C# or VB.NET, though.

Regards,

Stefan


0
sholderm (22)
4/22/2005 11:33:58 AM
> Perhaps generics now allow this, I'm not familiar enough with their 
> details.

Yes, they do.

Covariance : ClassName<? extends BaseType>
Contravariance : ClassName<? super BaseType>

However, the type of built-in arrays is not updated in order to be 
comptible with the former version. 

-- 
Thierry.
0
4/22/2005 9:14:48 PM
Joachim Durchholz <jo@durchholz.org> writes:

[...]

| Note that there's a little white lie involved. C++ templates would be
| Turing-complete if it were not restricted - I think there's a maximum
| instantiation depth of about 16.

Some myths have long life.

-- Gaby
0
gdr (104)
5/26/2005 11:44:12 AM
sgganesh@gmail.com writes:

[...]

| >> I think there's a maximum instantiation depth of about 16.
| C++ standard requires a mininum of 256 instantiation depth (which is
| quite enough for safe practical use).

That is not true either.  See past extensive dicsussion in
comp.lang.scheme.  The C++ standard states only that there is an
implementation defined limit -- value of which is not stated, especially
it does not require the limit to be finite, even though practical
considerations will make it.

-- Gaby
0
gdr (104)
5/26/2005 11:50:04 AM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| The C++ model certainly is somewhat more flexible, but you pay with a
| number of restrictions (like compile-time arguments only). Worse, in
| the face of separate compilation it leads to nasty problems with
| coherence (enforcement of the "one definition rule" in C++
| speak). That lead to the addition of ad-hoc mechanisms for template
| "export" and explicit instantiation (effectively moving it towards the
| other model), but as of today, they still not solve these problems
| satisfactory, as far as I am aware of it.

Since day one of C++ template design, separate compilation of templates
has always been there.  During C++ standardization, a diversion appeared
where suddenly a number of implementers have decided to implement only
the semantics of "inclusion model" (possibly because of absence of
prior experience with that "new" form of compilation).  Then, there
was a "fight" to bring separate compilation back, as it was originally
part of the design. "export" was a compromise for that.
Explicit instantiation has always been part of the design and they are
not addition of ad-hoc mechanisms.  
Surely, C++ template implementations pose real challenges which are
far beyond simply filling structures with pointer to functions and
claiming "genericity".  Sadly, it looks like academic literature does
not offer better :-((

-- Gaby
0
gdr (104)
5/26/2005 12:03:17 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> sgganesh@gmail.com writes:
>
> [...]
>
> | >> I think there's a maximum instantiation depth of about 16.
> | C++ standard requires a mininum of 256 instantiation depth (which is
> | quite enough for safe practical use).
>
> That is not true either.  See past extensive dicsussion in
> comp.lang.scheme.  The C++ standard states only that there is an
> implementation defined limit -- value of which is not stated, especially
> it does not require the limit to be finite, even though practical
> considerations will make it.

I thought the standard gives a lower bound on that limit.  (Correct me
if I am wrong.)  
0
find19 (1244)
5/26/2005 12:16:00 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> | 
> | > sgganesh@gmail.com writes:
> | >
> | > [...]
> | >
> | > | >> I think there's a maximum instantiation depth of about 16.
> | > | C++ standard requires a mininum of 256 instantiation depth (which is
> | > | quite enough for safe practical use).
> | >
> | > That is not true either.  See past extensive dicsussion in
> | > comp.lang.scheme.  The C++ standard states only that there is an
> | > implementation defined limit -- value of which is not stated, especially
> | > it does not require the limit to be finite, even though practical
> | > considerations will make it.
> | 
> | I thought the standard gives a lower bound on that limit.  (Correct me
> | if I am wrong.)  
>
> It does not give a lower limit.  What happens is that in the
> *informative* annexe B, it says a lower bound of 17 -- but that does
> not have any normative effect.  To quote people  directly involved in
> this business "it was 'pulled out of a hat'", but it was made sure it
> wasn't a power of 2 -- so that people don't draw wrong conclusions
> about its relevance.  As I pointed out, 17 isn't that arbitrary, it
> has many mathematical properties :-) 
>
> Last time, someone raised (in the C++ committee) similar issue about
> that limit it was agreed that it should be either removed the number or
> increased to another arbitrary number.  Then someone pointed out the
> following facts (that was in 2003 and I haven't conducted a recent
> survey) about compilers in production use:
>
>      EDG eccp:    64
>      gcc 2.x:     17 (adjustible)
>      gcc 3.x:    500 (adjustible)
>      HP aCC:     255
>      MSVC 7:    1031
>      SunPro:     128
>
> -- Gaby

What does the standard say (in an "*informative* annexe" or wherever)
what the lower bound on the limit on recursion depth for function- and
method-calls is?  What about nesting depth of "{ }" blocks? After all,
in practice these are bounded, too.

If it doesn't say anything about those, why has template recursion
been treated differently?

By the way, if you say that it isn't "normative", does that mean that
a compiler that limits it to, say, 1, would be a conforming C++
compiler?  If not, why not?

0
find19 (1244)
5/26/2005 3:34:25 PM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > sgganesh@gmail.com writes:
| >
| > [...]
| >
| > | >> I think there's a maximum instantiation depth of about 16.
| > | C++ standard requires a mininum of 256 instantiation depth (which is
| > | quite enough for safe practical use).
| >
| > That is not true either.  See past extensive dicsussion in
| > comp.lang.scheme.  The C++ standard states only that there is an
| > implementation defined limit -- value of which is not stated, especially
| > it does not require the limit to be finite, even though practical
| > considerations will make it.
| 
| I thought the standard gives a lower bound on that limit.  (Correct me
| if I am wrong.)  

It does not give a lower limit.  What happens is that in the
*informative* annexe B, it says a lower bound of 17 -- but that does
not have any normative effect.  To quote people  directly involved in
this business "it was 'pulled out of a hat'", but it was made sure it
wasn't a power of 2 -- so that people don't draw wrong conclusions
about its relevance.  As I pointed out, 17 isn't that arbitrary, it
has many mathematical properties :-) 

Last time, someone raised (in the C++ committee) similar issue about
that limit it was agreed that it should be either removed the number or
increased to another arbitrary number.  Then someone pointed out the
following facts (that was in 2003 and I haven't conducted a recent
survey) about compilers in production use:

     EDG eccp:    64
     gcc 2.x:     17 (adjustible)
     gcc 3.x:    500 (adjustible)
     HP aCC:     255
     MSVC 7:    1031
     SunPro:     128

-- Gaby

0
gdr (104)
5/26/2005 4:24:51 PM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Matthias Blume <find@my.address.elsewhere> writes:
| >
| > | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| > | 
| > | > sgganesh@gmail.com writes:
| > | >
| > | > [...]
| > | >
| > | > | >> I think there's a maximum instantiation depth of about 16.
| > | > | C++ standard requires a mininum of 256 instantiation depth (which is
| > | > | quite enough for safe practical use).
| > | >
| > | > That is not true either.  See past extensive dicsussion in
| > | > comp.lang.scheme.  The C++ standard states only that there is an
| > | > implementation defined limit -- value of which is not stated, especially
| > | > it does not require the limit to be finite, even though practical
| > | > considerations will make it.
| > | 
| > | I thought the standard gives a lower bound on that limit.  (Correct me
| > | if I am wrong.)  
| >
| > It does not give a lower limit.  What happens is that in the
| > *informative* annexe B, it says a lower bound of 17 -- but that does
| > not have any normative effect.  To quote people  directly involved in
| > this business "it was 'pulled out of a hat'", but it was made sure it
| > wasn't a power of 2 -- so that people don't draw wrong conclusions
| > about its relevance.  As I pointed out, 17 isn't that arbitrary, it
| > has many mathematical properties :-) 
| >
| > Last time, someone raised (in the C++ committee) similar issue about
| > that limit it was agreed that it should be either removed the number or
| > increased to another arbitrary number.  Then someone pointed out the
| > following facts (that was in 2003 and I haven't conducted a recent
| > survey) about compilers in production use:
| >
| >      EDG eccp:    64
| >      gcc 2.x:     17 (adjustible)
| >      gcc 3.x:    500 (adjustible)
| >      HP aCC:     255
| >      MSVC 7:    1031
| >      SunPro:     128
| >
| > -- Gaby
| 
| What does the standard say (in an "*informative* annexe" or wherever)
| what the lower bound on the limit on recursion depth for function- and
| method-calls is?  What about nesting depth of "{ }" blocks? After all,
| in practice these are bounded, too.

                               Annex B
                            (informative)
                      Implementation quantities

  1  Because computers are finite, C++ implementations are inevitably
     limited in the size of the programs they can successfully
     process. Every implementation shall document those limitations
     where known. This documentation may cite fixed limits where they
     exist, say how to compute variable limits as a function of
     available resources, or say that fixed limits do not exist or are
     unknown.  

  2  The limits may constrain quantities that include those described
     below or others. The bracketed number following each quantity is
     recommended as the minimum for that quantity. However, these
     quantities are only guidelines and do not determine compliance.

     -- Nesting levels of compound statements, iteration control
        structures, and selection control structures [256].
    
     -- Nesting levels of conditional inclusion [256].
   
     -- Pointer, array, and function declarators (in any combination)
        modifying an arithmetic, structure, union, or incomplete type
        in a declaration [256].

     -- Nesting levels of parenthesized expressions within a full
        expression [256].

     -- Number of characters in an internal identifier or macro name
        [1 024]. 

     -- Number of characters in an external identifier [1 024].

     -- External identifiers in one translation unit [65 536].

     -- Identifiers with block scope declared in one block [1 024].

     -- Macro identifiers simultaneously defined in one translation
        unit [65 536].

     -- Parameters in one function definition [256].

     -- Arguments in one function call [256].

     -- Parameters in one macro definition [256].

     -- Arguments in one macro invocation [256].

     -- Characters in one logical source line [65 536].

     -- Characters in a character string literal or wide string
        literal (after concatenation) [65 536].

     -- Size of an object [262 144].

     -- Nesting levels for #include files [256].

     -- Case labels for a switch statement (excluding those for any
        nested switch statements) [16 384].

     -- Data members in a single class, structure, or union [16 384].
  
     -- Enumeration constants in a single enumeration [4 096].

     -- Levels of nested class, structure, or union definitions in a
        single struct-declaration-list [256].

     -- Functions registered by atexit()[32].

     -- Direct and indirect base classes [16 384].

     -- Direct base classes for a single class [1 024].

     -- Members declared in a single class [4 096].

     -- Final overriding virtual functions in a class, accessible or
        not [16 384].

     -- Direct and indirect virtual bases of a class [1 024].

     -- Static members of a class [1 024].

     -- Friend declarations in a class [4 096].

     -- Access control declarations in a class [4 096].

     -- Member initializers in a constructor definition [6 144].

     -- Scope qualifications of one identifier [256].

     -- Nested external specifications [1 024].

     -- Template arguments in a template declaration [1 024].

     -- Recursively nested template instantiations [17].

     -- Handlers per try block [256].

     -- Throw specifications on a single function declaration [256]. 
     
| If it doesn't say anything about those, why has template recursion
| been treated differently?
| 
| By the way, if you say that it isn't "normative", does that mean that
| a compiler that limits it to, say, 1, would be a conforming C++
| compiler?  If not, why not?

A compiler can set the limit to 1, it would be conformant in that
regard.  Whether it would be useful is a different question :-)

-- Gaby
0
gdr (104)
5/26/2005 9:54:42 PM
Gabriel Dos Reis wrote:
> 
> | The C++ model certainly is somewhat more flexible, but you pay with a
> | number of restrictions (like compile-time arguments only). Worse, in
> | the face of separate compilation it leads to nasty problems with
> | coherence (enforcement of the "one definition rule" in C++
> | speak). That lead to the addition of ad-hoc mechanisms for template
> | "export" and explicit instantiation (effectively moving it towards the
> | other model), but as of today, they still not solve these problems
> | satisfactory, as far as I am aware of it.
> 
> Since day one of C++ template design, separate compilation of templates
> has always been there.  During C++ standardization, a diversion appeared
> where suddenly a number of implementers have decided to implement only
> the semantics of "inclusion model" (possibly because of absence of
> prior experience with that "new" form of compilation).  Then, there
> was a "fight" to bring separate compilation back, as it was originally
> part of the design. "export" was a compromise for that.

Thanks for the clarification, although it doesn't quite contradict what 
I said in the quoted text. AFAICS, the coherence problem is still a 
fundamental one, and can only be addressed at link time.

Moreover, has anything changed about the fact that even a decade after 
its introduction at most one existing implementation seems to be dealing 
with "export" properly? I don't think it is unfair to say that true 
separate compilation mostly was (and unfortunately still is) wishful 
thinking more than reality.

> Explicit instantiation has always been part of the design and they are
> not addition of ad-hoc mechanisms.  

If I remember correctly from D&E (or ARM?), first versions of templates 
didn't have it, but I may be mistaken. In any case, I stand by my claim 
that it is an ad-hoc mechanism.

> Surely, C++ template implementations pose real challenges which are
> far beyond simply filling structures with pointer to functions and
> claiming "genericity".  Sadly, it looks like academic literature does
> not offer better :-((

I suppose that depends on your definition of "better". Of course, you 
won't find anything that subsumes all that templates do (not least 
because that may not exactly be deemed desirable). But you will 
definitely find "academic" languages that offer comparable mechanisms 
that are even more expressive along certain axes, while staying much 
more structured and principled. Type classes come to mind immediately, 
which - incidentally - /can/ be compiled into tuples of functions.

Note that the inability to do the latter for templates might rather be a 
consequence of their unstructured nature (plus the lack of closures and 
other issues of C++) rather than of their expressiveness.

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
5/30/2005 10:03:50 AM
Gabriel Dos Reis wrote:
>      
> | If it doesn't say anything about those, why has template recursion
> | been treated differently?
> | 
> | By the way, if you say that it isn't "normative", does that mean that
> | a compiler that limits it to, say, 1, would be a conforming C++
> | compiler?  If not, why not?
> 
> A compiler can set the limit to 1, it would be conformant in that
> regard.  Whether it would be useful is a different question :-)

Then the situation is, in fact, worse than I anticipated.

What's the value of a standard if it doesn't even guarantee that you can 
make practical use of some feature at all??

The usual quality-of-implementation argument is moot in that respect. By 
that argument, we wouldn't need a normative standard in the first place.

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
5/30/2005 10:06:52 AM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Gabriel Dos Reis wrote:
| >      | If it doesn't say anything about those, why has template
| > recursion
| > | been treated differently?
| > | | By the way, if you say that it isn't "normative", does that mean
| > that
| > | a compiler that limits it to, say, 1, would be a conforming C++
| > | compiler?  If not, why not?
| > A compiler can set the limit to 1, it would be conformant in that
| > regard.  Whether it would be useful is a different question :-)
| 
| Then the situation is, in fact, worse than I anticipated.

Quite possible.  As I have been trying to taint this whole discussion
with a little of reality, have you found any C++ compiler in
production use/existence that set that limit to 1?  Or is it just pure
speculation? 

| What's the value of a standard if it doesn't even guarantee that you
| can make practical use of some feature at all??

Oh, neither the C (nor the C++) standard guarantees that a C (or C++)
compiler will accept and run the following program 

   int main(void) { return 0; }

still the respective standards have value for interested parties.  It
might just be that there are people using them and people talking
about people using them.

-- Gaby
0
gdr (104)
5/30/2005 9:45:56 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

[...]

| > Surely, C++ template implementations pose real challenges which are
| > far beyond simply filling structures with pointer to functions and
| > claiming "genericity".  Sadly, it looks like academic literature does
| > not offer better :-((
| 
| I suppose that depends on your definition of "better". Of course, you
| won't find anything that subsumes all that templates do (not least
| because that may not exactly be deemed desirable). But you will
| definitely find "academic" languages that offer comparable mechanisms
| that are even more expressive along certain axes, while staying much
| more structured and principled. Type classes come to mind immediately,
| which - incidentally - /can/ be compiled into tuples of functions.

I think I specifically dismissed compilation into tuples of functions
on the ground that it does not match the expressive power offered by
templates.  There is a urban legend that C or C++ designers or
implementers obviously don't quite understand functional programming
languages and features and implementations.  That legend, for large
part, is unfounded.

| Note that the inability to do the latter for templates might rather be
| a consequence of their unstructured nature (plus the lack of closures
| and other issues of C++) rather than of their expressiveness.

As a well known Swiss Army instruction goes, when the terrain and the
map differ -- trust the terrain. No doubt some programming languages
are invented to prove a point, but I've come to realize that the C++
templates were designed to solve a problem.  I'm not claiming it is
perfect (and I'm hoping for improvements) but theoretical
"unstructure" arguments without considering constraints offer little
clue.

-- Gaby
0
gdr (104)
5/30/2005 10:03:22 PM
Gabriel Dos Reis wrote:
> 
> | > Surely, C++ template implementations pose real challenges which are
> | > far beyond simply filling structures with pointer to functions and
> | > claiming "genericity".  Sadly, it looks like academic literature does
> | > not offer better :-((
> | 
> | I suppose that depends on your definition of "better". Of course, you
> | won't find anything that subsumes all that templates do (not least
> | because that may not exactly be deemed desirable). But you will
> | definitely find "academic" languages that offer comparable mechanisms
> | that are even more expressive along certain axes, while staying much
> | more structured and principled. Type classes come to mind immediately,
> | which - incidentally - /can/ be compiled into tuples of functions.
> 
> I think I specifically dismissed compilation into tuples of functions
> on the ground that it does not match the expressive power offered by
> templates.

Yes, and I tried to point out (quote below) that this is a faulty 
argument. I even believe that with some tweaks a clean-ups you could 
apply that technique to something close enough to templates. That you 
cannot do so in C++ is a consequence of the ad-hoc nature of many of its 
other features that in multiplicity preclude a systematic approach to 
template compilation other than macro expansion. For starters, its 
baroque, context-dependent scoping and name resolution rules, on top of 
highly ambiguous syntax.

> There is a urban legend that C or C++ designers or
> implementers obviously don't quite understand functional programming
> languages and features and implementations.  That legend, for large
> part, is unfounded.

OK, I take your word for it. Certain aspects of C++ - particularly with 
respect to typing - certainly make that hard to believe.

> | Note that the inability to do the latter for templates might rather be
> | a consequence of their unstructured nature (plus the lack of closures
> | and other issues of C++) rather than of their expressiveness.
> 
> As a well known Swiss Army instruction goes, when the terrain and the
> map differ -- trust the terrain. No doubt some programming languages
> are invented to prove a point, but I've come to realize that the C++
> templates were designed to solve a problem.

I read that as implicitly claiming that the same would not be true for 
similar features in FPLs or other "academic" languages. That does not 
quite support your previous point about urban legends... ;-)

> I'm not claiming it is
> perfect (and I'm hoping for improvements) but theoretical
> "unstructure" arguments without considering constraints offer little
> clue.

Oh, I am aware of the constraints. Does not lead me to like the outcome, 
though. The problem are these constraints to start with, templates just 
add to the complexity.

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
5/31/2005 9:26:49 AM
I recently came across this in a web discussion forum, and thought it
kind of cute (even if the author is possibly sincere, and the typo an
accident): 

| C++ is one of those few languages that allow you to do low-level
| stuff, compiles to compact and efficient code, yet also has concise
| powerful syntax (how many languages allow you to specify matrix
| multiplication by saying a + b?).

-kzm
-- 
If I haven't seen further, it is by standing in the footprints of giants
0
news2 (145)
5/31/2005 9:37:50 AM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Gabriel Dos Reis wrote:
| > | > Surely, C++ template implementations pose real challenges which
| > are
| > | > far beyond simply filling structures with pointer to functions and
| > | > claiming "genericity".  Sadly, it looks like academic literature does
| > | > not offer better :-((
| > | | I suppose that depends on your definition of "better". Of
| > course, you
| > | won't find anything that subsumes all that templates do (not least
| > | because that may not exactly be deemed desirable). But you will
| > | definitely find "academic" languages that offer comparable mechanisms
| > | that are even more expressive along certain axes, while staying much
| > | more structured and principled. Type classes come to mind immediately,
| > | which - incidentally - /can/ be compiled into tuples of functions.
| > I think I specifically dismissed compilation into tuples of functions
| > on the ground that it does not match the expressive power offered by
| > templates.
| 
| Yes, and I tried to point out (quote below) that this is a faulty
| argument.

I think, you made that statement without actually showing why it is so.

Clearly, compiling to tuple of functions is already supported by
C++ in form of virtual functions.  Templates, by design, were based on
the idea that when instantiated they should match the code as if it was
hand crafted directly.  It is hard, near to impossible to match that
zero-overhead if you comile to a tuple of functions with current
compiler technology.  It is very tempting to hide the inefficency of
tuple of functions behing the angle-bracket notation, as is done by
some languages. But, in the case of C++ that is a real concern and a
direct part of C++ template success.  It is not an argument, It is
report of a fact.  See below.

| I even believe that with some tweaks a clean-ups you could
| apply that technique to something close enough to templates. That you

What specifically are those "twaeks and clean-ups"?  That is not an
argumentative question, as this is an area I have high interest in and
open to suggestions.

| cannot do so in C++ is a consequence of the ad-hoc nature of many of
| its other features that in multiplicity preclude a systematic approach
| to template compilation other than macro expansion. For starters, its
| baroque, context-dependent scoping and name resolution rules, on top
| of highly ambiguous syntax.

Oh, the syntax is not the problem to separate compilation.  It is not
what precludes compilation to tuple of functions.  The dependent name
resolution is necessary if one ever wanted to meaningfully abstract
over anything.  You earlier metioned type classes, but that is exactly
what they do -- the name in those cases designate pointer to member
fields of tuples.  And use of type classes is context dependent too.
So, exactly what are those solutions? Handwaving does not give me a clue. 

[...]

| > | Note that the inability to do the latter for templates might rather be
| > | a consequence of their unstructured nature (plus the lack of closures
| > | and other issues of C++) rather than of their expressiveness.
| > As a well known Swiss Army instruction goes, when the terrain and the
| > map differ -- trust the terrain. No doubt some programming languages
| > are invented to prove a point, but I've come to realize that the C++
| > templates were designed to solve a problem.
| 
| I read that as implicitly claiming that the same would not be true for
| similar features in FPLs or other "academic" languages. That does not
| quite support your previous point about urban legends... ;-)

Well, I certainly cannot stop you from reading the way you want ;-)
What I claim is that, C++ templates were primarily designed to solve a
problem (that of being able to write a paramterized function or class
that, when instantiated, matches the efficiency of un-parameterized one).
They were not designed to prove a point that it is possible to compile
parameterized form separately.  If that were the aim, then clearly the
C++ designers knew how to do it.

| > I'm not claiming it is
| > perfect (and I'm hoping for improvements) but theoretical
| > "unstructure" arguments without considering constraints offer little
| > clue.
| 
| Oh, I am aware of the constraints. Does not lead me to like the
| outcome, though.

But given the constraints, do you have a better solution?  
(Compiling to tuple of functions does not meet the constraints).

We have listed what appear to us to be the most important constraints
here: 

   http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf

| The problem are these constraints to start with,
| templates just add to the complexity.

It can be argued that templates add complexity, but so does any new
language functionalities or "tweaks and clean-ups" in some sense.  So,
the issue must not be just that of adding complexity.  Certainly,
cost/benefits is an evaluating criteria.

-- Gaby
0
gdr (104)
5/31/2005 11:36:02 AM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

>> There is a urban legend that C or C++ designers or
>> implementers obviously don't quite understand functional programming
>> languages and features and implementations.  That legend, for large
>> part, is unfounded.
>
> OK, I take your word for it. Certain aspects of C++ - particularly
> with respect to typing - certainly make that hard to believe.

Seconded.  Also, for me, having /listened/ to one of the C++ designers
speak publicly and touch upon this subject makes it even harder to
believe.

0
find19 (1244)
5/31/2005 12:23:26 PM
Gabriel Dos Reis wrote:
> But given the constraints, do you have a better solution?  
> (Compiling to tuple of functions does not meet the constraints).
> 
> We have listed what appear to us to be the most important constraints
> here: 
> 
>    http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf

Well, if being compatible with C++ is a constraint, then you pretty much 
have to live with all the problems that C++ templates carry.

However, I think Andreas is comparing things along a different axis. 
It's not "how would a saner/checkable/better C++ template system look 
like", it's about the power/expressivity/safety of mechanisms that are 
different from C++ templates but offer similar abstraction facilities.

Regards,
Jo
0
jo427 (1164)
5/31/2005 12:37:47 PM
Gabriel Dos Reis wrote:

> Andreas Rossberg <rossberg@ps.uni-sb.de> writes:
> 
> | Gabriel Dos Reis wrote:
> | >      | If it doesn't say anything about those, why has template
> | > recursion
> | > | been treated differently?
> | > | | By the way, if you say that it isn't "normative", does that mean
> | > that
> | > | a compiler that limits it to, say, 1, would be a conforming C++
> | > | compiler?  If not, why not?
> | > A compiler can set the limit to 1, it would be conformant in that
> | > regard.  Whether it would be useful is a different question :-)
> | 
> | Then the situation is, in fact, worse than I anticipated.
> 
> Quite possible.  As I have been trying to taint this whole discussion
> with a little of reality, have you found any C++ compiler in
> production use/existence that set that limit to 1?  Or is it just pure
> speculation? 

The existence of such limits isn't too interesting for hand-written 
code, since most of the limitations listed can be overcome by rewriting 
the code.

However, the way Annex B does not make promises, and the list of things 
that are in it, that's all very bad for generated code. It's easy to 
have more than 256 nested parentheses in an expression, or to go beyond 
any of the other limits that a C++ compiler may have and be compliant.

I'm quite puzzled why C++ has such a long list of limited resources. In 
a modern system, it would be easy to lift all these restrictions (and 
replace them with the blanket "limited by available memory" statement).

Templates are different. Template instantiation can recurse, so 
termination isn't decidable. For that reason, it makes sense to limit 
recursion depth (or instantiation depth).

That recursion was felt to be necessary says something about the limited 
expressivity of templates though. If templates-without-recursion were 
more expressive, recursion wouldn't have been deemed necessary. (FPLs 
have instantiation mechanisms that are powerful enough for practical use 
but don't run into that undecidability trap. A typical FPL compiler 
indeed has just one limitation: available memory.)

Regards,
Jo
0
jo427 (1164)
5/31/2005 12:48:02 PM
Gabriel Dos Reis wrote:
> 
> Clearly, compiling to tuple of functions is already supported by
> C++ in form of virtual functions.  Templates, by design, were based on
> the idea that when instantiated they should match the code as if it was
> hand crafted directly.  It is hard, near to impossible to match that
> zero-overhead if you comile to a tuple of functions with current
> compiler technology.   It is very tempting to hide the inefficency of
> tuple of functions behing the angle-bracket notation, as is done by
> some languages. But, in the case of C++ that is a real concern and a
> direct part of C++ template success.  It is not an argument, It is
> report of a fact.  See below.

You cannot expect to arrive at a good language when you don't separate 
issues of semantics and implementation properly.

The root of many of the problems with C++ obviously is that most of its 
design process was driven by that sort of premature optimisation. With 
all kinds of hidden assumptions about "current compiler technology".

Regarding the latter, monomorphisation is a well-known optimisation 
technique for getting rid of implicit arguments passed to polymorphic 
definitions. It is not specifically hard to implement.

> | I even believe that with some tweaks a clean-ups you could
> | apply that technique to something close enough to templates. That you
> 
> What specifically are those "twaeks and clean-ups"?

Most prominently, giving proper typing to template parameters, to avoid 
any dependency of a templates meaning on the context of instantiation. 
And no: "concepts" don't cut it. I always thought they adhere to a scary 
notion of "flexibility" instead of imposing some proper structure.

> | cannot do so in C++ is a consequence of the ad-hoc nature of many of
> | its other features that in multiplicity preclude a systematic approach
> | to template compilation other than macro expansion. For starters, its
> | baroque, context-dependent scoping and name resolution rules, on top
> | of highly ambiguous syntax.
> 
> Oh, the syntax is not the problem to separate compilation.

It is part of it. If we ignore Perl, then no other modern language has 
context-sensitive parsing as bad as C++ has it, and that surely is part 
of the reason to require a macro-based approach (and clutches like 
"typename").

> The dependent name
> resolution is necessary if one ever wanted to meaningfully abstract
> over anything.  You earlier metioned type classes, but that is exactly
> what they do -- the name in those cases designate pointer to member
> fields of tuples.  And use of type classes is context dependent too.

Not at all on the same level. One problem in C++ e.g. is resolution of 
overloaded operators, which can refer to different definitions (global 
or member), depending on what is available. Another one is 
disambiguation of declarations and expressions, etc.

In other words, you not only have overloaded /names/ in C++, you have 
(heavily) overloaded and hence ambiguous /syntax/ - which is much worse.

> What I claim is that, C++ templates were primarily designed to solve a
> problem (that of being able to write a paramterized function or class
> that, when instantiated, matches the efficiency of un-parameterized one).
> They were not designed to prove a point that it is possible to compile
> parameterized form separately.  If that were the aim, then clearly the
> C++ designers knew how to do it.

Didn't you say in your previous post that separate compilation /was/ an aim?

> | Oh, I am aware of the constraints. Does not lead me to like the
> | outcome, though.
> 
> But given the constraints, do you have a better solution?  

No. But IMO the constraints are not put up wisely.

> (Compiling to tuple of functions does not meet the constraints).
> 
> We have listed what appear to us to be the most important constraints
> here: 
> 
>    http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf

And I just noted that this document proposes use of tuples of functions 
for enabling separate compilation of templates. :-)

My favorite quote from it still is:

| The C++ templates are fundamentally more abstract and flexible than
| type-based approaches (with its inspiration in math rather than in
| type theory).

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
5/31/2005 12:51:49 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Clearly, compiling to tuple of functions is already supported by
> C++ in form of virtual functions.

"Compiling to a tuple of functions" in and of itself is not the goal.
The goal is to type-check and compile separately.

> Templates, by design, were based on
> the idea that when instantiated they should match the code as if it was
> hand crafted directly.

The SML module systems gives you all of theses:

   * Functors are always type-checked separately and for functors that
     type-check there is a guarantee that any argument that matches
     the argument signature will lead to a successful instantiation.
   * If desired, functors can be compiled separately (usually using
     the tuples of functions approach).
   * Functors can be implemented using the "macro-expansion" approach,
     yielding code that is as efficient as hard-crafted code.

There exist at least two implementations for either strategy of
implementing functors in SML.

>  It is hard, near to impossible to match that
> zero-overhead if you comile to a tuple of functions with current
> compiler technology.

See above.  "Tuple of functions" is not the ultimate goal but merely
one technique for compiling separately.  Of course, separate
compilation nearly always has a certain overhead since at the time of
compiling the code one does not have all the information that one
would have in the macro-expand case.  It is a trade-off, and good
*language* design would give implementers a choice of which technology
they prefer.

> Well, I certainly cannot stop you from reading the way you want ;-)
> What I claim is that, C++ templates were primarily designed to solve a
> problem (that of being able to write a paramterized function or class
> that, when instantiated, matches the efficiency of un-parameterized one).
> They were not designed to prove a point that it is possible to compile
> parameterized form separately.  If that were the aim, then clearly the
> C++ designers knew how to do it.

"Clearly?"

> But given the constraints, do you have a better solution?  
> (Compiling to tuple of functions does not meet the constraints).

See above.

> We have listed what appear to us to be the most important constraints
> here: 
>
>    http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf

Choice quote from this document:

  "The C++ templates are fundamentally more abstract and flexible than
  type-based approaches (with its inspiration in math rather than in type
  theory)."

Remarkably, the notion of "concepts" that the document talks about at
length is (as far as I could tell) nothing more than what is commonly
known as a "kind".  But I know, this is inspired by math, not by type
theory... *g*

Cheers,
Matthias
0
find19 (1244)
5/31/2005 12:57:02 PM
Joachim Durchholz <jo@durchholz.org> writes:

| Gabriel Dos Reis wrote:
| > But given the constraints, do you have a better solution?
| > (Compiling to tuple of functions does not meet the constraints).
| > We have listed what appear to us to be the most important constraints
| > here:
| > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
| 
| Well, if being compatible with C++ is a constraint, then you pretty
| much have to live with all the problems that C++ templates carry.

Breaking C++ is not a luxury we have, that is a fundamental constraint.

-- Gaby
0
gdr (104)
5/31/2005 3:28:30 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Gabriel Dos Reis wrote:
| > Clearly, compiling to tuple of functions is already supported by
| > C++ in form of virtual functions.  Templates, by design, were based on
| > the idea that when instantiated they should match the code as if it was
| > hand crafted directly.  It is hard, near to impossible to match that
| > zero-overhead if you comile to a tuple of functions with current
| > compiler technology.   It is very tempting to hide the inefficiency of
| > tuple of functions behind the angle-bracket notation, as is done by
| > some languages. But, in the case of C++ that is a real concern and a
| > direct part of C++ template success.  It is not an argument, It is
| > report of a fact.  See below.
| 
| You cannot expect to arrive at a good language when you don't separate
| issues of semantics and implementation properly.

That is a matter of opinion instead of fact.  Whether a functionality
can be implemented, and be efficiently implemented has always been
part of the constraints -- that is the "designed to solve a problem part".
That is, the purpose was not just to add features, but consider ones
that can be efficiently implemented where C is supposed to run.  If
implementations and efficiency were not a concern, C++ designers knew
how to do far better.  

| The root of many of the problems with C++ obviously is that most of
| its design process was driven by that sort of premature
| optimisation. 

Implementation constraint is not premature optimization.

| With all kinds of hidden assumptions about "current
| compiler technology".

Where is the hidden assumption about compiler technology.  Again, this
is not argumentative.  Each time we have a new functionality, one has
to explain how it can be implemented and people have to form idea
about its efficiency.  That is no hidden assumption, that is no
premature optimization.

| Regarding the latter, monomorphisation is a well-known optimisation
| technique for getting rid of implicit arguments passed to polymorphic
| definitions. It is not specifically hard to implement.

Consider that C++ has a notion of separate compilation (largely
inherited from C) and has to work with most traditional linkers; how
do you concretely make that well-known optimization avaliable
everywhere C++ runs? The issues are not that simple, unless you
haven't tackle them for real.  

| > | I even believe that with some tweaks a clean-ups you could
| > | apply that technique to something close enough to templates. That you
| > What specifically are those "tweaks and clean-ups"?
| 
| Most prominently, giving proper typing to template parameters, to
| avoid any dependency of a templates meaning on the context of
| instantiation.

That is still handwaving.  Exactly what do you call "proper typing"?
It is crucial to nail that down, especially when you claim that
"concept" doesn't cut it.

| And no: "concepts" don't cut it. I always thought they
| adhere to a scary notion of "flexibility" instead of imposing some
| proper structure.

Is that thought based on actual discussion with C++ designers, or
based on a perception of what it might mean, given the premise that
they don't quite quite understand language design?

| > | cannot do so in C++ is a consequence of the ad-hoc nature of many of
| > | its other features that in multiplicity preclude a systematic approach
| > | to template compilation other than macro expansion. For starters, its
| > | baroque, context-dependent scoping and name resolution rules, on top
| > | of highly ambiguous syntax.
| > Oh, the syntax is not the problem to separate compilation.
| 
| It is part of it. 

No, the template syntax is not part of the problem one encounters when
one tries to separately compile templates.  C++ compilers have been
offering pure parsing long before they try to separately
compile templates. 

| If we ignore Perl, then no other modern language has
| context-sensitive parsing as bad as C++ has it, and that surely is
| part of the reason to require a macro-based approach (and clutches
| like "typename").

Funny you mentioned that one.  In previous mails, I wasn't quite sure
whether you were talking about the "typename" or ".template" curious
notation. The reason for the existence of that notation is a
manifestation of a curiosity inherited from C.  Forget about template,
forget about C++ for a moment.  Consider just the following plain C

     f(a);

what is the meaning of the above.  Before saying, it obviously is a
function call, consider whether it might also mean a variable
declaration.  Either way, it depends on whether f has been declared to
name a type or not.  Consider also

     x * y;

what is its meaning?  Before saying it obviously is a multiplication,
consider whether it could mean a variable declaration too. Either way,
it depends on whether x has been declared to name a type of not.  The
context-sensitive parsing is not something template  invented; it has
been there, in the base language. 

Now, when you come to parsing templates -- independently of whether
separate compilation of templates is supported or, I'm just talking
about *parsing* -- there ought to be a way to resolve those
ambiguities (that exist independently of templates) if one is going to
abstract meaningfully over anything.

One can change the template syntax (and indeed, we've done that here
at TAMU, internally for the purpose of reasoning about C++) to make
the parsing "easier". That change does not affect the whole issue.
The basic issue is how does one separately check template uses (without
having the body), separately check template definitions (without having
the uses) and make sure that everything link together keeping in mind
the fourteen constraints we listed.

| > The dependent name
| > resolution is necessary if one ever wanted to meaningfully abstract
| > over anything.  You earlier mentioned type classes, but that is exactly
| > what they do -- the name in those cases designate pointer to member
| > fields of tuples.  And use of type classes is context dependent too.
| 
| Not at all on the same level. One problem in C++ e.g. is resolution of
| overloaded operators, which can refer to different definitions (global
| or member), depending on what is available.

Yes, but you get the same with type classes.  There is no free lunch.
If one wants to overload something, there out to be use of "evidence"
for proper resolution.  Exactly which function is choosed follows
well-defined rules; it is not that those resolutions happen randomly.
If you're thinking of a specific case, please spell it out and don't be
afraid of loading me with details.

| Another one is
| disambiguation of declarations and expressions, etc.

As I explained above, that core disambiguation has nothing to do with 
templates; that notion was inherited largely from C.  For further
historical accounts, see D&E  (or a recent posting on
comp.compilers). 

| In other words, you not only have overloaded /names/ in C++, you have
| (heavily) overloaded and hence ambiguous /syntax/ - which is much
| worse.

But none of those are the consequences of template syntax.
Overloading for C++ was invented more than two decades ago, ambiguity
was inherited from C (the latter could have been abandoned but it was
contrary to the C++ design rules and constraints).  Compilers, without
separately compiling templates, can do the disambiguation.

Since the core issue is that of separately compiling templates, it
would be nice if you forgot about the syntax for a moment (it is a
solved problem) and concentrate on the main issue :-)

| > What I claim is that, C++ templates were primarily designed to solve a
| > problem (that of being able to write a parameterized function or class
| > that, when instantiated, matches the efficiency of un-parameterized one).
| > They were not designed to prove a point that it is possible to compile
| > parameterized form separately.  If that were the aim, then clearly the
| > C++ designers knew how to do it.
| 
| Didn't you say in your previous post that separate compilation /was/ an aim?

I did say:

   Since day one of C++ template design, separate compilation of templates
   has always been there. 

and I maintain it.  Do you see a contradiction?

| > | Oh, I am aware of the constraints. Does not lead me to like the
| > | outcome, though.
| > But given the constraints, do you have a better solution?
| 
| No. 

:-(

| But IMO the constraints are not put up wisely.

Ah.

| 
| > (Compiling to tuple of functions does not meet the constraints).
| > We have listed what appear to us to be the most important constraints
| > here:
| > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
| 
| And I just noted that this document proposes use of tuples of
| functions for enabling separate compilation of templates. :-)

Maybe you did not read it correctly :-)  Let me complete it with this
(from the document):

   The constraints/concept facility must sustain and enhance the
   compile-time evaluation and inlining that are the foundations of the
   performance of classical template code.

That gives you the set of constraints we have.   

-- Gaby
0
gdr (104)
5/31/2005 4:40:27 PM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Clearly, compiling to tuple of functions is already supported by
| > C++ in form of virtual functions.
| 
| "Compiling to a tuple of functions" in and of itself is not the goal.
| The goal is to type-check and compile separately.

Agreed.

| > Templates, by design, were based on
| > the idea that when instantiated they should match the code as if it was
| > hand crafted directly.
| 
| The SML module systems gives you all of theses:
| 
|    * Functors are always type-checked separately and for functors that
|      type-check there is a guarantee that any argument that matches
|      the argument signature will lead to a successful instantiation.
|    * If desired, functors can be compiled separately (usually using
|      the tuples of functions approach).
|    * Functors can be implemented using the "macro-expansion" approach,
|      yielding code that is as efficient as hard-crafted code.
| 
| There exist at least two implementations for either strategy of
| implementing functors in SML.

However, SML has a simpler type and expression system -- trying to
express everything in form of types, as done in (S)ML, severly limit
what can be expressed (talking only about the common cases) in C++.
In fact, that approach has been proposed several times long before I
got interest in the issue.

When I started my work in separate compilation of templates,
naturally I looked around trying to have an idea of the state of the
art.  I actually, for a moment, opted to take the SML road.  Untill I
discovered that it does not work for C++ -- at least if one works in
the fourteen constraints I aluded to earlier.

Then, very recently (in 2002), I went to see Xavier Leroy and had
fruitful discussions with him.  One conclusion I came to after that
visit was that SML and OCaml take a nearly opposite direction to that
of C++ in this parameterization business.  I would, however, refrain
from characterizing one as bad and the other as good.  Most certainly
I have issues with both directions.
There is no way (at least I can't see any) at this point to reuse
their technologies without actually severely depart from the working
constraints. 

In our several papers on the issue, we explained how just listing
entities by their types does not work for C++. 

[...]

| > We have listed what appear to us to be the most important constraints
| > here: 
| >
| >    http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
| 
| Choice quote from this document:
| 
|   "The C++ templates are fundamentally more abstract and flexible than
|   type-based approaches (with its inspiration in math rather than in type
|   theory)."
| 
| Remarkably, the notion of "concepts" that the document talks about at
| length is (as far as I could tell) nothing more than what is commonly
| known as a "kind".  But I know, this is inspired by math, not by type
| theory... *g*

It is very tempting, without actually digging deep into the details of 
templates, to think that the concept stuff is just "kind" known for a
century now. 
And some people have suggested that before, so I'm not surprised by
your sarcasm :-).  
But, in fact it is not.
Also, notice the distinction between C++ template, and the search for
a type system that accounts for the relations that template arguments
must satisfy.

The fundamental reason is that concepts are not constraints on list of
types.  Template definitions define relations between their (explicit)
parameters (which can be types as well as ordinary values) and a set
of implicit parameters (those that are referred to as "dependent
names"). Concepts are expression of those relations -- which are
checked by the compiler at instantiation time.  To date, I have not
seen anything in type theory that accounts for that, not even in the
most advanced dependent-type theories.

-- Gaby
0
gdr (104)
5/31/2005 5:10:50 PM
Joachim Durchholz <jo@durchholz.org> writes:

| Gabriel Dos Reis wrote:
| 
| > Andreas Rossberg <rossberg@ps.uni-sb.de> writes:
| > | Gabriel Dos Reis wrote:
| > | >      | If it doesn't say anything about those, why has template
| > | > recursion
| > | > | been treated differently?
| > | > | | By the way, if you say that it isn't "normative", does that mean
| > | > that
| > | > | a compiler that limits it to, say, 1, would be a conforming C++
| > | > | compiler?  If not, why not?
| > | > A compiler can set the limit to 1, it would be conformant in that
| > | > regard.  Whether it would be useful is a different question :-)
| > | | Then the situation is, in fact, worse than I anticipated.
| > Quite possible.  As I have been trying to taint this whole discussion
| > with a little of reality, have you found any C++ compiler in
| > production use/existence that set that limit to 1?  Or is it just pure
| > speculation?
| 
| The existence of such limits isn't too interesting for hand-written
| code, since most of the limitations listed can be overcome by
| rewriting the code.

Well, you'll be amazed at knowing that lot of C++ programs
running out there are program generated, and I know of no report
that any of them got into this because of the informative note annex
B.  Probably, a fact is that C++ compilers have to accomodate with
with real world and in reald world none of them have set the limit to
1 or 17 without allowing its user to raise it.  If you have found any,
I would be interested (as future reference). 
Maybe this whole issue is more a matter of abstract perception than
that of concrete ones.

| However, the way Annex B does not make promises, and the list of
| things that are in it, that's all very bad for generated code. It's
| easy to have more than 256 nested parentheses in an expression, or to
| go beyond any of the other limits that a C++ compiler may have and be
| compliant.

I hope you realized that 256 is not a normative limit, and Annex B
started with reminding that implementations must document their limits
(that requirement is already formulated in the normative part �1.9)
 
  1.9 Program execution

  1 The semantic descriptions in this International Standard define a
    parameterized nondeterministic abstract machine. This
    International Standard places no requirement on the  structure of
    conforming implementations.  In particular, they need not copy or
    emulate the structure of the  abstract machine. Rather,
    conforming implementations are required to emulate (only) the
    observable behavior  of the abstract machine as explained below.

  2 Certain aspects and operations of the abstract machine are
    described in this International Standard as implementation-defined
    (for example, sizeof(int)). These constitute the parameters of the
    abstract machine. Each implementation shall include documentation
    describing its characteristics and behavior in these
    respects. Such documentation shall define the instance of the 
    abstract machine that corresponds to that implementation (referred
    to as the corresponding instance below). 

| I'm quite puzzled why C++ has such a long list of limited
| resources.

Maybe it is because you haven't seen that of C :-). See below.
(I hope they are not problem for functional programming language
implementations that generate C codes ;-))

| In a modern system, it would be easy to lift all these
| restrictions (and replace them with the blanket "limited by available
| memory" statement).

one could, but the question: isn't that blanket statement already
part of the normative part?  Seurely it is.  The other thing is you
seem to believe that C++ must run only on "a modern system", something
that needs to be clarified.  People involved in C++ standardization
felt that C++ should be able to run also on not so "modern systems".
I think we all agree that, if one sufficiently narrows its scope, one
could achieve nifty things.  C++ has been trying not to narrow to much
its scope.

| Templates are different. Template instantiation can recurse, so
| termination isn't decidable. For that reason, it makes sense to limit
| recursion depth (or instantiation depth).

You could safely remove that number 17 from Annex B, it won't change
anything to the situation, because (C++ standard, �1.4/2)

   -- If a program contains no violations of the rules in this
      International Standard, a conforming implementation shall,
      within its resource limits, accept and correctly execute that
      program. 

-- Gaby

From the C99 standard:

       5.2.4.1  Translation limits

       [#1]  The  implementation  shall  be  able  to translate and
       execute at least one program  that  contains  at  least  one
       instance of every one of the following limits:13)

         -- 127 nesting levels of blocks

         -- 63 nesting levels of conditional inclusion

         -- 12 pointer, array, and  function  declarators  (in  any
            combinations)   modifying   an  arithmetic,  structure,
            union, or incomplete type in a declaration

         -- 63 nesting levels of parenthesized declarators within a
            full declarator

         -- 63 nesting levels of parenthesized expressions within a
            full expression

         -- 63  significant  initial  characters  in  an   internal
            identifier  or  a  macro name (each universal character
            name or  extended  source  character  is  considered  a
            single character)

         -- 31   significant  initial  characters  in  an  external
            identifier (each universal character name specifying  a
            short  identifier  of  0000FFFF or less is considered 6
            characters, each universal character name specifying  a
            short  identifier  of 00010000 or more is considered 10
            characters,  and  each  extended  source  character  is
            considered   the  same  number  of  characters  as  the
            corresponding universal character name, if any)14)

         -- 4095 external identifiers in one translation unit

         -- 511 identifiers with block scope declared in one block



       ____________________

       13)Implementations  should  avoid imposing fixed translation
          limits whenever possible.

       14)See ``future language directions'' (6.11.3).



         -- 4095 macro identifiers simultaneously  defined  in  one
            preprocessing translation unit

         -- 127 parameters in one function definition

         -- 127 arguments in one function call

         -- 127 parameters in one macro definition

         -- 127 arguments in one macro invocation

         -- 4095 characters in a logical source line

         -- 4095  characters  in a character string literal or wide
            string literal (after concatenation)

         -- 65535 bytes in an object (in a hosted environment only)

         -- 15 nesting levels for #included files

         -- 1023  case  labels  for  a  switch statement (excluding
            those for any nested switch statements)

         -- 1023 members in a single structure or union

         -- 1023 enumeration constants in a single enumeration

         -- 63 levels of nested structure or union definitions in a
            single struct-declaration-list

0
gdr (104)
5/31/2005 5:39:58 PM
Gabriel Dos Reis wrote:
> 
> Implementation constraint is not premature optimization.

Constraints is not, but starting the whole design from the 
implementation end is (which was the route for many things in C++, at 
least that was my perception from lots of the discussion in D&E - YMMV).

> | With all kinds of hidden assumptions about "current
> | compiler technology".
> 
> Where is the hidden assumption about compiler technology.  Again, this
> is not argumentative.

There have been various occasions where the design of C++ was vastly 
over-optimistic (e.g. separate compilation for templates) or 
over-pessimistic (extreme emphasis on low-level features) with respect 
to compilation technology.

> | Regarding the latter, monomorphisation is a well-known optimisation
> | technique for getting rid of implicit arguments passed to polymorphic
> | definitions. It is not specifically hard to implement.
> 
> Consider that C++ has a notion of separate compilation (largely
> inherited from C) and has to work with most traditional linkers; how
> do you concretely make that well-known optimization avaliable
> everywhere C++ runs?  The issues are not that simple, unless you
> haven't tackle them for real.  

I don't deny at all that it's hard or impossible to achieve for C++.

> | > | I even believe that with some tweaks a clean-ups you could
> | > | apply that technique to something close enough to templates. That you
> | > What specifically are those "tweaks and clean-ups"?
> | 
> | Most prominently, giving proper typing to template parameters, to
> | avoid any dependency of a templates meaning on the context of
> | instantiation.
> 
> That is still handwaving.  Exactly what do you call "proper typing"?

What you find in ML functors, for example. I know that this does not 
apply to C++ as is, but that is not my point.

To answer most of your post, my point rather is that it is not 
productive to try to pursue all these ideas in context of a language 
that is so fundamentally at odds with it - one shouldn't build 
skyscrapers on swampy ground. On the long run, a clean cut serves much 
better. In the case of C++, that cut should have been done 20 years ago, 
when the scalability problems of C became obvious enough. Instead, even 
more and nastier problems were happily introduced.

> | And no: "concepts" don't cut it. I always thought they
> | adhere to a scary notion of "flexibility" instead of imposing some
> | proper structure.
> 
> Is that thought based on actual discussion with C++ designers, or
> based on a perception of what it might mean, given the premise that
> they don't quite quite understand language design?

That's my personal opinion, based on experience with C++ as well as 
languages that lack some of its alleged bits of extra flexibility, but 
still provide more satisfactory overall support for genericity.

> | If we ignore Perl, then no other modern language has
> | context-sensitive parsing as bad as C++ has it, and that surely is
> | part of the reason to require a macro-based approach (and clutches
> | like "typename").
> 
> Funny you mentioned that one.  In previous mails, I wasn't quite sure
> whether you were talking about the "typename" or ".template" curious
> notation. The reason for the existence of that notation is a
> manifestation of a curiosity inherited from C.

Yes, I'm fully aware of that and the examples you give. I said it is the 
ad-hoc nature of many other features that cause templates to be so 
hairy, and I enumerated that one as an example.

> | > The dependent name
> | > resolution is necessary if one ever wanted to meaningfully abstract
> | > over anything.  You earlier mentioned type classes, but that is exactly
> | > what they do -- the name in those cases designate pointer to member
> | > fields of tuples.  And use of type classes is context dependent too.
> | 
> | Not at all on the same level. One problem in C++ e.g. is resolution of
> | overloaded operators, which can refer to different definitions (global
> | or member), depending on what is available.
> 
> Yes, but you get the same with type classes.

No, that's not correct. With type classes, an identifier uniquely refers 
to either an ordinary value or a class method, there can only ever be 
one in scope. (A class can be instantiated by different implementations, 
but that is completely orthogonal to scoping.)

> If one wants to overload something, there out to be use of "evidence"
> for proper resolution.  Exactly which function is choosed follows
> well-defined rules; it is not that those resolutions happen randomly.
> If you're thinking of a specific case, please spell it out and don't be
> afraid of loading me with details.

I was referring to C::operator+(D) vs operator+(C,D), which is a 
completely ad-hoc form of syntactic overloading. Similarly, unrelated 
definitions can apply for a conversion, you can overload functions with 
templates, etc. Surely you know the hot spots better than me. It's no 
suprise at all that no type theory one is willing to deal with will be 
able to handle such arbitrariness.

> Since the core issue is that of separately compiling templates, it
> would be nice if you forgot about the syntax for a moment (it is a
> solved problem) and concentrate on the main issue :-)

But the syntactic overloading is what makes the obvious 
"tuples-of-functions" approach to separate compilation impossible (or at 
least very hard).

> | > What I claim is that, C++ templates were primarily designed to solve a
> | > problem (that of being able to write a parameterized function or class
> | > that, when instantiated, matches the efficiency of un-parameterized one).
> | > They were not designed to prove a point that it is possible to compile
> | > parameterized form separately.  If that were the aim, then clearly the
> | > C++ designers knew how to do it.
> | 
> | Didn't you say in your previous post that separate compilation /was/ an aim?
> 
> I did say:
> 
>    Since day one of C++ template design, separate compilation of templates
>    has always been there. 
> 
> and I maintain it.  Do you see a contradiction?

At least I must apply a very twisted interpretation of your two 
statements to not see one. ;-)

> | But IMO the constraints are not put up wisely.
> 
> Ah.

Which means, to repeat the above picture, to rather start from scratch 
than bother with adding 120 more storeys and balconies to an already 
shaky piece of architecture under the constraint of not moving or fixing 
a single leaking pipe. :-)

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
5/31/2005 6:16:09 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Joachim Durchholz <jo@durchholz.org> writes:
>
> | Gabriel Dos Reis wrote:
> | > But given the constraints, do you have a better solution?
> | > (Compiling to tuple of functions does not meet the constraints).
> | > We have listed what appear to us to be the most important constraints
> | > here:
> | > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
> | 
> | Well, if being compatible with C++ is a constraint, then you pretty
> | much have to live with all the problems that C++ templates carry.
>
> Breaking C++ is not a luxury we have, that is a fundamental constraint.

Which means, we are basically screwed...

One day mankind (or at least the computer-literate part thereof) will
look back and shake its collective head at how much intellectual
resources were wasted on that horrible mistake called C++.

Cheers,
Matthias
0
find19 (1244)
6/1/2005 12:34:28 AM
Gabriel Dos Reis wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> | Gabriel Dos Reis wrote:
> | > But given the constraints, do you have a better solution?
> | > (Compiling to tuple of functions does not meet the constraints).
> | > We have listed what appear to us to be the most important constraints
> | > here:
> | > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
> | 
> | Well, if being compatible with C++ is a constraint, then you pretty
> | much have to live with all the problems that C++ templates carry.
> 
> Breaking C++ is not a luxury we have, that is a fundamental constraint.

Well, let me utter a sacrilege... C++ is the PL/I of modern days. It's 
trying to be everything to everyone, and adding too many ways to do the 
same thing, failing to provide some key mechanisms that could replace 
the existing ones (not that this failure is a fault of its designers: 
they had to work with the insights that were available at the time of 
design); with a baroque syntax and semantics that (almost) nobody 
completely understands. Expressiveness taken too far, with guarantees 
not keeping pace.
Algol was a grandiose improvement over PL/I. I expect some FPL to be a 
grandiose improvement over C++ - not because it can do everything that 
C++ can (that would end up with an even more baroque language), but 
because it offers similar expressivity with a vastly reduced set of 
primitive operations. SML structures and Haskell typeclasses are 
proofs-of-concept for constructs that compare favorably with C++ 
templates: not Turing-complete (hence not as powerful in theory), but 
powerful enough to anything that somebody would want to express within 
the framework of a type system; with a semantics that's above the 
(roughly) macro-substitution semantics of templates, hence better 
amenable to giving guarantees both to compiler (for optimisation) and 
human (for maintaining the code).

Just personal opinion. May be outdated tomorrow ;-)

Regards,
Jo
0
jo427 (1164)
6/1/2005 12:55:19 PM
Joachim Durchholz wrote:
> 
> Well, let me utter a sacrilege... C++ is the PL/I of modern days. It's 
> trying to be everything to everyone, and adding too many ways to do the 
> same thing, failing to provide some key mechanisms that could replace 
> the existing ones (not that this failure is a fault of its designers: 
> they had to work with the insights that were available at the time of 
> design);

More than once they chose to ignore insights that were well established 
for decades. To give just one example: Stroustrup consciously decided 
against everybody's advice for designing a context-free syntax and 
implementing the cfront parser using technology like Yacc. I dare say 
that the result is catastrophic.

> Algol was a grandiose improvement over PL/I.

Um, Algol predates PL/I by almost a decade.

> SML structures and Haskell typeclasses are 
> proofs-of-concept for constructs that compare favorably with C++ 
> templates: not Turing-complete (hence not as powerful in theory)

There are extensions to ML modules as well as to type classes that make 
type checking undecidable. But at least it is clear where the boundaries 
lie. Certain generalisations of type classes even turn it into a Turing 
complete logic programming language.

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB

0
rossberg (600)
6/1/2005 1:23:33 PM
Gabriel Dos Reis wrote:

> Andreas Rossberg <rossberg@ps.uni-sb.de> writes:
> 
> | You cannot expect to arrive at a good language when you don't separate
> | issues of semantics and implementation properly.
> 
> That is a matter of opinion instead of fact.

No, it's hard fact.

I have programmed both in Eiffel and C++. Both languages are good 
representatives for the static-typing OO view of the programming world. 
Eiffel was designed for clarity of concepts, C++ was designed for 
efficient compilation. This shows in many ways:
* The default for Eiffel member functions is that they are virtual. 
Nonvirtual functions are a very rare exception. The additional dynamic 
dispatch isn't a real issue, 90% of dispatching calls can be made static 
- it's more difficult under separate compilation, and would probably 
require some kind of smart linking (in a separate step before linking 
with modules written in other languages), but it's all not quite rocket 
science, and can be made as efficient as one would care.
* You can make virtual calls from within constructors. Actually 
constructor functions are completely normal functions, except that they 
can be called when an object is constructed initially. No fiddling with 
automatic initialisation. This is *far* simpler than the set of rules 
used in C++.
* Eiffel requires garbage collection. Now that makes Eiffel unsuitable 
for HRT, but it makes it far more reliable - if a constructor throws an 
exception, created objects are orphaned and will be reclaimed. In other 
words, I don't have to worry about memory leaks - that's a *huge* 
simplification for programmers. Besides, I wouldn't want to use C++ for 
HRT either - and, no, "smart pointers" aren't a smart solution here, 
deallocating an object may trigger a chain of deallocations and makes 
deallocation less predictable (and queuing up the deallocations just 
means that memory isn't freed at the time it becomes available, so we're 
halfways back to the timing performance of traditional automatic GC, but 
with a horribly slow interface that requires permanent updates in 
reference counts). If I were to do HRT programming, I'd not use dynamic 
memory allocation anyway - so neither C++ nor Eiffel fit the bill :-)

 From my experience, I can't say that the Eiffel software that I worked 
with "felt" noticeably slower than its C++ equivalent.
However, what took me weeks in Eiffel has taken me months in C++, and 
the main culprits for that are the points above: I spent hours chasing 
bugs with functions that should have been virtual (or nonvirtual), I 
spent days chasing constructor bugs (whoever said that virtual calls 
from a constructor should go to the function that's used in the place 
where the constructor was written should be flogged with an iron whip - 
now I have static, virtual, and half-virtual functions to deal with), I 
spent weeks chasing dangling-pointer bugs.

In other words: Eiffel is *far* more efficient in programmer time (I can 
even consider algorithmic improvements while my poor fellow C++ 
programmers are still chasing pointer bugs), and while it's admittedly 
slower than C++, that's less a question of language design and more one 
of man-centuries spent in writing optimising compilers. (The Eiffel 
compilers that I worked with had no more than a few man-decades in them, 
and not many of these. If C++ had that little effort in it, it would be 
quite a lot slower. Actually early C++ compilers weren't very impressive...)

(For the record: in my eyes, improving C++ is a misguided attempt at 
improving something that should better be left to rot. I know that this 
is not feasible, simply because too much C++ software already has been 
written, and easing the job of the maintainers is worth the effort... 
but I don't think that adding new mechanisms to C++ templates is the way 
to go. C++ already has a history of compilers that barely manage to 
implement the language properly, of programmers not quite understanding 
all those complex and wonderful mechanisms (many don't grok STL, which 
is supposedly standard...) - adding yet another complex mechanism isn't 
going to improve on these points.)

Regards,
Jo
0
jo427 (1164)
6/1/2005 1:24:21 PM
Gabriel Dos Reis wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> | However, the way Annex B does not make promises, and the list of
> | things that are in it, that's all very bad for generated code. It's
> | easy to have more than 256 nested parentheses in an expression, or to
> | go beyond any of the other limits that a C++ compiler may have and be
> | compliant.
> 
> I hope you realized that 256 is not a normative limit,

Sure.

I'm also well aware that that 256 number listed is just an example of 
such a limit - it could be 100, 20, 20,000, or "bounded only by memory".

 > and Annex B
> started with reminding that implementations must document their limits
> (that requirement is already formulated in the normative part �1.9)

I don't object to the precision of Annex B - sometimes it's helpful to 
specifically state what things are explicitly *not* guaranteed.

However, I would have found it far better if the language had specified 
that no such limits are allowed (except for the obvious "limited by 
available memory"). Right now, anybody who generates C++ programs will 
have to consider all these limitations, and provide workarounds for them 
- this *vastly* complicates code generation if done properly (so most 
code-generating programs probably punt on the issue and rely on the C++ 
compiler to properly report if the table overflows).

> | I'm quite puzzled why C++ has such a long list of limited
> | resources.
> 
> Maybe it is because you haven't seen that of C :-). See below.
> (I hope they are not problem for functional programming language
> implementations that generate C codes ;-))

Contrary to popular belief, C is not a good portable assembler. The 
standard strategy for compiling FPLs nowadays seems to be machine code 
generation.

> | In a modern system, it would be easy to lift all these
> | restrictions (and replace them with the blanket "limited by available
> | memory" statement).
> 
> one could, but the question: isn't that blanket statement already
> part of the normative part?  Seurely it is.  The other thing is you
> seem to believe that C++ must run only on "a modern system", something
> that needs to be clarified.  People involved in C++ standardization
> felt that C++ should be able to run also on not so "modern systems".
> I think we all agree that, if one sufficiently narrows its scope, one
> could achieve nifty things.  C++ has been trying not to narrow to much
> its scope.

Hold it. I'd say that at C++ *compiler* can be expected to run on a 
reasonably modern system. (Besides, I don't know of a C++ compiler that 
doesn't require several dozen megabytes, so that's reality already.)

The compiled code could run on anything, from mainframe with gigabytes 
of RAM to embedded processors. Actually compiling to a smaller machine 
requires a smarter compiler, so I'd expect the performance of the 
developer machine to go up if the target system resources go down.

Besides, compiling with no arbitrary limits should be standard software 
technology today. I find it telling that C++ isn't advanced enough to 
make getting rid of these a non-problem.

If I may contrast this with my Eiffel experience: the compiler indeed 
had limits, but these were imposed by the run-time system, not by the 
parser. I simply don't understand how anybody can write a parser that 
will accept only a limited nesting depth, for example - don't they read 
the Dragon Book anymore?

Well, whenever the topic of C++ parsing comes up, I learn something new 
and disgusting about the language or its compilers.

Regards,
Jo
0
jo427 (1164)
6/1/2005 1:43:42 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Joachim Durchholz wrote:
| > Well, let me utter a sacrilege... C++ is the PL/I of modern
| > days. It's trying to be everything to everyone, and adding too many
| > ways to do the same thing, failing to provide some key mechanisms
| > that could replace the existing ones (not that this failure is a
| > fault of its designers: they had to work with the insights that were
| > available at the time of design);
| 
| More than once they chose to ignore insights that were well
| established for decades. To give just one example: Stroustrup
| consciously decided against everybody's advice for designing a
| context-free syntax and implementing the cfront parser using
| technology like Yacc. I dare say that the result is catastrophic.

I'm having hard time figuring out whether your statement has any
factual basis.  Please, don't be afraid to share your source/reference. 


As before, I will try to inject, once again, a bit of facts in this
discussion.  D&E, page 68-69

  �3.3.2  Parsing C++

  In 1982 when I first planned Cfront, I wanted to use a recursive
  descent parser because I had experience writing and maintaining such
  a beast, because I liked such parsers' ability to produce good
  error messages, and because I liked the idea of having the full
  power of a general purpose programming language available when
  decisions had to be made in the parser.  However, being a
  conscientious young computer scientist I asked the experts.  Al Aho
  and Steve Johnson were in the Computer Science Research Center and
  they, primarily Steve, convinced me that writing a parser by hand
  was most old-fashioned, would be an inefficient use of my time,
  would almost certainly result in a hard-to-understand and
  hard-to maintain parser, and would be prone to unsystematic and
  therefore unreliable error recovery.  The right way was to use an
  LALR(1) parser generator, so I used Al and Steve's YACC [Aho, 1986].

-- Gaby
0
gdr (104)
6/1/2005 6:08:37 PM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Joachim Durchholz <jo@durchholz.org> writes:
| >
| > | Gabriel Dos Reis wrote:
| > | > But given the constraints, do you have a better solution?
| > | > (Compiling to tuple of functions does not meet the constraints).
| > | > We have listed what appear to us to be the most important constraints
| > | > here:
| > | > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
| > | 
| > | Well, if being compatible with C++ is a constraint, then you pretty
| > | much have to live with all the problems that C++ templates carry.
| >
| > Breaking C++ is not a luxury we have, that is a fundamental constraint.
| 
| Which means, we are basically screwed...

Only if you decide that you;re defeated the you're screwed :-).
Personally, I think there are lot of things that can be improved and
we have done some of them. The only scare resource is time -- however,
it looks like myths and misconceptions about the facts are also time
sucker.   

| One day mankind (or at least the computer-literate part thereof) will
| look back and shake its collective head at how much intellectual
| resources were wasted on that horrible mistake called C++.

I guess that would depend on how would they measure "waste" and "mistake". 

(in this discussion, I've wated more intellectual resources trying to
inject facts in here than I've done working with C++ design and
implementations) 

The functional programminng community has "owned" institutions for
over three decades now, yet...

-- Gaby
0
gdr (104)
6/1/2005 6:15:23 PM
Joachim Durchholz <jo@durchholz.org> writes:

| Gabriel Dos Reis wrote:
| 
| > Joachim Durchholz <jo@durchholz.org> writes:
| > | Gabriel Dos Reis wrote:
| > | > But given the constraints, do you have a better solution?
| > | > (Compiling to tuple of functions does not meet the constraints).
| > | > We have listed what appear to us to be the most important constraints
| > | > here:
| > | > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
| > | | Well, if being compatible with C++ is a constraint, then you
| > pretty
| > | much have to live with all the problems that C++ templates carry.
| > Breaking C++ is not a luxury we have, that is a fundamental
| > constraint.
| 
| Well, let me utter a sacrilege... C++ is the PL/I of modern days. It's
| trying to be everything to everyone, and adding too many ways to do

Having been involved in C++ design and implementation discussions for
some time now, what I've figured out is that for many people it is
not doing enough.  For the next version of C++, the C++ standard
Evolution Working Group had asked for "wishlist" for improvements from
the community.  The list we got is quite long and looking over it, it
appears that clearly C++ was not providing enough for some people.
But I've also heard your rant some times.  The reality is that, unless
you've been close enough (either as implementors leasting to users) or
designers (listening to users) trying to improve over things, it is
hard to assess the complexity and the tension between the variety of
interests. Furthermore, if the primary design aim has been to design a
beautiful language, I'm confident that C++ designers would have done a
better job.  

| the same thing, failing to provide some key mechanisms that could
| replace the existing ones (not that this failure is a fault of its
| designers: they had to work with the insights that were available at
| the time of design); with a baroque syntax and semantics that (almost)

There is an account of C++ design history that I think anybody who
wants to make serious criticisms about quirks in C++ should read.  In
particular, it has many discussions about the syntax issues in several
paragraphs (apart from the main section �2.8 Syntax Problems). 

  �2.8  Syntax Problems

  Could I have "fixed" the most annoying deficiencies of the C syntax
  and semantics at some point before C++ was made generally available?
  Could I have done so without removing useful features (to C with
  Classes' users in their environments -- as opposed to an ideal
  world) or introducing incompatibilities that were unacceptable to C
  programmers wanting to migrate to C with Classes?  I think not.  In
  some cases, I tried, but I backed out my changes after receiving
  complaints from outraged users.

  [...] 
  
  The negative reaction to changes in this area from users was very
  strong.  they considered the "terseness" allowed by C essential to
  the point of refusing to use a "fascist" language that required them
  to write redundant type specifiers.  I backed out the change.  I
  don't think I had a choice.  Allowing that implicit int is the
  source of many of the annoying problems with the C++ grammar today.
  Note that the pressure came from users, not management or arm-chair
  language experts. [...]
 
  My eventual rationale for leaving things as they were was that any new
  syntax would (temporarily at least) add complexity to a known mess.
  Also, even though the old style is a boon to teachers of trivia and
  to people who want to ridicule C, it is not a significant problem
  for C programmers.  In this case, I'm not sure if I did the right
  thing, though.  The agony to me and other C++ implementers,
  documenters, and tool builders caused by the perversities of syntax
  has been significant.  Users can -- and do -- of course insulate
  themselves from such problems by writing in a small easily understood
  subset of the C/C++ declaration syntax (�7.2).


  �2.8.3  The Importance of Syntax

  [...]

  A subtle aspect of C compatibility discussions is that old-time C
  programmers are comfortable with the old ways of doing thing and can
  therefore be quite intolerant of the incompatibilities needed to
  support styles of programming that C wasn't designed for.
  Conversely, non-C programmers usually underestimate the value C
  programmers attribute to the C syntax.


| nobody completely understands. Expressiveness taken too far, with
| guarantees not keeping pace.
| Algol was a grandiose improvement over PL/I.

A time-travel problem?

| I expect some FPL to be a grandiose improvement over C++ - 

I hope so too.  The functional programming community has owned
institutions and spent wonderful resources there for over three
decades. It would be a terrible and unqualifiable waste if they could
not have a grandiose improvement of C++.

-- Gaby
0
gdr (104)
6/1/2005 6:49:45 PM
Joachim Durchholz wrote:
> Gabriel Dos Reis wrote:
> 
>> Breaking C++ is not a luxury we have, that is a fundamental constraint.
> 
> Well, let me utter a sacrilege... C++ is the PL/I of modern days. It's 
> trying to be everything to everyone, and adding too many ways to do the 
> same thing, failing to provide some key mechanisms that could replace 
> the existing ones (not that this failure is a fault of its designers: 
> they had to work with the insights that were available at the time of 
> design); with a baroque syntax and semantics that (almost) nobody 
> completely understands.

Almost?

Andreas Rossberg wrote:
 > Joachim Durchholz wrote:
 > > Algol was a grandiose improvement over PL/I.
 >
 > Um, Algol predates PL/I by almost a decade.

Hence Tony Hoares's comment on Algol 60:

   Here is a language so far ahead of its time, that it was not only an
   improvement on its predecessors, but also on nearly all its successors.


[The quote is from 'Hints on Programming Language Design',
<http://www.iam.unibe.ch/~scg/Teaching/PS/PS-S05/Serie-1/Hoare_Hints.pdf>
Written in December 1973, but most of it could have been written
yesterday. Another wonderful and relevant quote:

   I fear that most designers of extensible languages have spurned the
   technical simplifications which make them feasible.
]

-- 
David Hopwood <david.nospam.hopwood@blueyonder.co.uk>
0
6/1/2005 9:29:50 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> | 
> | > Joachim Durchholz <jo@durchholz.org> writes:
> | >
> | > | Gabriel Dos Reis wrote:
> | > | > But given the constraints, do you have a better solution?
> | > | > (Compiling to tuple of functions does not meet the constraints).
> | > | > We have listed what appear to us to be the most important constraints
> | > | > here:
> | > | > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
> | > | 
> | > | Well, if being compatible with C++ is a constraint, then you pretty
> | > | much have to live with all the problems that C++ templates carry.
> | >
> | > Breaking C++ is not a luxury we have, that is a fundamental constraint.
> | 
> | Which means, we are basically screwed...
>
> Only if you decide that you;re defeated the you're screwed :-).

Well, I am not defeated, but "not breaking C++" is not a constraint
that I live by.  (Actually, C++ was already broken from the start.
Every couple of years I look at it again, and it has grown more hair,
has acquired more stuff designed to patch up or hide the sins of its
past.)

> Personally, I think there are lot of things that can be improved and
> we have done some of them.

Some things are just not worth repairing.  The basic problem is that
you are not willing to "break C++" (see above).  This precludes any
improvement.  It is like giving the cancer patient a new haircut.

> | One day mankind (or at least the computer-literate part thereof) will
> | look back and shake its collective head at how much intellectual
> | resources were wasted on that horrible mistake called C++.
>
> I guess that would depend on how would they measure "waste" and "mistake". 

No, this does not depend on anything.  I was making a prediction of
what future generations will think of C++, and it contains an implied
prediction of what these generations will consider a "waste" and a
"mistake".  My prediction will either come true or it won't.  Only time
can tell, but I am confident that I am right.

> The functional programminng community has "owned" institutions for
> over three decades now, yet...

Yet what?

0
find19 (1244)
6/1/2005 10:00:32 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> | I expect some FPL to be a grandiose improvement over C++ - 
> 
> I hope so too.  The functional programming community has owned
> institutions and spent wonderful resources there for over three
> decades. It would be a terrible and unqualifiable waste if they could
> not have a grandiose improvement of C++.

A lot of the ideas from FPL could (and in my opinion should) be
transplanted to next-generation imperative programming languages. Even
if none of the FPL programming ever becomes mainstream the research has
not been a waste.

In fact this transplantation is already happening: Python has borrowed
quite a lot from functional languages (except, unfortunately, a type
system), and has become very popular. I don't know Ruby, but I get the
impression there the same is true. Guy Steele and others are designing a
new programming language Fortress that also borrows a lot.

Moreover, processor design has increasing difficulty in hiding
parallelism, so traditional imperative languages are in trouble anyway.
I doubt this trend will make an existing FPL mainstream, but at least
the FPLs show that there are alternatives, and they offer at least part
of the solution.
0
reeuwijk (3)
6/1/2005 10:39:50 PM
Joachim Durchholz <jo@durchholz.org> writes:

> Gabriel Dos Reis wrote:
> 
> > Andreas Rossberg <rossberg@ps.uni-sb.de> writes:
> > | You cannot expect to arrive at a good language when you don't
> > separate
> > | issues of semantics and implementation properly.
> > That is a matter of opinion instead of fact.
> 
> No, it's hard fact.
> 
> I have programmed both in Eiffel and C++. Both languages are good
> representatives for the static-typing OO view of the programming
> world. Eiffel was designed for clarity of concepts, C++ was designed for
> efficient compilation.

Well, I sort of agree.  But C++ was designed to be compatible with C.
Many of the problems in C++ can be traced to that compatibility
requirement.

I agree with Andreas Rossberg's statement above, but I don't think that
should mean "ignore implementation issues".

>... This shows in many ways:
> * The default for Eiffel member functions is that they are
> virtual. Nonvirtual functions are a very rare exception. The additional
> dynamic dispatch isn't a real issue, 90% of dispatching calls can be
> made static - it's more difficult under separate compilation, and would
> probably require some kind of smart linking (in a separate step before
> linking with modules written in other languages), but it's all not quite
> rocket science, and can be made as efficient as one would care.
> * You can make virtual calls from within constructors. Actually
> constructor functions are completely normal functions, except that they
> can be called when an object is constructed initially. No fiddling with
> automatic initialisation. This is *far* simpler than the set of rules
> used in C++.
> * Eiffel requires garbage collection. Now that makes Eiffel unsuitable
> for HRT, but it makes it far more reliable - if a constructor throws an
> exception, created objects are orphaned and will be reclaimed. In other
> words, I don't have to worry about memory leaks - that's a *huge*
> simplification for programmers. Besides, I wouldn't want to use C++ for
> HRT either - and, no, "smart pointers" aren't a smart solution here,
> deallocating an object may trigger a chain of deallocations and makes
> deallocation less predictable (and queuing up the deallocations just
> means that memory isn't freed at the time it becomes available, so we're
> halfways back to the timing performance of traditional automatic GC, but
> with a horribly slow interface that requires permanent updates in
> reference counts). If I were to do HRT programming, I'd not use dynamic
> memory allocation anyway - so neither C++ nor Eiffel fit the bill :-)

I'm not sure why you say that.  C++ can be used without dynamic
allocation pretty easily.  I suppose Eiffel could, too, but it's perhaps
more painful (declare everything "expanded"?).  For hard-real-time, I
prefer Ada.

- Bob
0
bobduff (1543)
6/1/2005 11:51:44 PM
Joachim Durchholz <jo@durchholz.org> writes:

> Gabriel Dos Reis wrote:
> 
> > Joachim Durchholz <jo@durchholz.org> writes:
> > | However, the way Annex B does not make promises, and the list of
> > | things that are in it, that's all very bad for generated code. It's
> > | easy to have more than 256 nested parentheses in an expression, or to
> > | go beyond any of the other limits that a C++ compiler may have and be
> > | compliant.
> > I hope you realized that 256 is not a normative limit,
> 
> Sure.
> 
> I'm also well aware that that 256 number listed is just an example of
> such a limit - it could be 100, 20, 20,000, or "bounded only by memory".
> 
>  > and Annex B
> > started with reminding that implementations must document their limits
> > (that requirement is already formulated in the normative part �1.9)
> 
> I don't object to the precision of Annex B - sometimes it's helpful to
> specifically state what things are explicitly *not* guaranteed.
> 
> However, I would have found it far better if the language had specified
> that no such limits are allowed (except for the obvious "limited by
> available memory").

I agree with you that compilers should not have such arbitrary limits,
other than those based on "available memory".  But I don't see how a
language standard can say so.  How can you write a test case that
determines whether the compiler obeys such a rule?  I mean, if the thing
crashes on the 257'th level of nesting, how do you know (formally)
whether it has an arbitrary limit of 256, or it just ran out of memory?
(You can guess...)

>... Right now, anybody who generates C++ programs will
> have to consider all these limitations, and provide workarounds for them
> - this *vastly* complicates code generation if done properly (so most
> code-generating programs probably punt on the issue and rely on the C++
> compiler to properly report if the table overflows).

Perhaps it would be better for a language standard to avoid mentioning
such limits at all.  And for a conformance test suite to use lots of
nesting.

> > | I'm quite puzzled why C++ has such a long list of limited
> > | resources.
> > Maybe it is because you haven't seen that of C :-). See below.
> > (I hope they are not problem for functional programming language
> > implementations that generate C codes ;-))
> 
> Contrary to popular belief, C is not a good portable assembler. The
> standard strategy for compiling FPLs nowadays seems to be machine code
> generation.

Well, C isn't *so* bad.  Problems include:  Lack of overflow detection.
No access to hardware operations like (single X single)-->double
integer multiply instructions.  No portable and efficient way to
implement exception handling.  Etc.

> > | In a modern system, it would be easy to lift all these
> > | restrictions (and replace them with the blanket "limited by available
> > | memory" statement).
> > one could, but the question: isn't that blanket statement already
> > part of the normative part?  Seurely it is.  The other thing is you
> > seem to believe that C++ must run only on "a modern system", something
> > that needs to be clarified.  People involved in C++ standardization
> > felt that C++ should be able to run also on not so "modern systems".
> > I think we all agree that, if one sufficiently narrows its scope, one
> > could achieve nifty things.  C++ has been trying not to narrow to much
> > its scope.
> 
> Hold it. I'd say that at C++ *compiler* can be expected to run on a
> reasonably modern system. (Besides, I don't know of a C++ compiler that
> doesn't require several dozen megabytes, so that's reality already.)

Yes.  All compilers (these days) should run on fast machines with lots
of memory.  For embedded systems, cross compilers should be used.

- Bob
0
bobduff (1543)
6/2/2005 12:06:59 AM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

> Joachim Durchholz wrote:
> > Algol was a grandiose improvement over PL/I.
> 
> Um, Algol predates PL/I by almost a decade.

Yes.  And yet Algol is an improvement upon PL/I.  ;-)

- Bob
0
bobduff (1543)
6/2/2005 12:16:55 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> [...]
>
> | > Personally, I think there are lot of things that can be improved and
> | > we have done some of them.
> | 
> | Some things are just not worth repairing.  The basic problem is that
> | you are not willing to "break C++" (see above).  This precludes any
> | improvement.
>
> But that is your opinion.  You actually have not tried.  Have you?  

No, I have not.  Not everything needs to be tried first to know that
it is no use.
0
find19 (1244)
6/2/2005 2:26:13 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> reeuwijk@few.vu.nl (Kees van Reeuwijk) writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> | 
> | > Joachim Durchholz <jo@durchholz.org> writes:
> | > 
> | > | I expect some FPL to be a grandiose improvement over C++ - 
> | > 
> | > I hope so too.  The functional programming community has owned
> | > institutions and spent wonderful resources there for over three
> | > decades. It would be a terrible and unqualifiable waste if they could
> | > not have a grandiose improvement of C++.
> | 
> | A lot of the ideas from FPL could (and in my opinion should) be
> | transplanted to next-generation imperative programming languages. Even
> | if none of the FPL programming ever becomes mainstream the research has
> | not been a waste.
>
> The point was not that ideas from functional programming languages
> could be borrowed and implanted elsewhere.  The claim was that FPL
> could be a gandiose improvement over C++.  I think it takes more than
> just borrowing.

A lot of FPLs (and a lot of other languages, too) are *already*
significant (to avoid saying "grandiose") improvements over C++.

0
find19 (1244)
6/2/2005 2:27:54 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> | 
> | > Matthias Blume <find@my.address.elsewhere> writes:
> | >
> | > [...]
> | >
> | > | > Personally, I think there are lot of things that can be improved and
> | > | > we have done some of them.
> | > | 
> | > | Some things are just not worth repairing.  The basic problem is that
> | > | you are not willing to "break C++" (see above).  This precludes any
> | > | improvement.
> | >
> | > But that is your opinion.  You actually have not tried.  Have you?  
> | 
> | No, I have not.
>
> Thanks for the confirmation, I was suspecting that possibility but I
> was not sure.

To avoid misunderstandings: I am *very* interested in well-designed
programming languages, their design in itself, their efficient
implementation, and their application.  But that does not mean I have
to work on something in which I see absolutely no value just to be
able to judge it. C++ is so far from my idea of a good language, it
cannot possibly be "improved" to something I would like and use
voluntarily, especially not if there is a "constraint" that all the
existing badness needs to be preserved.  Therefore, your suggestion
that I am somehow not in the position of judging wether C++ is good or
bad just because I have not personally tried to improve it is more
than misguided.

Matthias
0
find19 (1244)
6/2/2005 2:51:56 AM
Matthias Blume <find@my.address.elsewhere> writes:

[...]

| > Personally, I think there are lot of things that can be improved and
| > we have done some of them.
| 
| Some things are just not worth repairing.  The basic problem is that
| you are not willing to "break C++" (see above).  This precludes any
| improvement.

But that is your opinion.  You actually have not tried.  Have you?  

-- Gaby
0
gdr (104)
6/2/2005 2:54:37 AM
reeuwijk@few.vu.nl (Kees van Reeuwijk) writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
| 
| > Joachim Durchholz <jo@durchholz.org> writes:
| > 
| > | I expect some FPL to be a grandiose improvement over C++ - 
| > 
| > I hope so too.  The functional programming community has owned
| > institutions and spent wonderful resources there for over three
| > decades. It would be a terrible and unqualifiable waste if they could
| > not have a grandiose improvement of C++.
| 
| A lot of the ideas from FPL could (and in my opinion should) be
| transplanted to next-generation imperative programming languages. Even
| if none of the FPL programming ever becomes mainstream the research has
| not been a waste.

The point was not that ideas from functional programming languages
could be borrowed and implanted elsewhere.  The claim was that FPL
could be a gandiose improvement over C++.  I think it takes more than
just borrowing.

-- Gaby
0
gdr (104)
6/2/2005 2:57:45 AM
David Hopwood <david.nospam.hopwood@blueyonder.co.uk> writes:

| Joachim Durchholz wrote:
| > Gabriel Dos Reis wrote:
| >
| >> Breaking C++ is not a luxury we have, that is a fundamental constraint.
| > Well, let me utter a sacrilege... C++ is the PL/I of modern
| > days. It's trying to be everything to everyone, and adding too many
| > ways to do the same thing, failing to provide some key mechanisms
| > that could replace the existing ones (not that this failure is a
| > fault of its designers: they had to work with the insights that were
| > available at the time of design); with a baroque syntax and
| > semantics that (almost) nobody completely understands.
| 
| Almost?
| 
| Andreas Rossberg wrote:
|  > Joachim Durchholz wrote:
|  > > Algol was a grandiose improvement over PL/I.
|  >
|  > Um, Algol predates PL/I by almost a decade.
| 
| Hence Tony Hoares's comment on Algol 60:
| 
|    Here is a language so far ahead of its time, that it was not only an
|    improvement on its predecessors, but also on nearly all its successors.
| 

I thought it was clear that, for most claims in this thread, facts are
obviously perversions that should be avoided. :-)


-- Gaby
0
gdr (104)
6/2/2005 3:01:24 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> | 
> | > reeuwijk@few.vu.nl (Kees van Reeuwijk) writes:
> | >
> | > | Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
> | > | 
> | > | > Joachim Durchholz <jo@durchholz.org> writes:
> | > | > 
> | > | > | I expect some FPL to be a grandiose improvement over C++ - 
> | > | > 
> | > | > I hope so too.  The functional programming community has owned
> | > | > institutions and spent wonderful resources there for over three
> | > | > decades. It would be a terrible and unqualifiable waste if they could
> | > | > not have a grandiose improvement of C++.
> | > | 
> | > | A lot of the ideas from FPL could (and in my opinion should) be
> | > | transplanted to next-generation imperative programming languages. Even
> | > | if none of the FPL programming ever becomes mainstream the research has
> | > | not been a waste.
> | >
> | > The point was not that ideas from functional programming languages
> | > could be borrowed and implanted elsewhere.  The claim was that FPL
> | > could be a gandiose improvement over C++.  I think it takes more than
> | > just borrowing.
> | 
> | A lot of FPLs (and a lot of other languages, too) are *already*
> | significant (to avoid saying "grandiose") improvements over C++.
>
> That may be quite possible though I would prefer facts not just claims
> (there seem to be many of them in this thread that carefully avoid
> being tainted by reality) and evidence of why they are significant
> improvement over C++.  

What "reality" are you talking about?  The many deficits of C++ have
been listed over and over.  I won't repeat them here.

As for me, I find programming in those FPL far more pleasant and
productive than trying to do the same in C++.

> No, I would not take your word for it, sorry :-)

I am not asking you to take my word for it.  Just a shame that some
clearly capable people waste their talents on something which, as I
believe strongly, will ultimately be known as a grandiose mistake.

0
find19 (1244)
6/2/2005 3:03:09 AM
Robert A Duff <bobduff@shell01.TheWorld.com> writes:

| Joachim Durchholz <jo@durchholz.org> writes:
| 
| > Gabriel Dos Reis wrote:
| > 
| > > Joachim Durchholz <jo@durchholz.org> writes:
| > > | However, the way Annex B does not make promises, and the list of
| > > | things that are in it, that's all very bad for generated code. It's
| > > | easy to have more than 256 nested parentheses in an expression, or to
| > > | go beyond any of the other limits that a C++ compiler may have and be
| > > | compliant.
| > > I hope you realized that 256 is not a normative limit,
| > 
| > Sure.
| > 
| > I'm also well aware that that 256 number listed is just an example of
| > such a limit - it could be 100, 20, 20,000, or "bounded only by memory".
| > 
| >  > and Annex B
| > > started with reminding that implementations must document their limits
| > > (that requirement is already formulated in the normative part �1.9)
| > 
| > I don't object to the precision of Annex B - sometimes it's helpful to
| > specifically state what things are explicitly *not* guaranteed.
| > 
| > However, I would have found it far better if the language had specified
| > that no such limits are allowed (except for the obvious "limited by
| > available memory").
| 
| I agree with you that compilers should not have such arbitrary limits,
| other than those based on "available memory".  But I don't see how a
| language standard can say so.  How can you write a test case that
| determines whether the compiler obeys such a rule?  I mean, if the thing
| crashes on the 257'th level of nesting, how do you know (formally)
| whether it has an arbitrary limit of 256, or it just ran out of memory?

It is a point I've already made, pointing to the relevant part of the C++
definition; but that does not count it appears...

[...]

| Yes.  All compilers (these days) should run on fast machines with lots
| of memory.

And for those that don't?  They are still quite plenty of them, last
time I checked.  As an implementer, I regularly get complain about the
compiler speed on not so modern but not so old machines,

|  For embedded systems, cross compilers should be used.

Yes, but there is a wide spectrum between the two extremes.

-- Gaby


0
gdr (104)
6/2/2005 3:09:03 AM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Matthias Blume <find@my.address.elsewhere> writes:
| >
| > [...]
| >
| > | > Personally, I think there are lot of things that can be improved and
| > | > we have done some of them.
| > | 
| > | Some things are just not worth repairing.  The basic problem is that
| > | you are not willing to "break C++" (see above).  This precludes any
| > | improvement.
| >
| > But that is your opinion.  You actually have not tried.  Have you?  
| 
| No, I have not.

Thanks for the confirmation, I was suspecting that possibility but I
was not sure.

-- Gaby
0
gdr (104)
6/2/2005 3:39:04 AM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > reeuwijk@few.vu.nl (Kees van Reeuwijk) writes:
| >
| > | Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
| > | 
| > | > Joachim Durchholz <jo@durchholz.org> writes:
| > | > 
| > | > | I expect some FPL to be a grandiose improvement over C++ - 
| > | > 
| > | > I hope so too.  The functional programming community has owned
| > | > institutions and spent wonderful resources there for over three
| > | > decades. It would be a terrible and unqualifiable waste if they could
| > | > not have a grandiose improvement of C++.
| > | 
| > | A lot of the ideas from FPL could (and in my opinion should) be
| > | transplanted to next-generation imperative programming languages. Even
| > | if none of the FPL programming ever becomes mainstream the research has
| > | not been a waste.
| >
| > The point was not that ideas from functional programming languages
| > could be borrowed and implanted elsewhere.  The claim was that FPL
| > could be a gandiose improvement over C++.  I think it takes more than
| > just borrowing.
| 
| A lot of FPLs (and a lot of other languages, too) are *already*
| significant (to avoid saying "grandiose") improvements over C++.

That may be quite possible though I would prefer facts not just claims
(there seem to be many of them in this thread that carefully avoid
being tainted by reality) and evidence of why they are significant
improvement over C++.  
No, I would not take your word for it, sorry :-)

-- Gaby
0
gdr (104)
6/2/2005 3:46:17 AM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Matthias Blume <find@my.address.elsewhere> writes:
| >
| > | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| > | 
| > | > Matthias Blume <find@my.address.elsewhere> writes:
| > | >
| > | > [...]
| > | >
| > | > | > Personally, I think there are lot of things that can be improved and
| > | > | > we have done some of them.
| > | > | 
| > | > | Some things are just not worth repairing.  The basic problem is that
| > | > | you are not willing to "break C++" (see above).  This precludes any
| > | > | improvement.
| > | >
| > | > But that is your opinion.  You actually have not tried.  Have you?  
| > | 
| > | No, I have not.
| >
| > Thanks for the confirmation, I was suspecting that possibility but I
| > was not sure.
| 
| To avoid misunderstandings: I am *very* interested in well-designed
| programming languages, their design in itself, their efficient
| implementation, and their application.  But that does not mean I have
| to work on something in which I see absolutely no value just to be
| able to judge it. C++ is so far from my idea of a good language, it
| cannot possibly be "improved" to something I would like and use
| voluntarily, especially not if there is a "constraint" that all the
| existing badness needs to be preserved.  Therefore, your suggestion
| that I am somehow not in the position of judging wether C++ is good or
| bad just because I have not personally tried to improve it is more
| than misguided.

Well, the suggestion was not that you're not in position to make
judgement on something you have not tried but have strong opinions on
and are absolutely right that it cannot not be improved.  It looks
like to you can draw just about any conclusion.

-- Gaby
0
gdr (104)
6/2/2005 6:31:50 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

>| A lot of the ideas from FPL could (and in my opinion should) be
>| transplanted to next-generation imperative programming languages. Even
>| if none of the FPL programming ever becomes mainstream the research has
>| not been a waste.

> The point was not that ideas from functional programming languages
> could be borrowed and implanted elsewhere.  

The point of research and universities is mainly to produce ideas.
Products are to a large extent side effects, proofs of concept that
an idea works in practice.  Expecting computer science departments to
compete with C++ is like expecting the literature department to
publish best seller novels.

> The claim was that FPL could be a gandiose improvement over C++.  I
> think it takes more than just borrowing.

I used to have a job writing C++ code.  I definitely believe I'm more
productive and write more robust code using a FPL, and I *know* that I
have a lot more fun doing it.

Which FPLs have you used, and in what ways do you think they are
inferior to C++?

-kzm
-- 
If I haven't seen further, it is by standing in the footprints of giants
0
news2 (145)
6/2/2005 6:37:35 AM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Matthias Blume <find@my.address.elsewhere> writes:
| >
| > | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| > | 
| > | > reeuwijk@few.vu.nl (Kees van Reeuwijk) writes:
| > | >
| > | > | Gabriel Dos Reis <gdr@integrable-solutions.net> wrote:
| > | > | 
| > | > | > Joachim Durchholz <jo@durchholz.org> writes:
| > | > | > 
| > | > | > | I expect some FPL to be a grandiose improvement over C++ - 
| > | > | > 
| > | > | > I hope so too.  The functional programming community has owned
| > | > | > institutions and spent wonderful resources there for over three
| > | > | > decades. It would be a terrible and unqualifiable waste if they could
| > | > | > not have a grandiose improvement of C++.
| > | > | 
| > | > | A lot of the ideas from FPL could (and in my opinion should) be
| > | > | transplanted to next-generation imperative programming languages. Even
| > | > | if none of the FPL programming ever becomes mainstream the research has
| > | > | not been a waste.
| > | >
| > | > The point was not that ideas from functional programming languages
| > | > could be borrowed and implanted elsewhere.  The claim was that FPL
| > | > could be a gandiose improvement over C++.  I think it takes more than
| > | > just borrowing.
| > | 
| > | A lot of FPLs (and a lot of other languages, too) are *already*
| > | significant (to avoid saying "grandiose") improvements over C++.
| >
| > That may be quite possible though I would prefer facts not just claims
| > (there seem to be many of them in this thread that carefully avoid
| > being tainted by reality) and evidence of why they are significant
| > improvement over C++.  
| 
| What "reality" are you talking about?  The many deficits of C++ have
| been listed over and over.  I won't repeat them here.

Like this 

  <d7kcsl$2581l$4@hades.rz.uni-saarland.de> 
?

Yes, please don't :-)

Furthermore, as has being pointed out, the "many deficits" of C++
listed here have been made based on misunderstanding of what they are
and where they came from.  Someone insisted on syntax and "typename"
issue without quite understanding that it was a problem inherited from
C, as opposed to a problem introduced by templates.  

In fact, I've found that working on C++ is more challenging than, say,
working on ML variants or Haskell -- not that those languages do not
provide opportunities for intellectual excitements.  The primary
reason being that problems with C++ are really challenging for both
existing theories, design and implementation techniques.  As you may
know, some have even decided not to look because they thought they
could not make any progress :-)  And, it is quite gratifying to see
that progress can be made where others have resigned -- but I do
not expect to convince you of that. 

| As for me, I find programming in those FPL far more pleasant and
| productive than trying to do the same in C++.

I do respect you opinion.
Personally, my FPLs are not that good as my C/C++ but I do have
extensive programming experience with FPLs (hard to do otherwise in
certain areas in the French system) and I've come to the conclusion
that despite those aspects I really dislike in C++, I've yet to see
most of claimed advances in modern FPLs match in expressivity and
scalability  -- yes, I know that is a sufficient reason to be flamed
for on c.l.f. but I'm hope there are souls there less dogmatic (yes, I
know there are, I've met them on several occasions :-)).  I don't have
to like it before solving the challenges it poses.  I'd encourage
anyone who has not been there before to try it.

Now, what about others far more well-known who have actually
transgressed the cultural barriers and sub-community walls?

     http://www.stepanovpapers.com/

But, I guess that does not count.

| > No, I would not take your word for it, sorry :-)
| 
| I am not asking you to take my word for it.  Just a shame that some
| clearly capable people waste their talents on something which, as I
| believe strongly, will ultimately be known as a grandiose mistake.

Yes, I guess if those people spent their talents on SML/NJ it would
not be waste. 
In fact I tried for some time -- it is hard to evolve in the French
system without being exposed to hardcore FP, especially in certain
academic circles -- and decided my efforts are best spent somewhere
else.  Clearly, the notion of what is "waste" is not universal.  And I
understand you hold yours very firmly.
I'm just hoping that somedays, cultural barriers will be transgressed
more smoothly and we would be talking about semantics, programming,
systems building,  instead of focusing on angle brackets, bananas,
curly-braces and dot-notations.  

-- Gaby
0
gdr (104)
6/2/2005 7:28:58 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
> 
> | A lot of FPLs (and a lot of other languages, too) are *already*
> | significant (to avoid saying "grandiose") improvements over C++.
> 
> That may be quite possible though I would prefer facts not just claims
> (there seem to be many of them in this thread that carefully avoid
> being tainted by reality) and evidence of why they are significant
> improvement over C++.  
> No, I would not take your word for it, sorry :-)

I tried to offer what is at least anecdotal evidence from 
an industrial setting of how we've used Erlang to gain a 
quite significant edge in productivity and quality.

"Four-Fold Increase in Productivity and Quality"
http://www.erlang.se/publications/Ulf_Wiger.pdf
FEmSYS 2001, Munich.

The "four-fold increase in productivity" relates to the
observation that systems with similar feature sets tend
to have 4-10x more lines of source code when written in 
C++ than in Erlang. We chose the more conservative 
estimate of four. Measuring line-per-man hour productivity,
different projects seem to be fairly similar as well, but 
obviously then, the more expressive language wins. 
Similarly for quality, we've observed that fault
density measured in errors per KLOC seems to be roughly 
the same. Given fewer lines of code per feature, total
quality by this measure should be higher.

Since the writing of that paper, the fault-density measured
in errors per 100 lines of code has decreased by a factor
3-4 in the product in question, at the same time as the 
source code volume has doubled in size. We are now in the 
process of building successors to that product, where we 
have been able to rewrite and restructure more freely, and
I believe that the end result will be quite impressive.

There are some obvious problems: I cannot reveal all the 
background data due to confidentiality constraints. It's 
also quite difficult to produce scientific comparisons 
of products written in different programming languages,
since we obviously never build the same product twice
using teams that are identical in experience and 
competence, but with different implementation technologies
(and the size and complexity of the products, something 
that obviously affects the comparison, makes it practically
impossible to perform such a study in an academic (or indeed
any) setting). Furthermore, the improvements made since 2001
also reflect the fact that we've had low personnel turnover,
and thus have many designers with several years of 
experience working with this technology and using our 
methodology. Especially for FPLs in a commercial environment,
this is something very unusual. 

Some of my thoughts on using unconventional development
tools in industry were summarized in 
http://www.erlang.se/workshop/2004/ulfwiger.pdf

/Uffe
-- 
Ulf Wiger, Senior Specialist,
   / / /   Architecture & Design of Carrier-Class Software
  / / /    Team Leader, Software Characteristics
 / / /     Ericsson AB, IMS Gateways
0
ulf.wiger1 (107)
6/2/2005 9:00:25 AM
Andreas Rossberg wrote:

> Joachim Durchholz wrote:
> 
>> Algol was a grandiose improvement over PL/I.
> 
> Um, Algol predates PL/I by almost a decade.

Yes. It was a great improvement over many of its successors.
(This isn't my observation, I'm just quoting somebody (Dijkstra?) from 
memory.)

Regards,
Jo
0
jo427 (1164)
6/2/2005 12:08:01 PM
Gabriel Dos Reis wrote:

> Furthermore, as has being pointed out, the "many deficits" of C++
> listed here have been made based on misunderstanding of what they are
> and where they came from.

I agree that there may be misunderstandings about where C++ deficits 
come from. However, what they are is well-known (ignoring Annex B for 
the moment - compared to some other problems, this is really a secondary 
point).

 > Someone insisted on syntax and "typename"
> issue without quite understanding that it was a problem inherited from
> C, as opposed to a problem introduced by templates.  

It's still a serious problem. Mimicking C++'s quirks in C so closely had 
advantages for acceptability, but it make the language far, far worse.

However, I think Bjarne got a lot of the new things really, really wrong 
(overloading, per-default nonvirtual functions, almost all aspects of 
constructor semantics, redundant class specifications, just to name a 
few). Most of these seem to be due to a (mistaken, IMNSHO) priorisation 
of efficient compilation and run-time execution over a clean language 
semantics.

> In fact, I've found that working on C++ is more challenging than, say,
> working on ML variants or Haskell -- not that those languages do not
> provide opportunities for intellectual excitements.  The primary
> reason being that problems with C++ are really challenging for both
> existing theories, design and implementation techniques.  As you may
> know, some have even decided not to look because they thought they
> could not make any progress :-)  And, it is quite gratifying to see
> that progress can be made where others have resigned -- but I do
> not expect to convince you of that. 

I don't think it's even remotely possible to turn C++ into a safe 
language. This says everything that I need to know about whether 
investing intellectual effort into it is worth it.

> | As for me, I find programming in those FPL far more pleasant and
> | productive than trying to do the same in C++.
> 
> I do respect you opinion.
> Personally, my FPLs are not that good as my C/C++ but I do have
> extensive programming experience with FPLs (hard to do otherwise in
> certain areas in the French system) and I've come to the conclusion
> that despite those aspects I really dislike in C++, I've yet to see
> most of claimed advances in modern FPLs match in expressivity and
> scalability  -- yes, I know that is a sufficient reason to be flamed
> for on c.l.f. but I'm hope there are souls there less dogmatic (yes, I
> know there are, I've met them on several occasions :-)).  I don't have
> to like it before solving the challenges it poses.  I'd encourage
> anyone who has not been there before to try it.

Um... where are the scalability problems?

Actually C++ offers its own set of scalability problems. There's often 
cultural blindness involved - people get so used to the limitations of 
the language that they use on a day-to-day basis that they think the 
problems are of a general nature, instead of due to design mistakes in 
the language.

> I'm just hoping that somedays, cultural barriers will be transgressed
> more smoothly and we would be talking about semantics, programming,
> systems building,  instead of focusing on angle brackets, bananas,
> curly-braces and dot-notations.  

I have been talking about semantics all the time. My conclusion has been 
that C++ sucks, plain and simple. That's even common wisdom, as in "C 
gives you enough rope to hang yourself, but C++ also provides you with a 
gun and ammo to blow your feet off".

Not that I particularly like C++'s syntax. It's a nightmare. Template 
syntax is just as bad; I'm amazed about the amount of i**ocy that makes 
a language designer use << >> as template parameter delimiters and set 
up the parsing rules so that you need symbol table information to see 
whether that's two < < symbols in a row or a single << parameter.

In other words: while I agree that Bjarne had a tough job being 
compatible enough with C to avoid outrage (a questionable but reasonable 
decision), he added so much to the syntactic confusion that C 
compatibility simply isn't a good excuse anymore. C++ is a piece of 
language design teaching how *not* to do it. (This doesn't mean I could 
do better. I just observe that there were a lot of people who are doing 
better. It's a pity that nobody besides Bjarne tried a good 
static-typing extension to C - or, if alternatives existed, they didn't 
get the attention that Bjarne with his corporate backing got.)

Regards,
Jo
0
jo427 (1164)
6/2/2005 12:31:50 PM
Robert A Duff wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
>> * Eiffel requires garbage collection. [...] If I were to do HRT 
>> programming, I'd not use dynamic memory allocation anyway - so
 >> neither C++ nor Eiffel fit the bill :-)
> 
> I'm not sure why you say that.  C++ can be used without dynamic 
> allocation pretty easily.   I suppose Eiffel could, too, but it's
> perhaps more painful (declare everything "expanded"?).

Well, you could, but "expanded" means you don't have polymorphism. In 
other words, all the OO stuff goes out of the window, and you could just 
as well program in Ada or Modula or whatever.

I'd expect similar problems with C++ if dynamic memory allocation is 
disallowed, but I'm not familiar enough with that scenario to tell for sure.

Regards,
Jo
0
jo427 (1164)
6/2/2005 12:40:24 PM
Joachim Durchholz <jo@durchholz.org> writes:

> I'm amazed about the amount of i**ocy that makes a language designer
> use << >> as template parameter delimiters and set up the parsing
> rules so that you need symbol table information to see whether
> that's two < < symbols in a row or a single << parameter.

Delimiters are < >, not << >>, and >> never means > >, unlike Java
(and < < never occurs); actually this is what many people consider
a wart.

Symbol table information is required to distinguish between template
parameters and less-than operator though. Parsing C++ requires full
typechecking, including name resolution, overloading resolution,
template instantiation, and evaluation of constant expressions.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/2/2005 12:40:37 PM
Robert A Duff wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
>>However, I would have found it far better if the language had specified
>>that no such limits are allowed (except for the obvious "limited by
>>available memory").
> 
> I agree with you that compilers should not have such arbitrary limits,
> other than those based on "available memory".  But I don't see how a
> language standard can say so.  How can you write a test case that
> determines whether the compiler obeys such a rule?

Simple enough. Write a test suite that doubles any limit in question. 
Observe the compiler's memory footprint. If the memory footprint nears 
available memory, without the compiler complaining, it passes.

Of course, a devious compiler writer could get away with arbitrary 
limits, either by providing large-enough tables or by arbitrarily 
allocating unneeded memory :-)
.... but then I don't think anybody would do that :-))

>>>> I'm quite puzzled why C++ has such a long list of limited
>>>> resources.
>>>Maybe it is because you haven't seen that of C :-). See below.
>>>(I hope they are not problem for functional programming language
>>>implementations that generate C codes ;-))
>>
>>Contrary to popular belief, C is not a good portable assembler. The
>>standard strategy for compiling FPLs nowadays seems to be machine code
>>generation.
> 
> Well, C isn't *so* bad.  Problems include:  Lack of overflow detection.
> No access to hardware operations like (single X single)-->double
> integer multiply instructions.  No portable and efficient way to
> implement exception handling.  Etc.

No tail-call optimisation. This is the first barrier that FPL compiler 
writers hit (exceptions and some issues with closure construction and 
other exoticities come next, but many implementors have already given up 
on C before reaching that point).

Regards,
Jo
0
jo427 (1164)
6/2/2005 12:46:02 PM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:

> Symbol table information is required to distinguish between template
> parameters and less-than operator though. Parsing C++ requires full
> typechecking, including name resolution, overloading resolution,
> template instantiation, and evaluation of constant expressions.

A pathologic example: whether <2> in the last line is template
parameter or less-then and greater-then operators depends on the
number of bits in an int.

template<unsigned N> struct C {static const int x = 1;};
template<> struct C<0> {template<int a> static void x(int b) {}};
int main() {C<0x100u * 0x100u>::x<2>(3);}

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/2/2005 12:49:22 PM
>>>>> Joachim Durchholz wrote (on Thu, 02 Jun 2005 at 13:08):

    > Andreas Rossberg wrote:
    >> Joachim Durchholz wrote:
    >> 
    >>> Algol was a grandiose improvement over PL/I.
    >> Um, Algol predates PL/I by almost a decade.

    > Yes. It was a great improvement over many of its successors.
    > (This isn't my observation, I'm just quoting somebody (Dijkstra?) from
    > memory.)

Hoare. In "Hints on programming language design".

H

0
hancock (83)
6/2/2005 12:55:43 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Furthermore, as has being pointed out, the "many deficits" of C++
> listed here have been made based on misunderstanding of what they are
> and where they came from.  Someone insisted on syntax and "typename"
> issue without quite understanding that it was a problem inherited from
> C, as opposed to a problem introduced by templates.  

The fact that it is inherited from C *is* the problem.  (I don't care
"where it came from".  If it is bad, it is bad.)
You seem to suggest that something becomes better if we understand why
it came to be so bad.  I reject that view.

> In fact, I've found that working on C++ is more challenging than, say,
> working on ML variants or Haskell -- not that those languages do not
> provide opportunities for intellectual excitements.

Teaching calculus to dogs is also far more challenging than teaching
it to humans.  Should we enroll dogs in math courses, for the
challenge's sake?

By the way, what specifically have you done "working on ML variants or
Haskell"?  (Just curious.)

> The primary reason being that problems with C++ are really
> challenging for both existing theories, design and implementation
> techniques.

Yes, but that is precisely the problem with C++.  Basically, it is
way, way too complex -- withouth this complexity actually being paid
for by anything good.

> As you may know, some have even decided not to look because they
> thought they could not make any progress :-)
> And, it is quite gratifying to see that progress can be made where
> others have resigned -- but I do not expect to convince you of that.

I don't consider the development of C++ "progress" -- not its original
design, and not its subsequent development.  So far, not having
accepted the "challenge" seems like it was the right thing to do.

> Yes, I guess if those people spent their talents on SML/NJ it would
> not be waste.

Spending one's efforts on one particular implementation (or even just
one particular language) only is probably going to be a waste unless
lessons can be learned that "survive".  Lessons from ML will certainly
survive.

> Clearly, the notion of what is "waste" is not universal.

Granted.  However, notice that my prediction (i.e., my belief) is that
C++ will *eventually* be viewed as a waste (almost) universally.

> I'm just hoping that somedays, cultural barriers will be transgressed
> more smoothly and we would be talking about semantics, programming,
> systems building,  instead of focusing on angle brackets, bananas,
> curly-braces and dot-notations.  

Did I say even one word about "angle brackets, bananas, curly-braces
and dot-notations"?

Matthias

PS: What are "bananas"?
0
find19 (1244)
6/2/2005 1:01:43 PM
Gabriel Dos Reis wrote:
> 
> Furthermore, as has being pointed out, the "many deficits" of C++
> listed here have been made based on misunderstanding of what they are
> and where they came from.  Someone insisted on syntax and "typename"
> issue without quite understanding that it was a problem inherited from
> C, as opposed to a problem introduced by templates.  

Since I believe that you are referring to me I have to rebut that I 
think it's you who still misunderstands. To repeat: I'm aware of the 
constraints and their origins, I'm aware that it's hard to achieve 
anything significantly better under these constraints. But since I'm not 
bound to these constraints (I don't need C compatibility), I don't need 
to consider them in my evaluation of the outcome.

And I simply can't believe that you do not see any deficits in the outcome.

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB
0
rossberg (600)
6/2/2005 2:06:18 PM
Gabriel Dos Reis wrote:
> 
> As before, I will try to inject, once again, a bit of facts in this
> discussion.  D&E, page 68-69
> 
>   �3.3.2  Parsing C++
> 
>   In 1982 when I first planned Cfront, I wanted to use a recursive
>   descent parser because I had experience writing and maintaining such
>   a beast, because I liked such parsers' ability to produce good
>   error messages, and because I liked the idea of having the full
>   power of a general purpose programming language available when
>   decisions had to be made in the parser.  However, being a
>   conscientious young computer scientist I asked the experts.  Al Aho
>   and Steve Johnson were in the Computer Science Research Center and
>   they, primarily Steve, convinced me that writing a parser by hand
>   was most old-fashioned, would be an inefficient use of my time,
>   would almost certainly result in a hard-to-understand and
>   hard-to maintain parser, and would be prone to unsystematic and
>   therefore unreliable error recovery.  The right way was to use an
>   LALR(1) parser generator, so I used Al and Steve's YACC [Aho, 1986].

Come on, I don't have the book here, but I recall that in the next 
paragraph he describes how he failed, how he judged that as a 
consequence of using the wrong tool (instead of realizing that the 
syntax design was broken) and abandoned it.

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB
0
rossberg (600)
6/2/2005 2:15:52 PM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Furthermore, as has being pointed out, the "many deficits" of C++
| > listed here have been made based on misunderstanding of what they are
| > and where they came from.  Someone insisted on syntax and "typename"
| > issue without quite understanding that it was a problem inherited from
| > C, as opposed to a problem introduced by templates.  
| 
| The fact that it is inherited from C *is* the problem.  (I don't care
| "where it came from".  If it is bad, it is bad.)
| You seem to suggest that something becomes better if we understand why
| it came to be so bad.  I reject that view.

I did not suggest that, so you may reject view that and that is fine;
don't say I suggested it.

| > In fact, I've found that working on C++ is more challenging than, say,
| > working on ML variants or Haskell -- not that those languages do not
| > provide opportunities for intellectual excitements.
| 
| Teaching calculus to dogs is also far more challenging than teaching
| it to humans.

That is an interesting observation.

|  Should we enroll dogs in math courses, for the
| challenge's sake?

I think the idea may worth consideration, in particular if someone
like you were part of the class.  The challengce might not necessarily
from come where one might think.

[...]

| > Yes, I guess if those people spent their talents on SML/NJ it would
| > not be waste.
| 
| Spending one's efforts on one particular implementation (or even just
| one particular language) only is probably going to be a waste unless
| lessons can be learned that "survive".  Lessons from ML will certainly
| survive.

And of course, lessons from ML will survive but not from C++; and this
is because you've looked enough into C++ problems to state that.

| > Clearly, the notion of what is "waste" is not universal.
| 
| Granted.  However, notice that my prediction (i.e., my belief) is that
| C++ will *eventually* be viewed as a waste (almost) universally.
| 
| > I'm just hoping that somedays, cultural barriers will be transgressed
| > more smoothly and we would be talking about semantics, programming,
| > systems building,  instead of focusing on angle brackets, bananas,
| > curly-braces and dot-notations.  
| 
| Did I say even one word about "angle brackets, bananas, curly-braces
| and dot-notations"?

those are my words for "syntax".

| 
| Matthias
| 
| PS: What are "bananas"?

a notation common in certain area of FP community.

-- Gaby
0
gdr (104)
6/2/2005 2:42:55 PM
Marcin 'Qrczak' Kowalczyk wrote:
> 
> A pathologic example: whether <2> in the last line is template
> parameter or less-then and greater-then operators depends on the
> number of bits in an int.
> 
> template<unsigned N> struct C {static const int x = 1;};
> template<> struct C<0> {template<int a> static void x(int b) {}};
> int main() {C<0x100u * 0x100u>::x<2>(3);}

Nice one! That pretty much says everything. Of course, there will be a 
perfectly viable excuse for this behaviour...

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB
0
rossberg (600)
6/2/2005 2:51:18 PM
Joachim Durchholz <jo@durchholz.org> writes:

| Robert A Duff wrote:
| 
| > Joachim Durchholz <jo@durchholz.org> writes:
| >
| >>However, I would have found it far better if the language had specified
| >>that no such limits are allowed (except for the obvious "limited by
| >>available memory").
| > I agree with you that compilers should not have such arbitrary
| > limits,
| > other than those based on "available memory".  But I don't see how a
| > language standard can say so.  How can you write a test case that
| > determines whether the compiler obeys such a rule?
| 
| Simple enough. Write a test suite that doubles any limit in
| question.

Simple enough, but that does not cut it.  Each time you run a compiler,
you run a possibly different instantiation of the abstract machine and
a process from the the host environment. 

| Observe the compiler's memory footprint. 

but how do you express that in a language standard?

| Of course, a devious compiler writer could get away with arbitrary
| limits, either by providing large-enough tables or by arbitrarily
| allocating unneeded memory :-)
| ... but then I don't think anybody would do that :-))

Notice that some compilers set internal characteristics, passes or
resource limits, depending on the avaliable memory.  

-- Gaby
0
gdr (104)
6/2/2005 2:55:40 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

> Marcin 'Qrczak' Kowalczyk wrote:
>> A pathologic example: whether <2> in the last line is template
>> parameter or less-then and greater-then operators depends on the
>> number of bits in an int.
>> template<unsigned N> struct C {static const int x = 1;};
>> template<> struct C<0> {template<int a> static void x(int b) {}};
>> int main() {C<0x100u * 0x100u>::x<2>(3);}
>
> Nice one! That pretty much says everything. Of course, there will be a
> perfectly viable excuse for this behaviour...

I'm confident there is some paragraph somewhere, written by Bjarne
himself, telling the world how angry users forced him to leave things
this way, even though he know better...
0
find19 (1244)
6/2/2005 3:07:17 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

> Gabriel Dos Reis wrote:
>> As before, I will try to inject, once again, a bit of facts in this
>> discussion.  D&E, page 68-69

>>   therefore unreliable error recovery.  The right way was to use an
>>   LALR(1) parser generator, so I used Al and Steve's YACC [Aho, 1986].

> Come on, I don't have the book here, but I recall that in the next
> paragraph he describes how he failed, how he judged that as a
> consequence of using the wrong tool (instead of realizing that the
> syntax design was broken) and abandoned it.

Incidentally, I just discovered my copy when cleaning up a shelf.
Here's how it continues:

  For most projects, it would have been the right choice.  For almost
  every project writing an experimental language from scratch, it
  would have been the right choice.  For most people, it would have
  been the right choice.  In retrospect, for me and C++ it was a bad
  mistake.  C++ was not a new experimental language, it was an almost
  compatible superset of C. [difficulties of C parsing snipped] Worse,
  it seems that some people have a natural affinity to some parser
  strategies and others work much better with other strategies.  My
  bias towards top-down parsing has shown itself many times over the
  years in the form of constructs that are hard to fit into a YACC
  grammar. To this day, Cfront has a YACC parser supplemented by much
  lexical trickery relying on recursive descent techniques.  On the
  other hand, it /is/ possible to write an efficient and reasonably
  nice recursive descent parser for C++.  Several modern C++ compilers
  use recursive descent.

So, it is blamed on the sucky syntax of C, but also on his personal
preferences (preferring sucky syntax? :-).

-kzm
-- 
If I haven't seen further, it is by standing in the footprints of giants
0
news2 (145)
6/2/2005 5:58:14 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Gabriel Dos Reis wrote:
| > As before, I will try to inject, once again, a bit of facts in this
| > discussion.  D&E, page 68-69
| >   �3.3.2  Parsing C++
| >   In 1982 when I first planned Cfront, I wanted to use a recursive
| >   descent parser because I had experience writing and maintaining such
| >   a beast, because I liked such parsers' ability to produce good
| >   error messages, and because I liked the idea of having the full
| >   power of a general purpose programming language available when
| >   decisions had to be made in the parser.  However, being a
| >   conscientious young computer scientist I asked the experts.  Al Aho
| >   and Steve Johnson were in the Computer Science Research Center and
| >   they, primarily Steve, convinced me that writing a parser by hand
| >   was most old-fashioned, would be an inefficient use of my time,
| >   would almost certainly result in a hard-to-understand and
| >   hard-to maintain parser, and would be prone to unsystematic and
| >   therefore unreliable error recovery.  The right way was to use an
| >   LALR(1) parser generator, so I used Al and Steve's YACC [Aho, 1986].
| 
| Come on, 

Oh yeah, don't bother contrasting your previous claim with what
actually happened. 

| I don't have the book here, but I recall that in the next
| paragraph he describes how he failed, how he judged that as a
| consequence of using the wrong tool (instead of realizing that the
| syntax design was broken)

I don't know how much of determined distorsion it takes to make
the above statement, when the author said (page 45):

   Could I have "fixed" the most annoying deficiencies of the C syntax
   and semantics at some point before C++ was made pubically
   available?  Could I have done so without removing useful features
   (to C with Classes' users in their environments -- as opposed to an
   idea world) or introducing incompatibilities that were unacceptable
   to C programmers wanting to migrate to C with Classes?  I think
   not.  In some cases, I tried, but I backed out my changes after
   complaints from outraged users.

   [...]

   The part of the C syntax I disliked the most was the declaration
   syntax.  Having both prefix and postfix declarator operators is the
   source of a fair amount of confusion. [...]

   The negative reaction to changes in this area from users was very
   strong.  They considered the "terseness" allowed by C essential to
   the point of refusing to use a "fascist" language that required
   them to write redundant type specifiers.  I backed out the
   change. I don't think I had a choice.  Allowing implicit int is the
   source of many of the annoying problems with the C++ grammar
   today. Note that the pressure came from users, not management or
   arm-chair language experts. [...]

   Similarly, I considered the possibility of introducing a linear
   notation for declarators.  The C trick of having the declaration of
   a name mimic its use leads to declarations that are hard to read
   and write, and maximizes the opportunity for humans and programs to
   confuse declarations and expressions. 

   [...]

   My eventual rationale for leaving things as they were was that any
   new syntax would (temporarily at least) add complexity to a known
   mess.  Also, even though the old style is a boon to teachers of
   trivia and to people who want to ridicule C, it is not a
   significant problem for C programmers.  I this case, I'm not sure
   if I did the right thing, though.  The agony to me and C++
   implementers, documenters, and tool builders caused by the
   perversities of syntax has been significant.  Users can -- and do
   -- of course insulate themselves from such problems by writing in a
   small and easily understood subset of C/C++ declaration syntax.

Andreas, if you want to accuse and ridicule someone of atroce
ignorance, at least do it right, based on facts.


| and abandoned it.

Again, from facts, he did not abandon the YACC parser.

  For most projects, it would have been the right choice, For almost
  every project writing an experimental language from scratch, it
  would have been the right choice.  In retrospect, for me and C++ it
  was a bad mistake.  C++ was not a new experimental language, it was
  an almost compatible superset of C -- and at the time nobody had
  been able to write an LALR(1) grammar for C.  The LALR(1) grammar
  used by ANSI C was constructed by Tom Pennello about a year and half
  later -- far too late to benefit me and C++.  Even Steve Johnson's
  PCC, which was the preeminent C compiler at the time, cheated at
  details that were to prove troublesome to C++ parser writers.  For
  example, PCC didn't handle redundant parentheses correctly so that 
  int(x); wasn't accepted as a declaration as a declaration of x.
  Worse, it seems hat some people have a natural affinity to some
  parser strategies and work much better with other strategies.  My
  bias toward top-down parsing has shown itself many times other the
  years in the form of constructs that are hard to fit into a YACC
  grammar.  To this day, Cfront has a YACC parser supplemented by much
  lexical trickery relying on recursive descent techniques.  On the
  other hand, it /is/ possible to write an efficient and reasonably
  nice recursive descent parser for C++.  Several modern C++ compilers
  use recursive descent.

-- Gaby
0
gdr (104)
6/2/2005 6:47:37 PM
Problems with C/C++ syntaxes result from choices which didn't cause
troubles when they were made, only later after the languages have been
extended in other aspects.

The original C syntax was context-free. When 'typedef' got added,
parsing of declarations and casts started to depend on which
identifiers name types. In C++ it got worse with classes
(whose members can be types or not) and templates.

The syntax of declarations didn't look as bad when the only modifiers
of a declarator were D[N] (array), D[] (pointer) and D() (function).
Then pointers got a syntax more distinct from arrays, function
parameters became a part of the function's type, function pointers
and method pointers got added, and we arrived at what we have now,
where the 'signal' function can be declared as
   void (*signal(int signum, void (*handler)(int)))(int);

The syntax of casts was easy to parse when all types started with a
keyword. With the adition of 'typedef', function parameter types etc.
the '(T) E' syntax become nearly ambiguous, and old gcc versions
misparsed 'throw (C());' with apparently redundant parentheses as
a beginning of a cast of something to a function pointer type
(promoted from a function type).

The choice of <> as template brackets didn't cause parsing problems at
first (except the annoyance with >>), but then the ability to specify
function template parameters explicitly on a function call got added,
and they started to collide with relational operators.

Templates were originally expanded almost textually, and were only
minimally parsed at definition time. Later rules changed in order
to detect more errors at template definition time rather than
instantiation time, and the comittee had to add the 'typename'
keyword and a syntax like 'C<T>::template f<T>(x, x)' in order
to distinguish type names from other names, and template names
from other names, before seeing their definitions.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/2/2005 6:49:50 PM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:

| Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:
| 
| > Symbol table information is required to distinguish between template
| > parameters and less-than operator though. Parsing C++ requires full
| > typechecking, including name resolution, overloading resolution,
| > template instantiation, and evaluation of constant expressions.

Parsing C++ does not require template instantiation, nor overload
resolutions, nor full typechecking.  
But, in this discussion facts don't count.  

| A pathologic example: whether <2> in the last line is template
| parameter or less-then and greater-then operators depends on the
| number of bits in an int.

If you want to see pathology, why don't you do it right and ask people
in the trenches?

   http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1757.html

you may even get more pathological examples if that is what you're
after.  

-- Gaby
0
gdr (104)
6/2/2005 6:59:48 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> | > Symbol table information is required to distinguish between template
> | > parameters and less-than operator though. Parsing C++ requires full
> | > typechecking, including name resolution, overloading resolution,
> | > template instantiation, and evaluation of constant expressions.
>
> Parsing C++ does not require template instantiation, nor overload
> resolutions, nor full typechecking.

C++ parser needs to know which names are types, and which names are
templates. For qualified names like C<T>::name this requires template
instantiation and matching template specializations.

Matching template specializations requires evaluating constant
expressions. Computing the value of a constant expression which
involves sizeof requires computing the type of an arbitrary
expression. Computing the type requires overload resolution.

From C++ draft:

  6.8  Ambiguity resolution                                 [stmt.ambig]

1 There is an ambiguity in the grammar  involving  expression-statements
  and   declarations:  An  expression-statement  with  a  function-style
  explicit type conversion (_expr.type.conv_) as its leftmost subexpres-
  sion  can  be  indistinguishable  from  a  declaration where the first
  declarator starts with a (.  In those cases the statement is a  decla-
  ration.   [Note: To disambiguate, the whole statement might have to be
  examined to determine if it is an expression-statement or  a  declara-
  tion.   This  disambiguates  many examples.  [Example: assuming T is a
  simple-type-specifier (_dcl.type_),
          T(a)->m = 7;       // expression-statement
          T(a)++;            // expression-statement
          T(a,5)<<c;         // expression-statement
          T(*d)(int);        // declaration
          T(e)[5];           // declaration
          T(f) = { 1, 2 };   // declaration
          T(*g)(double(3));  // declaration
  In the last example above, g, which is a pointer to T, is  initialized
  to  double(3).  This is of course ill-formed for semantic reasons, but
  that does not affect the syntactic analysis.   --end example]

2 The remaining cases are declarations.  [Example:
          class T {
                  // ...
          public:
                  T();
                  T(int);
                  T(int, int);
          };
          T(a);         // declaration
          T(*b)();      // declaration
          T(c)=7;       // declaration
          T(d),e,f=3;   // declaration
          extern int h;
          T(g)(h,2);    // declaration
   --end example]  --end note]

3 The disambiguation is purely syntactic; that is, the  meaning  of  the
  names  occurring  in  such  a statement, beyond whether they are type-
  names or not, is not generally used in or changed by  the  disambigua-
  tion.  Class templates are instantiated as necessary to determine if a
  qualified name is a type-name.  Disambiguation precedes parsing, and a
  statement disambiguated as a declaration may be an ill-formed declara-
  tion.  If, during parsing, a name in a  template  parameter  is  bound
  differently  than  it would be bound during a trial parse, the program
  is ill-formed.  No diagnostic is required.  [Note: This can occur only
  when the name is declared earlier in the declaration.  ] [Example:

          struct T1 {
                  T1 operator()(int x) { return T1(x); }
                  int operator=(int x) { return x; }
                  T1(int) { }
          };
          struct T2 { T2(int){ } };
          int a, (*(*b)(T2))(int), c, d;
          void f() {
                  // dismabiguation requires this to be parsed
                  // as a declaration
                  T1(a) = 3,
                  T2(4),                  // T2 will be declared as
                  (*(*b)(T2(c)))(int(d)); // a variable of type T1
                                          // but this will not allow
                                          // the last part of the
                                          // declaration to parse
                                          // properly since it depends
                                          // on T2 being a type-name
          }
   --end example]

[...]

  8.2  Ambiguity resolution                              [dcl.ambig.res]

1 The ambiguity arising from the  similarity  between  a  function-style
  cast and a declaration mentioned in _stmt.ambig_ can also occur in the
  context of a declaration.  In that context, the choice  is  between  a
  function  declaration  with  a  redundant  set of parentheses around a
  parameter name and an object declaration with a function-style cast as
  the   initializer.    Just   as   for  the  ambiguities  mentioned  in
  _stmt.ambig_, the resolution is to consider any construct  that  could
  possibly  be a declaration a declaration.  [Note: a declaration can be
  explicitly disambiguated by a nonfunction-style cast, by a = to  indi-
  cate  initialization  or  by removing the redundant parentheses around
  the parameter name.  ] [Example:
          struct S {
              S(int);
          };
          void foo(double a)
          {
              S w(int(a));        // function declaration
              S x(int());         // function declaration
              S y((int)a);        // object declaration
              S z = int(a);       // object declaration
          }
   --end example]

2 The ambiguity arising from the  similarity  between  a  function-style
  cast  and  a  type-id  can occur in different contexts.  The ambiguity
  appears as a choice between a function-style  cast  expression  and  a
  declaration  of  a  type.   The  resolution is that any construct that
  could possibly be a type-id in its syntactic context shall be  consid-
  ered a type-id.

3 [Example:
          #include <cstddef>
          char *p;
          void *operator new(size_t, int);
          void foo()  {
                  const int x = 63;
                  new (int(*p)) int;      // new-placement expression
                  new (int(*[x]));        // new type-id
          }

4 For another example,

          template <class T>
          struct S {
          T *p;
          };
          S<int()> x;             // type-id
          S<int(1)> y;            // expression (ill-formed)

5 For another example,
          void foo()
          {
                  sizeof(int(1)); // expression
                  sizeof(int());  // type-id (ill-formed)
          }

6 For another example,
          void foo()
          {
                  (int(1));       // expression
                  (int())1;       // type-id (ill-formed)
          }
   --end example]

7 Another  ambiguity arises in a parameter-declaration-clause of a func-
  tion declaration, or in a type-id that is the operand of a  sizeof  or
  typeid  operator,  when a type-name is nested in parentheses.  In this
  case, the choice is between the declaration of  a  parameter  of  type
  pointer  to function and the declaration of a parameter with redundant
  parentheses around the declarator-id.  The resolution is  to  consider
  the  type-name as a simple-type-specifier rather than a declarator-id.
  [Example:
          class C { };
          void f(int(C)) { } // void f(int (*fp)(C c)) { }
                             // not: void f(int C);

          int g(C);

          void foo() {
                  f(1);    // error: cannot convert 1 to function ptr
                  f(g);    // OK
          }
  For another example,
          class C { };
          void h(int *(C[10]));  // void h(int *(*_fp)(C _parm[10]));
                                 // not: void h(int *C[10]);
   --end example]

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/2/2005 7:47:03 PM
We had a conversation on just this very topic on comp.compilers just
recently (lanugages that are hard to parse).  In it I criticized
exactly one facet of the declaration syntax that I thought would have
been avoided by taking the conflict messages of yacc seriously.
However, Dr Stroustrup pointed out that at the time he was first
implementing C++, it was not known how to parse the current dialect of
C using LR techniques.  Thus, the grammar he began with was simplified
to exclude the parsing problems that were then unsolved.  Doing so
allowed him to introduce new conflicts (that were undetected in his
subset grammar) that are problems to this day, without his being
adequately warned by the tool in question.

Unfortunately, since C++ was broken with respect to LL/LR compilaton
from that early point, (The existence of hand-written recursive
descent compilers, does not imply the ability of the language to be
parsed LL, as hand-written compilers can be written "ad hack" and use
the full (Turing) power of the host programming language.) later
language extenders (i.e. those adding templates) have also falled into
similar traps.  I think it would have been unlikely that a language
designer with a working lexer and LR (or LL) parser for C++
pre-templates, would have added templates in exactly the syntax
proposed.  In particular, they would not have added in the >> problem
for closing templates.

However, this is just my own issue.

As to C++, it is most certainly the PL/I of our times.  And, just like
PL/I there are many usable dialects within it.

0
cfc (239)
6/2/2005 8:04:15 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> | 
> | > Furthermore, as has being pointed out, the "many deficits" of C++
> | > listed here have been made based on misunderstanding of what they are
> | > and where they came from.  Someone insisted on syntax and "typename"
> | > issue without quite understanding that it was a problem inherited from
> | > C, as opposed to a problem introduced by templates.  
> | 
> | The fact that it is inherited from C *is* the problem.  (I don't care
> | "where it came from".  If it is bad, it is bad.)
> | You seem to suggest that something becomes better if we understand why
> | it came to be so bad.  I reject that view.
>
> I did not suggest that, so you may reject view that and that is fine;
> don't say I suggested it.

Then what's the point in reviewing the history of how C++ came to be
the way it is?  I don't care about the history.  I see the result, and
I see that it is bad.

> | > In fact, I've found that working on C++ is more challenging than, say,
> | > working on ML variants or Haskell -- not that those languages do not
> | > provide opportunities for intellectual excitements.
> | 
> | Teaching calculus to dogs is also far more challenging than teaching
> | it to humans.
>
> That is an interesting observation.
>
> |  Should we enroll dogs in math courses, for the
> | challenge's sake?
>
> I think the idea may worth consideration, in particular if someone
> like you were part of the class.  The challengce might not necessarily
> from come where one might think.

Thank you.  Consider the compliment reciprocated.

> [...]
>
> | > Yes, I guess if those people spent their talents on SML/NJ it would
> | > not be waste.
> | 
> | Spending one's efforts on one particular implementation (or even just
> | one particular language) only is probably going to be a waste unless
> | lessons can be learned that "survive".  Lessons from ML will certainly
> | survive.
>
> And of course, lessons from ML will survive but not from C++; and this
> is because you've looked enough into C++ problems to state that.

Lessons from C++ will survive, mostly in the form of "don't make the
following mistake: ...".

> | Did I say even one word about "angle brackets, bananas, curly-braces
> | and dot-notations"?
>
> those are my words for "syntax".

I don't think I said anything about syntax either.

0
find19 (1244)
6/2/2005 8:17:44 PM
Chris F Clark <cfc@shell01.TheWorld.com> writes:

> We had a conversation on just this very topic on comp.compilers just
> recently (lanugages that are hard to parse).

Perl is probably even harder to parse than C++, considering its
lexical structure (the grammar is not that bad).

Some of its rules are not defined by documentation but by code which
looks like this (perl-5.8.5/toke.c):

/* S_intuit_more
 * Returns TRUE if there's more to the expression (e.g., a subscript),
 * FALSE otherwise.
 *
 * It deals with "$foo[3]" and /$foo[3]/ and /$foo[0123456789$]+/
 *
 * ->[ and ->{ return TRUE
 * { and [ outside a pattern are always subscripts, so return TRUE
 * if we're outside a pattern and it's not { or [, then return FALSE
 * if we're in a pattern and the first char is a {
 *   {4,5} (any digits around the comma) returns FALSE
 * if we're in a pattern and the first char is a [
 *   [] returns FALSE
 *   [SOMETHING] has a funky algorithm to decide whether it's a
 *      character class or not.  It has to deal with things like
 *      /$foo[-3]/ and /$foo[$bar]/ as well as /$foo[$\d]+/
 * anything else returns TRUE
 */

/* This is the one truly awful dwimmer necessary to conflate C and sed. */

STATIC int
S_intuit_more(pTHX_ register char *s)
{
    if (PL_lex_brackets)
	return TRUE;
    if (*s == '-' && s[1] == '>' && (s[2] == '[' || s[2] == '{'))
	return TRUE;
    if (*s != '{' && *s != '[')
	return FALSE;
    if (!PL_lex_inpat)
	return TRUE;

    /* In a pattern, so maybe we have {n,m}. */
    if (*s == '{') {
	s++;
	if (!isDIGIT(*s))
	    return TRUE;
	while (isDIGIT(*s))
	    s++;
	if (*s == ',')
	    s++;
	while (isDIGIT(*s))
	    s++;
	if (*s == '}')
	    return FALSE;
	return TRUE;
	
    }

    /* On the other hand, maybe we have a character class */

    s++;
    if (*s == ']' || *s == '^')
	return FALSE;
    else {
        /* this is terrifying, and it works */
	int weight = 2;		/* let's weigh the evidence */
	char seen[256];
	unsigned char un_char = 255, last_un_char;
	char *send = strchr(s,']');
	char tmpbuf[sizeof PL_tokenbuf * 4];

	if (!send)		/* has to be an expression */
	    return TRUE;

	Zero(seen,256,char);
	if (*s == '$')
	    weight -= 3;
	else if (isDIGIT(*s)) {
	    if (s[1] != ']') {
		if (isDIGIT(s[1]) && s[2] == ']')
		    weight -= 10;
	    }
	    else
		weight -= 100;
	}
	for (; s < send; s++) {
	    last_un_char = un_char;
	    un_char = (unsigned char)*s;
	    switch (*s) {
	    case '@':
	    case '&':
	    case '$':
		weight -= seen[un_char] * 10;
		if (isALNUM_lazy_if(s+1,UTF)) {
		    scan_ident(s, send, tmpbuf, sizeof tmpbuf, FALSE);
		    if ((int)strlen(tmpbuf) > 1 && gv_fetchpv(tmpbuf,FALSE, SVt_PV))
			weight -= 100;
		    else
			weight -= 10;
		}
		else if (*s == '$' && s[1] &&
		  strchr("[#!%*<>()-=",s[1])) {
		    if (/*{*/ strchr("])} =",s[2]))
			weight -= 10;
		    else
			weight -= 1;
		}
		break;
	    case '\\':
		un_char = 254;
		if (s[1]) {
		    if (strchr("wds]",s[1]))
			weight += 100;
		    else if (seen['\''] || seen['"'])
			weight += 1;
		    else if (strchr("rnftbxcav",s[1]))
			weight += 40;
		    else if (isDIGIT(s[1])) {
			weight += 40;
			while (s[1] && isDIGIT(s[1]))
			    s++;
		    }
		}
		else
		    weight += 100;
		break;
	    case '-':
		if (s[1] == '\\')
		    weight += 50;
		if (strchr("aA01! ",last_un_char))
		    weight += 30;
		if (strchr("zZ79~",s[1]))
		    weight += 30;
		if (last_un_char == 255 && (isDIGIT(s[1]) || s[1] == '$'))
		    weight -= 5;	/* cope with negative subscript */
		break;
	    default:
		if (!isALNUM(last_un_char) && !strchr("$@&",last_un_char) &&
			isALPHA(*s) && s[1] && isALPHA(s[1])) {
		    char *d = tmpbuf;
		    while (isALPHA(*s))
			*d++ = *s++;
		    *d = '\0';
		    if (keyword(tmpbuf, d - tmpbuf))
			weight -= 150;
		}
		if (un_char == last_un_char + 1)
		    weight += 5;
		weight -= seen[un_char];
		break;
	    }
	    seen[un_char]++;
	}
	if (weight >= 0)	/* probably a character class */
	    return FALSE;
    }

    return TRUE;
}

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/2/2005 9:08:33 PM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > | > Symbol table information is required to distinguish between template
| > | > parameters and less-than operator though. Parsing C++ requires full
| > | > typechecking, including name resolution, overloading resolution,
| > | > template instantiation, and evaluation of constant expressions.
| >
| > Parsing C++ does not require template instantiation, nor overload
| > resolutions, nor full typechecking.
| 
| C++ parser needs to know which names are types, and which names are
| templates. For qualified names like C<T>::name this requires template
| instantiation and matching template specializations.

The premisses are right, but the conclusion is Wrong.  No template
instantiation is required in order to parse template definitions.

Consider the following:

    template<class C> void f(C c) 
    {
       typename C::template rebind<int>::other t;
    }

It basically contains all the ingredients you did not understand.

[ snipping of passage not supporting the claim made ]

[...]

|           template <class T>
|           struct S {
|           T *p;
|           };
|           S<int()> x;             // type-id
|           S<int(1)> y;            // expression (ill-formed)

But, this does not require instantiation of template before parsing.

| 
| 5 For another example,
|           void foo()
|           {
|                   sizeof(int(1)); // expression
|                   sizeof(int());  // type-id (ill-formed)
|           }

This has nothing to do with your claim.

| 6 For another example,
|           void foo()
|           {
|                   (int(1));       // expression
|                   (int())1;       // type-id (ill-formed)
|           }

Neither this.

I appreciate that you went through the trouble of looking at a draft,
but it would been better if the quote actually supported the claim you
made. I gave an example above.  Could you tell me, in your view, which
template should be instantiated before parsing the function definition?

-- Gaby
0
gdr (104)
6/2/2005 11:17:32 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> The premisses are right, but the conclusion is Wrong.  No template
> instantiation is required in order to parse template definitions.

It's required to parse definitions even not occurring in templates, as
long as they don't depend on a template parameter of a template we are in.
From what you have snipped:

3 The disambiguation is purely syntactic; that is, the  meaning  of  the
  names  occurring  in  such  a statement, beyond whether they are type-
  names or not, is not generally used in or changed by  the  disambigua-
  tion.  Class templates are instantiated as necessary to determine if a
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  qualified name is a type-name.  Disambiguation precedes parsing, and a
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  statement disambiguated as a declaration may be an ill-formed declara-
  tion.  If, during parsing, a name in a  template  parameter  is  bound
  differently  than  it would be bound during a trial parse, the program
  is ill-formed.  No diagnostic is required.  [Note: This can occur only
  when the name is declared earlier in the declaration.  ]

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/3/2005 4:52:14 AM
Gabriel Dos Reis wrote:
> 
> I don't know how much of determined distorsion it takes to make
> the above statement, when the author said (page 45):
> 
>    Could I have "fixed" the most annoying deficiencies of the C syntax
>    and semantics at some point before C++ was made pubically
>    available?  Could I have done so without removing useful features
>    (to C with Classes' users in their environments -- as opposed to an
>    idea world) or introducing incompatibilities that were unacceptable
>    to C programmers wanting to migrate to C with Classes?  I think
>    not.  In some cases, I tried, but I backed out my changes after
>    complaints from outraged users.

So? Since when are individual outraged users a suitable criterion for 
judging good language design? Any bit of progress will always outrage 
somebody. C++ probably would have many less "outraged" or annoyed users 
today if he had chosen to wisely ignore such voices at the right times.

Even if he had no choice, as he claims: that he couldn't do better does 
not imply that the result is a good language. You see, I find your line 
of argument really strange. Somebody says "this is bad" and you 
continuously reply "no, because it was designed under that constraint". 
That's a non-sequitur.

> Again, from facts, he did not abandon the YACC parser.

Reread the paragraph, he did. Later ("to this day") he returned to it, 
but only with "much lexical trickery relying on recursive descent 
techniques". That's not good enough, and it was too late by then: some 
of the posts and examples in this thread undoubtedly show that something 
had gone terribly wrong already.

And it's no excuse that there was no working C parser at the time - 
before I start throwing huge piles of extensions at something, I should 
fix the core if that turns out to be necessary - everything else is not 
design but hackery.

I better drop out of this thread now before it gets too heated-up...

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB
0
rossberg (600)
6/3/2005 10:08:18 AM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Gabriel Dos Reis wrote:
| > I don't know how much of determined distorsion it takes to make
| > the above statement, when the author said (page 45):
| >    Could I have "fixed" the most annoying deficiencies of the C
| > syntax
| >    and semantics at some point before C++ was made pubically
| >    available?  Could I have done so without removing useful features
| >    (to C with Classes' users in their environments -- as opposed to an
| >    idea world) or introducing incompatibilities that were unacceptable
| >    to C programmers wanting to migrate to C with Classes?  I think
| >    not.  In some cases, I tried, but I backed out my changes after
| >    complaints from outraged users.
| 
| So?

Just facts. But, you do not seem to like facts, especially those that
would expose the fiction in your claims.  You claimed:

   instead of realizing that the syntax design was broken

and I'm pointing out that, the author did know (at the time) and write
about it several times and explains the reason of why he could not
have done the cleanup he wanted, in the real world of the language
users (as opposed to an imaginary perfect world).

Your reasoning is quite singular.  Each time you make claims that do
not match reality and you're put before facts and realized that, well,
you should really have checked reality before making the claims your made
you just turn to make another false claims.  When you seem to have
exhausted the list of false claims you could make, it is now because
the people you're crediting of fictionary facts were just ignorant.
And this whole discussion started with a distorted report of yours,
and you went on worse and worse.

-- Gaby
0
gdr (104)
6/3/2005 12:39:28 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Andreas Rossberg <rossberg@ps.uni-sb.de> writes:
>
> | Gabriel Dos Reis wrote:
> | > I don't know how much of determined distorsion it takes to make
> | > the above statement, when the author said (page 45):
> | >    Could I have "fixed" the most annoying deficiencies of the C
> | > syntax
> | >    and semantics at some point before C++ was made pubically
> | >    available?  Could I have done so without removing useful features
> | >    (to C with Classes' users in their environments -- as opposed to an
> | >    idea world) or introducing incompatibilities that were unacceptable
> | >    to C programmers wanting to migrate to C with Classes?  I think
> | >    not.  In some cases, I tried, but I backed out my changes after
> | >    complaints from outraged users.
> | 
> | So?
>
> Just facts. But, you do not seem to like facts, especially those that
> would expose the fiction in your claims.  You claimed:
>
>    instead of realizing that the syntax design was broken
>
> and I'm pointing out that, the author did know (at the time) and write
> about it several times and explains the reason of why he could not
> have done the cleanup he wanted, in the real world of the language
> users (as opposed to an imaginary perfect world).

Actually, Stroustrup merely *claims* that he could not have done the
cleanup.  He obviously could have -- at the expense of annoying some
users.  As Andreas said, *any* language change *always* annoys
someone, and it was extremely unwise of Stroustrup to listen to those
particular voices.  I know for a fact that there were other people
around him at the time who hated C++'s design from the beginning.  Why
did he not listen to those people?

> Your reasoning is quite singular.  Each time you make claims that do
> not match reality and you're put before facts and realized that, well,
> you should really have checked reality before making the claims your made
> you just turn to make another false claims.

The fact that he wrote so in his books does not prove that he really
knew the design was bad at the time he did it. Perfect hindsight can
be wonderful thing.  But I don't know what he really knew at the time
either, and it isn't really the point anyway.

So let's suppose he _did_ know that his design was awful back
then...  Isn't that even worse?  Botching something because one does
not know better can at least be excused by ignorance.  Again, those
"outraged users" are *not* an excuse.

>  When you seem to have
> exhausted the list of false claims you could make, it is now because
> the people you're crediting of fictionary facts were just ignorant.

What "list"?  The only claim of Andreas that you seem to be hung up on
is the claim of ignorance on Bjarne's part.  What other "false claims"
did Andreas make according to you?

> And this whole discussion started with a distorted report of yours,
> and you went on worse and worse.

I just looked it up.  The discussion did not start with anything
Andreas did, so here is a distorted fact for you.  And, as far as I
can tell, the first contribution of Andreas to this (already ongoning
thread) was pretty accurate.

Matthias
0
find19 (1244)
6/3/2005 1:01:05 PM
Gabriel Dos Reis wrote:
> 
> Just facts. But, you do not seem to like facts, especially those that
> would expose the fiction in your claims.

Sorry, but I think I have made sufficiently clear why most of the facts 
you brought don't address any of the criticism. Also, I don't readily 
take everything claimed in some book as "fact".

> You claimed:
> 
>    instead of realizing that the syntax design was broken
> 
> and I'm pointing out that, the author did know (at the time) and write
> about it several times and explains the reason of why he could not
> have done the cleanup he wanted, in the real world of the language
> users (as opposed to an imaginary perfect world).

He realized that there was a problem. But obvious "fact" is, that he 
either didn't realize the extent of it, or consciously decided to ignore 
the well-established insight that a language designed with such problems 
is doomed to break (which was my claim regarding syntax design). And 
that C++ syntax broke horribly is also undeniable "fact".

I don't even blame anybody personally. I just conclude from this (and 
all the other problems the language has) that the early C++ gurus' 
expertise in language design was, at least back then, limited.

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB
0
rossberg (600)
6/3/2005 1:13:39 PM
Matthias Blume <find@my.address.elsewhere> writes:

[...]

| > And this whole discussion started with a distorted report of yours,
| > and you went on worse and worse.
| 
| I just looked it up.  The discussion did not start with anything
| Andreas did, so here is a distorted fact for you.  

           That lead to the addition of ad-hoc mechanisms for template
   "export" and explicit instantiation (effectively moving it towards the
   other model), but as of today, they still not solve these problems
   satisfactory, as far as I am aware of it.

and see the answer in <m3br6yyz22.fsf@uniton.integrable-solutions.net>.

-- Gaby
0
gdr (104)
6/3/2005 6:01:22 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:

| Gabriel Dos Reis wrote:
| > Just facts. But, you do not seem to like facts, especially those that
| > would expose the fiction in your claims.
| 
| Sorry, but I think I have made sufficiently clear why most of the
| facts you brought don't address any of the criticism. 

You denied evidence, that for sure.  You claimed he did not realize
that the syntax was broken -- but you decided to ignore the fact that
he recognized very early that the syntax he inherited from C was
aproblem and tried to fix it.  You claimed that he ignored everybody's
else adive and abandon YACC -- while what he did was actually go and
ask the experts and took their advices and did not abandon YACC.
You claimed Algol was a grandiose improvment over PL/I -- which causes
a time travel problem.  

The other claim, you constantly made was that you don't like C++. That
is a taste matter, and most certainly that is hardly argued with 
with facts, and I did not do that.  

| Also, I don't  readily take everything claimed in some book as "fact".

I can understand that -- though it looks like,  you don't hesitate to
argue with "recalling next paragraph" until it is produced and don't
support your claim.

It is not just "some book".  Those involved in C and C++, and those
also hating C++, have had long to verify the report.  That certainly
provide for far better evidence than the claims you've made so far.  

-- Gaby
0
gdr (104)
6/3/2005 6:30:30 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> You claimed Algol was a grandiose improvment over PL/I -- which causes
> a time travel problem.  

So you're quibbling with Hoare here?  After all, this is a fairly
famous quote!

0
find19 (1244)
6/3/2005 6:46:07 PM
Gabriel Dos Reis wrote:
> ...
> Just facts. But, you do not seem to like facts, especially those that
> would expose the fiction in your claims.  You claimed:
> 
>    instead of realizing that the syntax design was broken
> 
> and I'm pointing out that, the author did know (at the time) and write
> about it several times and explains the reason of why he could not
> have done the cleanup he wanted, in the real world of the language
> users (as opposed to an imaginary perfect world).

so if you start with something that is broken, realize it, but decide 
you can't change the brokenness because of some constraints, the result 
is not broken?

> ...

hs
0
hs60 (77)
6/3/2005 11:46:43 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Hartmann Schaffer <hs@hartmann.schaffernet> writes:
>
> | Gabriel Dos Reis wrote:
> | > ...
> | > Just facts. But, you do not seem to like facts, especially those that
> | > would expose the fiction in your claims.  You claimed:
> | >    instead of realizing that the syntax design was broken
> | > and I'm pointing out that, the author did know (at the time) and
> | > write
> | > about it several times and explains the reason of why he could not
> | > have done the cleanup he wanted, in the real world of the language
> | > users (as opposed to an imaginary perfect world).
> | 
> | so if you start with something that is broken, realize it, but decide
> | you can't change the brokenness because of some constraints, the
> | result is not broken?
>
> I don't think "brokenness" is a universal, absolute notion.

I am not interested in any definition of "brokenness" (of programming
languages) according to which C++ is not broken.

The discussion here (especially the one you had with Marcin) was quite
telling.  If even experts have a fight over deciding whether parsing
requires template instantiation (regardless of what the true answer to
this question might be -- I frankly don't care), then something is
very, very wrong.  The excerpts from the draft hat Marcin posted are
absolutely mind-boggling!  It reads like tax law, for crying out loud!
I thought I knew C++ was bad.  But I was actually wrong about this.
The truth is that C++ is an absolute nightmare!

> What some people consider broken -- say Scheme, SML, Haskell, C++ --
> may be considered not broken by others.

All these languages are, indeed, "broken" to some degree.  There are
excellent analyses available.  One of the most thorough ones for the
case of SML was written by your dear friend Andreas Rossberg, btw.
So, now that we have this out of the way, what remains to be
considered is the degree of brokenness.  And C++ stands out in this
regard.

> Furthermore, other people may consider "brokenness" in the context
> of how the thing was made and the constraints.

Some people clearly do that.  However, this approach is, IMNSHO, to be
thoroughly rejected.  If something is broken it is broken.  Period.

> And I believe that for programming languages, the consideration of
> contexts offer better insights into getting a judgment.
> However, I also understand that some people prefer or
> decide to be ignorant of history and the facts.

Nobody should be ignorant of the facts.  However, being ignorant of
certain some "facts" is not really a problem in those cases where
these "facts" have nothing to do with the judgment one is trying to
make.  Nobody needs to know the history of C++ to understand that it
is a disaster.

Historical context is merely helpful in understanding, well, history:
how and why something became as bad as it is.  It does /absolutely/
/nothing/ in terms of changing the verdict.

> To take your question at the other end, so if you start with something
> that is broken, realize it, but decide you can't change *all* the
> brokenness because of some constraints, can the  result still be an
> improvement? 

Maybe, it depends on the concrete situation.  Anyway, it is not clear
that C++ even is one of the cases that fit the above scenario.  It was
Stroustrup's personal opinion that he was bound by those constraints
that he keeps listing in his books.  But there is no proof that that
these contraints existed objectively.  We can't rewind history and see
what would have happened if he had ignored the voices of those who
readily equate PL design decisions with a philosophy that has resulted
in some of the worst crimes of humanity.  (If someone calls a language
design "fascist", I stop listening to that person.)

Fixing the problems inherited from C early on might have resulted in a
language even more popular than the current C++.  It is hard to tell.
Not hard to tell is that doing so wouldn't have resulted in a language
technically superior to the current C++.

Those so-called "improvements" that were made to C++ over the years,
btw., have only compounded the problems.  Ultimately, C++'s problem is
its gratuitous complexity.  And that cannot be cured without
simplifying.  Yet, during the evolution of C++ nothing has been
simplified, and additional complexity has been added.

0
find19 (1244)
6/4/2005 2:25:15 AM
Hartmann Schaffer <hs@hartmann.schaffernet> writes:

| Gabriel Dos Reis wrote:
| > ...
| > Just facts. But, you do not seem to like facts, especially those that
| > would expose the fiction in your claims.  You claimed:
| >    instead of realizing that the syntax design was broken
| > and I'm pointing out that, the author did know (at the time) and
| > write
| > about it several times and explains the reason of why he could not
| > have done the cleanup he wanted, in the real world of the language
| > users (as opposed to an imaginary perfect world).
| 
| so if you start with something that is broken, realize it, but decide
| you can't change the brokenness because of some constraints, the
| result is not broken?

I don't think "brokenness" is a universal, absolute notion.  What
some people consider broken -- say Scheme, SML, Haskell, C++ -- may be
considered not broken by others. Furthermore, other people may
consider "brokenness" in the context of how the thing was made 
and the constraints. And I believe that for programming languages,
the consideration of contexts offer better insights into getting a
judgment.  However, I also understand that some people prefer or
decide to be ignorant of history and the facts.

To take your question at the other end, so if you start with something
that is broken, realize it, but decide you can't change *all* the
brokenness because of some constraints, can the  result still be an
improvement? 

-- Gaby
0
gdr (104)
6/4/2005 2:44:47 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> | > I don't think "brokenness" is a universal, absolute notion.
> | 
> | I am not interested in any definition of "brokenness" (of programming
> | languages) according to which C++ is not broken.
>
> so, you want to take "C++ is broken" as an axiom.  No matter what.
> It is more than religion.

No. Of course, I realize that you are in denial and don't want to
understand, but here it goes anyway:

The point is that I have a certain value system which I use to judge
whether a language design is broken or not.  According to this system,
C++ is (badly) broken.  That's not an axiom, it is an observation.

Now, I realize that other people have different value systems, so they
will make judgments differently.  However, systems that are reasonably
"close" to each other would at least lead to similar conclusions.
Given how low C++ ranks in /my/ system, any /other/ system where it
ranks highly must be /very/ far from mine.  In fact, so far that I
have a hard time conducting a meaningful exchange of opinions on
language design matters with anyone who uses such a radically
different system.

The two of us are currently demonstrating this phenomenon to the
world.

I confess that it is incomprehesible to me how anyone could possibly
think of C++ as a well-designed programming language.

> [...]
>
> | in some of the worst crimes of humanity.  (If someone calls a language
> | design "fascist", I stop listening to that person.)
>
> And which language have you designed?

1. What does that have to do with anything?
2. A few, but certainly not something as "substantial" as C++.
   One example is here:
        http://www.ttic.org/blume/papers/tame-ixp.pdf
   In a strange twist of fate, a substantial portion of this work was
   carried out while I occupied Bjarne's old office at Bell Labs... :-)

Cheers,
Matthias
0
find19 (1244)
6/4/2005 4:35:38 AM
Matthias Blume <find@my.address.elsewhere> writes:

>    One example is here:
>         http://www.ttic.org/blume/papers/tame-ixp.pdf

Oops, there is a hyphen missing.  This should have been:

  http://www.tti-c.org/blume/papers/tame-ixp.pdf

Matthias
0
find19 (1244)
6/4/2005 4:48:01 AM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Hartmann Schaffer <hs@hartmann.schaffernet> writes:
| >
| > | Gabriel Dos Reis wrote:
| > | > ...
| > | > Just facts. But, you do not seem to like facts, especially those that
| > | > would expose the fiction in your claims.  You claimed:
| > | >    instead of realizing that the syntax design was broken
| > | > and I'm pointing out that, the author did know (at the time) and
| > | > write
| > | > about it several times and explains the reason of why he could not
| > | > have done the cleanup he wanted, in the real world of the language
| > | > users (as opposed to an imaginary perfect world).
| > | 
| > | so if you start with something that is broken, realize it, but decide
| > | you can't change the brokenness because of some constraints, the
| > | result is not broken?
| >
| > I don't think "brokenness" is a universal, absolute notion.
| 
| I am not interested in any definition of "brokenness" (of programming
| languages) according to which C++ is not broken.

so, you want to take "C++ is broken" as an axiom.  No matter what.
It is more than religion.

[...]

| in some of the worst crimes of humanity.  (If someone calls a language
| design "fascist", I stop listening to that person.)

And which language have you designed?

-- Gaby
0
gdr (104)
6/4/2005 5:14:40 AM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> | Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
> | 
> | > | > I don't think "brokenness" is a universal, absolute notion.
> | > | 
> | > | I am not interested in any definition of "brokenness" (of programming
> | > | languages) according to which C++ is not broken.
> | >
> | > so, you want to take "C++ is broken" as an axiom.  No matter what.
> | > It is more than religion.
> | 
> | No. Of course, I realize that you are in denial and don't want to
> | understand, but here it goes anyway:
>
> No, you got it wrong.  I understand people can have strong opinions.
> In your case, it goes beyond that.  You have taken something to be an
> axiom.  That is not me being in denial.  

If you say so...  (How come you can read my mind?)

> [...]
>
> |                                             In fact, so far that I
> | have a hard time conducting a meaningful exchange of opinions on
> | language design matters with anyone who uses such a radically
> | different system.
>
> You never pose and ask yourself whether your system is broken, if I
> may borrow words from you?

I do.  Of course, my system is based on my experience.  I have
programmed in many languages, I have implemented several languages, I
have designed some languages.  I think this has given me some
background in judging language designs.

Of course, there is a small probability that I am totally off base,
and that C++ is the design to end all design.  But this seems somewhat
unlikely.  My views on what is good design has changed many times over
the years, but as far as C++ is concerned, the trend was a simple one:
the more experience I gained, the less I could stand it.

> [...]
>
> | > | in some of the worst crimes of humanity.  (If someone calls a language
> | > | design "fascist", I stop listening to that person.)
> | >
> | > And which language have you designed?
> | 
> | 1. What does that have to do with anything?
>
> When someone has such interesting opinions as you offer here about what a
> programming language, its design and relation to users should be, I say
> "woaw, that is interesting!

So you had never heard this before from others?!?  Now it's upon me to
say "whoa!"

>  Is this pure theology or is there any
> thing concrete I can look at to see how he does things himself and
> what they look like?". But, I was not expecting you to react that way
> (or more precisely I guessed, but I thought you were too smart to go
> that way). 

Sorry, but you are being too cryptic for me here.  What are you trying
to say?

> |    One example is here:
> |         http://www.ttic.org/blume/papers/tame-ixp.pdf
>
> Maybe, I should have mentioned I already knew about that one and
> others you published about.

Good.  Then why did you ask?

> In case you're wondering, the question was not facetious.  I thought
> you made something I missed, that obviously demonstrate how things
> should be in your system and I wanted to see  what impact they have on
> the rest of computer science and the world. Those were genuine interests.

Why do /I/ have to make something that demonstrates how things should
be in my opinion?  There are perfectly good language designs out there
which come close enough.  In fact, few languages fare worse than C++
in "my system".  (And no, that's not because "C++ is bad" is an axiom.)

> (And very recently, when someone from your "previous" team came to visit
> us, I naturally took news about your recent work :-))

Again, you are being too vague.  Which recent work are you referring
to exactly?  What "previous" team are you talking about?

> |    In a strange twist of fate, a substantial portion of this work was
> |    carried out while I occupied Bjarne's old office at Bell Labs... :-)
>
> As they say in French, � L'habit ne fait pas le moine. �  (I hope
> someone will translate.)

Yeah, I was relying on this sort of wisdom when I trusted that nothing
would rub off. :-)

0
find19 (1244)
6/4/2005 5:35:54 AM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > | > I don't think "brokenness" is a universal, absolute notion.
| > | 
| > | I am not interested in any definition of "brokenness" (of programming
| > | languages) according to which C++ is not broken.
| >
| > so, you want to take "C++ is broken" as an axiom.  No matter what.
| > It is more than religion.
| 
| No. Of course, I realize that you are in denial and don't want to
| understand, but here it goes anyway:

No, you got it wrong.  I understand people can have strong opinions.
In your case, it goes beyond that.  You have taken something to be an
axiom.  That is not me being in denial.  

[...]

|                                             In fact, so far that I
| have a hard time conducting a meaningful exchange of opinions on
| language design matters with anyone who uses such a radically
| different system.

You never pose and ask yourself whether your system is broken, if I
may borrow words from you?

[...]

| > | in some of the worst crimes of humanity.  (If someone calls a language
| > | design "fascist", I stop listening to that person.)
| >
| > And which language have you designed?
| 
| 1. What does that have to do with anything?

When someone has such interesting opinions as you offer here about what a
programming language, its design and relation to users should be, I say
"woaw, that is interesting!  Is this pure theology or is there any
thing concrete I can look at to see how he does things himself and
what they look like?".  But, I was not expecting you to react that way
(or more precisely I guessed, but I thought you were too smart to go
that way). 

| 2. A few, but certainly not something as "substantial" as C++.

Ah, I see.

|    One example is here:
|         http://www.ttic.org/blume/papers/tame-ixp.pdf

Maybe, I should have mentioned I already knew about that one and
others you published about.  

In case you're wondering, the question was not facetious.  I thought
you made something I missed, that obviously demonstrate how things
should be in your system and I wanted to see  what impact they have on
the rest of computer science and the world. Those were genuine interests.
(And very recently, when someone from your "previous" team came to visit
us, I naturally took news about your recent work :-))

|    In a strange twist of fate, a substantial portion of this work was
|    carried out while I occupied Bjarne's old office at Bell Labs... :-)

As they say in French, � L'habit ne fait pas le moine. �  (I hope
someone will translate.)

-- Gaby
0
gdr (104)
6/4/2005 6:13:50 AM
* Gabriel Dos Reis:

> The premisses are right, but the conclusion is Wrong.  No template
> instantiation is required in order to parse template definitions.
>
> Consider the following:
>
>     template<class C> void f(C c) 
>     {
>        typename C::template rebind<int>::other t;
>     }
>
> It basically contains all the ingredients you did not understand.

I think he isn't after template definitions, but non-template code
which instantiated templates.  No typename/template annotations are
required in this case, so the compiler must in fact instantiate the
template before it can make a decision.
0
fw12 (438)
6/4/2005 8:37:20 AM
Florian Weimer <fw@deneb.enyo.de> writes:

> I think he isn't after template definitions, but non-template code
> which instantiated templates.  No typename/template annotations are
> required in this case,

Actually they are forbidden outside templates.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/4/2005 9:33:16 AM
Matthias Blume <find@my.address.elsewhere> writes:

[...]

| > |                                             In fact, so far that I
| > | have a hard time conducting a meaningful exchange of opinions on
| > | language design matters with anyone who uses such a radically
| > | different system.
| >
| > You never pose and ask yourself whether your system is broken, if I
| > may borrow words from you?
| 
| I do.  Of course, my system is based on my experience.  I have
| programmed in many languages, I have implemented several languages, I
| have designed some languages. 

The point was not whether you designed some languages.  But whether
you designed a language that had sufficient impact on computer science
and the world, and how your system worked out when confronted with the
reality of the word (as opposed to an abstract one).  I'm merely
trying to differentiate claims from someone who would have designed toy
languages that have little impact, from someone who would actually
have done something substantial.  Say differently, I'm trying to 
differentiate arm-chair designers from real practitioners.

| I think this has given me some
| background in judging language designs.
| 
| Of course, there is a small probability that I am totally off base,
| and that C++ is the design to end all design.

You missed the point, because that was not the claim.

[...]

| > | > | in some of the worst crimes of humanity.  (If someone calls a language
| > | > | design "fascist", I stop listening to that person.)
| > | >
| > | > And which language have you designed?
| > | 
| > | 1. What does that have to do with anything?
| >
| > When someone has such interesting opinions as you offer here about what a
| > programming language, its design and relation to users should be, I say
| > "woaw, that is interesting!
| 
| So you had never heard this before from others?!?

Sure I did and do from time to time.  But then, I always try to see
whether their authors are simply arrogant, or arm-chair designers, or
real practitioners.  

| Now it's upon me to  say "whoa!"
| 
| >  Is this pure theology or is there any
| > thing concrete I can look at to see how he does things himself and
| > what they look like?". But, I was not expecting you to react that way
| > (or more precisely I guessed, but I thought you were too smart to go
| > that way). 
| 
| Sorry, but you are being too cryptic for me here.  What are you trying
| to say?
| 
| > |    One example is here:
| > |         http://www.ttic.org/blume/papers/tame-ixp.pdf
| >
| > Maybe, I should have mentioned I already knew about that one and
| > others you published about.
| 
| Good.  Then why did you ask?

the answer was in the sentences that followed.

| > In case you're wondering, the question was not facetious.  I thought
| > you made something I missed, that obviously demonstrate how things
| > should be in your system and I wanted to see  what impact they have on
| > the rest of computer science and the world. Those were genuine interests.
| 
| Why do /I/ have to make something that demonstrates how things should
| be in my opinion?

I was not asking you to make something that dmonstrates how things
should be in your opinion.  I was asking whether you had something I
could look at that shows how things should be in your system.  The
answer could have been "yes".  That was fine.  The answer could have
been "no".  That was fine too.  In either case, I'd have had a
material to answer my question "is this theology, or is this something
that got confrontation with the reality?"  See?

-- Gaby
0
gdr (104)
6/4/2005 2:11:54 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Matthias Blume <find@my.address.elsewhere> writes:
>
> [...]
>
> | > |                                             In fact, so far that I
> | > | have a hard time conducting a meaningful exchange of opinions on
> | > | language design matters with anyone who uses such a radically
> | > | different system.
> | >
> | > You never pose and ask yourself whether your system is broken, if I
> | > may borrow words from you?
> | 
> | I do.  Of course, my system is based on my experience.  I have
> | programmed in many languages, I have implemented several languages, I
> | have designed some languages. 
>
> The point was not whether you designed some languages.  But whether
> you designed a language that had sufficient impact on computer science
> and the world, and how your system worked out when confronted with the
> reality of the word (as opposed to an abstract one).

Obviously you knew the answer to this one.  If I had, you would
certainly have heard of it, hadn't you?  So don't try to sound sincere
when you are not, ok?

> I'm merely trying to differentiate claims from someone who would
> have designed toy languages that have little impact, from someone
> who would actually have done something substantial.

Well, at least I have not done substantial damage either.  As I said,
one day people will look back and marvel at how much damage C++ has
caused the (computing) world.

> Say differently, I'm trying to differentiate arm-chair designers
> from real practitioners.

Well, guilty as charged.  Now, let me ask you:  What languages have
/you/ designed?

> Sure I did and do from time to time.  But then, I always try to see
> whether their authors are simply arrogant, or arm-chair designers, or
> real practitioners.

But even when they are arrogant and/or armchair designers, they might
just be right.  And "real practitioners" can be wrong, even while
temporarily looking successful.  C++ impressively demonstrates this.

> I was not asking you to make something that dmonstrates how things
> should be in your opinion.  I was asking whether you had something I
> could look at that shows how things should be in your system.  The
> answer could have been "yes".  That was fine.  The answer could have
> been "no".  That was fine too.  In either case, I'd have had a
> material to answer my question "is this theology, or is this something
> that got confrontation with the reality?"  See?

You can go around and call this "theology" or "axiom" or whatever.  I
don't care.  I have nothing at stake depends in any way on C++ one way
or the other.  I don't use this language, I rarely think about it, I
don't have to work with it or on it, I don't have to prove that it is
bad, I don't have to try and improve it.  To have an axiom
specifically naming C++, or to have a "theology" that talks about C++
would make no sense at all for me.  It just so happens that my
experience with languages have shaped my value system, and as it so
happens, C++ does not look very good in this system.

Matthias
0
find19 (1244)
6/4/2005 3:38:36 PM
Gabriel Dos Reis wrote:

> Hartmann Schaffer <hs@hartmann.schaffernet> writes:
> 
> | Gabriel Dos Reis wrote:
> | > ...
> | > Just facts. But, you do not seem to like facts, especially those that
> | > would expose the fiction in your claims.  You claimed:
> | >    instead of realizing that the syntax design was broken
> | > and I'm pointing out that, the author did know (at the time) and
> | > write
> | > about it several times and explains the reason of why he could not
> | > have done the cleanup he wanted, in the real world of the language
> | > users (as opposed to an imaginary perfect world).
> | 
> | so if you start with something that is broken, realize it, but decide
> | you can't change the brokenness because of some constraints, the
> | result is not broken?
> 
> I don't think "brokenness" is a universal, absolute notion.  What
> some people consider broken -- say Scheme, SML, Haskell, C++ -- may be
> considered not broken by others.

That doesn't make either of them right.

Besides, C++ *is* broken.

It's broken in theory: parsing is a mess, its semantics is riddled with 
exceptions and special cases. I already gave constructor issues in a 
recent post, and that's just the start.

It's broken according to broad consensus. It's even a common saying that 
"C++ gives you not enough rope to hang yourself, but a pistol to shoot 
nice large holes through your foot".

It's broken according to personal experience. I have done similar 
projects in C++ and in other languages, and C++ required me to write 
down details that would be handled automatically in other languages 
(hence more LoC, more time to write it, more bugs), it took me more time 
to look up semantic details to get the code express what I wanted it to 
express, it layed traps for me that cost me hours of debugging.

By all definitions, C++ is broken. That anybody can allude that C++ may 
be considered nonbroken by some people makes me seriously doubt that 
person's sanity.

 > Furthermore, other people may
> consider "brokenness" in the context of how the thing was made 
> and the constraints.

It may be that C++ was the least broken thing that could be done under 
the circumstances. I seriously doubt that, but it's entirely possible.

Still, this doesn't make C++ non-broken.

 > And I believe that for programming languages,
> the consideration of contexts offer better insights into getting a
> judgment.

Judgment on Bjarne Stroustrup's language design skills is what you've 
been highlighting. I'm under the impression that most people here think 
that that's largely irrelevant - what we think about is the merit of the 
language itself (and C++ is quite unanimously considered breakage here, 
else we'd be populating comp.lang.c++ instead of comp.lang.functional).

 > However, I also understand that some people prefer or
> decide to be ignorant of history and the facts.

Please, allegations don't belong into a technical discussion.

> To take your question at the other end, so if you start with something
> that is broken, realize it, but decide you can't change *all* the
> brokenness because of some constraints, can the  result still be an
> improvement? 

It's certainly possible to improve something bad into something 
not-quite-so-bad. The question is whether the end result is good enough. 
The consensus here is that changing C++ into even a reasonable language 
would require so deep alterations that the result wouldn't be C++ 
anymore, and would be rejected for that reason. It's like polishing a 
blind corner of a broken mirror - the shard certainly has improved, but 
there's no way that the mirror will ever become whole again, regardless 
of the skill that went into the polish.

Regards,
Jo
0
jo427 (1164)
6/4/2005 5:05:05 PM
* Joachim Durchholz:

> It's broken in theory: parsing is a mess, its semantics is riddled with 
> exceptions and special cases. I already gave constructor issues in a 
> recent post, and that's just the start.

I was bitten by that one, too, but if you think about it, it's a
direct consequence of having true constructors and destructors.  If
you always invoke the member functions in the most derived class,
you'd have partially constructed or destructed flying around, which
would be a real nightmare.

There are a few features I consider truly broken.  For example, it's
not quite clear if you can portably allocate an array whose size is
determined at run time.  Some choices in the syntax department turned
out to be unfortunate, but this mostly concerns implementors and not
programmers.

> It's broken according to broad consensus. It's even a common saying that 
> "C++ gives you not enough rope to hang yourself, but a pistol to shoot 
> nice large holes through your foot".

By this definition, most (all?) successful technology is broken.

> It's broken according to personal experience. I have done similar 
> projects in C++ and in other languages, and C++ required me to write 
> down details that would be handled automatically in other languages 
> (hence more LoC, more time to write it, more bugs), it took me more time 
> to look up semantic details to get the code express what I wanted it to 
> express, it layed traps for me that cost me hours of debugging.

Usually, you are less productive when you use tools which you hate.

> By all definitions, C++ is broken. That anybody can allude that C++ may 
> be considered nonbroken by some people makes me seriously doubt that 
> person's sanity.

At least C++ fits reasonably well with the traditional and current
UNIX development model (separate compilation, processes are often
short-lived).  There's an unfortunate mismatch in the area of I/O, but
this is probably also a quality-of-implementation issue 
(sorry Gaby 8->).
0
fw12 (438)
6/4/2005 5:46:14 PM
Joachim Durchholz <jo@durchholz.org> writes:

> Robert A Duff wrote:
> 
> > Joachim Durchholz <jo@durchholz.org> writes:
> >> * Eiffel requires garbage collection. [...] If I were to do HRT
> >> programming, I'd not use dynamic memory allocation anyway - so
>  >> neither C++ nor Eiffel fit the bill :-)
> > I'm not sure why you say that.  C++ can be used without dynamic
> > allocation pretty easily.   I suppose Eiffel could, too, but it's
> > perhaps more painful (declare everything "expanded"?).
> 
> Well, you could, but "expanded" means you don't have polymorphism.

Yeah, that's what I meant by "painful".  Eiffel really wants everything
to be in the heap; the rules for "expanded" seem kind of weird to me,
and appear to be tacked on after the fact (in fact, I believe "expanded"
was not in the original version of Eiffel).  Eiffel is a pretty nice
language design, but it wouldn't be my first choice for hard real time.

>... In
> other words, all the OO stuff goes out of the window, and you could just
> as well program in Ada or Modula or whatever.

Ada is a fully OO language.  It does not require heap usage in order to
get run-time polymorphism, although there are many OO-style applications
that will want to use the heap for various reasons.  Ada *is* used for
HRT programs -- that's what it (Ada 83) was originally design for.  Ada
95 added the OO features.  Many HRT applications do not use heap at all,
and many do not use run-time polymorphism, either -- but you can have
one without the other.

> I'd expect similar problems with C++ if dynamic memory allocation is
> disallowed, but I'm not familiar enough with that scenario to tell for
> sure.

I believe C++ is similar to Ada in this regard.

Neither C++ nor Ada have garbage collection, by the way, although either
can be used with Boehm's conservative GC.  Also, Ada implementations
targetting the JVM or .NET have GC, because the underlying platform
does.

- Bob
0
bobduff (1543)
6/4/2005 5:49:08 PM
Gabriel Dos Reis wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> | Gabriel Dos Reis wrote:
> | 
> | > Joachim Durchholz <jo@durchholz.org> writes:
> | > | Gabriel Dos Reis wrote:
> | > | > But given the constraints, do you have a better solution?
> | > | > (Compiling to tuple of functions does not meet the constraints).
> | > | > We have listed what appear to us to be the most important constraints
> | > | > here:
> | > | > http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1522.pdf
> | > | | Well, if being compatible with C++ is a constraint, then you
> | > pretty
> | > | much have to live with all the problems that C++ templates carry.
> | > Breaking C++ is not a luxury we have, that is a fundamental
> | > constraint.
> | 
> | Well, let me utter a sacrilege... C++ is the PL/I of modern days. It's
> | trying to be everything to everyone, and adding too many ways to do
> 
> Having been involved in C++ design and implementation discussions for
> some time now, what I've figured out is that for many people it is
> not doing enough.  For the next version of C++, the C++ standard
> Evolution Working Group had asked for "wishlist" for improvements from
> the community.  The list we got is quite long and looking over it, it
> appears that clearly C++ was not providing enough for some people.

Oh. So C++ is going to be even more bloated.

I really wish somebody would start to take away things from C++. I know 
that's impossible, but I wish it were. The current language is simply 
far too large, with too many obscure interactions between language 
features. Adding yet another set of features will most likely just 
worsen the problem (and that's what I mean if I call a language "bloated").

> But I've also heard your rant some times.  The reality is that, unless
> you've been close enough (either as implementors leasting to users) or
> designers (listening to users) trying to improve over things, it is
> hard to assess the complexity and the tension between the variety of
> interests.

Been there, done that. It was just a crummy 4GL, and I was more into 
design of the accompagnying libraries than the language itself, but I 
have seen the trade-off nightmares, the guesswork, and general insecurity.

 > Furthermore, if the primary design aim has been to design a
> beautiful language, I'm confident that C++ designers would have done a
> better job.  

I don't care too much about "beauty". I care about learning curves, 
amount of surprise (aka "pitfalls"), compiler reliability, and similar 
things. Languages that fare well in these areas tend to have a quality 
that is often described as "elegance" or "beauty", but it's a 
consequence, not an aim in itself.

> | the same thing, failing to provide some key mechanisms that could
> | replace the existing ones (not that this failure is a fault of its
> | designers: they had to work with the insights that were available at
> | the time of design); with a baroque syntax and semantics that (almost)
> 
> There is an account of C++ design history that I think anybody who
> wants to make serious criticisms about quirks in C++ should read.  In
> particular, it has many discussions about the syntax issues in several
> paragraphs (apart from the main section �2.8 Syntax Problems). 

Well, I have read that part of Bjarne's musings three times now, so 
there's no need to post it again.

That the syntax is baroque is largely a C legacy, and perhaps 
unavoidable. Still, there is gratuitious baroqueness in C++'s syntax, 
easily demonstrated through the observation that there are several 
useful C parsers available now, but _not_a_single_C++_parser_.

However, the syntax problems were just a passing note. They are quite 
bad, but they pale in comparison with C++'s semantic blunders. The 
language implements all the mechanisms of an OO language, but it fails 
to have the accompagnying semantic concepts, so every programmer has to 
manually establish things like LSP, proper virtual function linkague 
during construction, and similar things. (Oh, yeah, it does have a 
semantics during construction: the object under construction starts as 
that of the most basic class and undergoes a set of transformation until 
it arrives at the designated target class. Unfortunately, this semantic 
model is Wrong with a capital W.)

Regards,
Jo
0
jo427 (1164)
6/4/2005 5:50:45 PM
Joachim Durchholz <jo@durchholz.org> writes:

> Robert A Duff wrote:
> 
> > Joachim Durchholz <jo@durchholz.org> writes:
> >
> >>However, I would have found it far better if the language had specified
> >>that no such limits are allowed (except for the obvious "limited by
> >>available memory").
> > I agree with you that compilers should not have such arbitrary limits,
> > other than those based on "available memory".  But I don't see how a
> > language standard can say so.  How can you write a test case that
> > determines whether the compiler obeys such a rule?
> 
> Simple enough. Write a test suite that doubles any limit in
> question. Observe the compiler's memory footprint. If the memory
> footprint nears available memory, without the compiler complaining, it
> passes.
> 
> Of course, a devious compiler writer could get away with arbitrary
> limits, either by providing large-enough tables or by arbitrarily
> allocating unneeded memory :-)
> ... but then I don't think anybody would do that :-))

But now you're not talking about formal requirements in a language
standard, but practical matters.  Looking at memory footprints is not a
fair test, in any formal sense.

> >>>> I'm quite puzzled why C++ has such a long list of limited
> >>>> resources.
> >>>Maybe it is because you haven't seen that of C :-). See below.
> >>>(I hope they are not problem for functional programming language
> >>>implementations that generate C codes ;-))
> >>
> >>Contrary to popular belief, C is not a good portable assembler. The
> >>standard strategy for compiling FPLs nowadays seems to be machine code
> >>generation.
> > Well, C isn't *so* bad.  Problems include:  Lack of overflow detection.
> > No access to hardware operations like (single X single)-->double
> > integer multiply instructions.  No portable and efficient way to
> > implement exception handling.  Etc.
> 
> No tail-call optimisation.

Good point.  This is indeed a bigger issue than the ones I mentioned.

>... This is the first barrier that FPL compiler
> writers hit (exceptions and some issues with closure construction and
> other exoticities come next, but many implementors have already given up
> on C before reaching that point).

- Bob
0
bobduff (1543)
6/4/2005 5:57:31 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Notice that some compilers set internal characteristics, passes or
> resource limits, depending on the avaliable memory.  

I'd advise compiler writers not to do that.  It can cause subtle bugs
that happen to the compiler users, but can't be reproduced by the
compiler writers, which is a nightmare.

If such feature is necessary, let the user control it with command-line
switches, rather than having the compiler query the OS ("how much memory
can I have right now?).

- Bob
0
bobduff (1543)
6/4/2005 6:00:23 PM
* Joachim Durchholz:

> (Oh, yeah, it does have a 
> semantics during construction: the object under construction starts as 
> that of the most basic class and undergoes a set of transformation until 
> it arrives at the designated target class. Unfortunately, this semantic 
> model is Wrong with a capital W.)

What do you propose as an alternative?  Partially constructed objects?
0
fw12 (438)
6/4/2005 6:05:26 PM
* Robert A. Duff:

> Neither C++ nor Ada have garbage collection, by the way, although either
> can be used with Boehm's conservative GC.  Also, Ada implementations
> targetting the JVM or .NET have GC, because the underlying platform
> does.

But not for objects with user-defined finalization, those are never
garbage-collected.  (I'm not sure what JGNAT does, but after looking
at the GC-aware parts of GNAT, I think it doesn't implement the
language semantics properly.)
0
fw12 (438)
6/4/2005 6:10:41 PM
Florian Weimer wrote:

> * Joachim Durchholz:
> 
>>It's broken in theory: parsing is a mess, its semantics is riddled with 
>>exceptions and special cases. I already gave constructor issues in a 
>>recent post, and that's just the start.
> 
> I was bitten by that one, too, but if you think about it, it's a
> direct consequence of having true constructors and destructors.  If
> you always invoke the member functions in the most derived class,
> you'd have partially constructed or destructed flying around, which
> would be a real nightmare.

No, not at all.

I'm speaking from my Eiffel experience here. Eiffel's policy is: a 
function is always virtual (there are exceptions). Constructors are 
otherwise normal functions, and they start with an object that's 
initialized to all zeros. I have written dozens if not hundreds of 
classes in Eiffel, and partially constructed objects have _not_once_ 
been an issue.

I don't know why exactly that's not a problem. One of the patterns that 
I observed in an Eiffel program is that the more complex classes with 
multiple constructors tend to have a protected "basic constructor" that 
establishes the class invariant and little more, and the published 
constructors first call that basic constructor, then do their thing to 
honor their more specific parameters.

Anyway. It's not really a problem. Those complicated initialisation 
rules for C++ are dealing with a problem that simply doesn't exist.

>>It's broken according to broad consensus. It's even a common saying that 
>>"C++ gives you not enough rope to hang yourself, but a pistol to shoot 
>>nice large holes through your foot".
> 
> By this definition, most (all?) successful technology is broken.

(Let me restrict to "programming languages in the mainstream" - 
"technology" is too general here, and "successful" is a somewhat 
imprecise term.)

Lisp. Python.

Admittedly, that list is depressingly short :-(

Of course, all languages have warts, including Lisp and Python. C++ is 
just infinitely worse...

>>It's broken according to personal experience. I have done similar 
>>projects in C++ and in other languages, and C++ required me to write 
>>down details that would be handled automatically in other languages 
>>(hence more LoC, more time to write it, more bugs), it took me more time 
>>to look up semantic details to get the code express what I wanted it to 
>>express, it layed traps for me that cost me hours of debugging.
> 
> Usually, you are less productive when you use tools which you hate.

True.

On the other hand, I didn't go into C++ development with an attitude of 
hate. We had a project to do, and while none of us exactly liked C++, we 
all assumed it would be good enough. Which it actually was, there's no 
mistake about that - but it forced us into some extra twists that we 
would liked to have avoided.

I hadn't had any practical Eiffel experience before that, so my hate 
isn't the typical case of a disgruntled <insert your favorite language 
here> programmer who was forced into C++ - in fact I welcomed the 
opportunity to get hands-on experience with C++.

That experience strengthened my distaste for C++. I had an opportunity 
to go into an Eiffel job and took it. My findings were:
- All those typical problems of C++ programming (memory leaks, exception 
handling issues, diamond inheritance issues, syntactic and semantic 
surprises) simply vanished.
- Despite Eiffel being in the verbose tradition of Pascal Ada, Eiffel 
programs are far shorter than equivalent C++ programs. Part of it is 
that Eiffel has automatic garbage collection (this takes off quite a lot 
of lines of code, and often simplifies the design considerably), part of 
it is that Eiffel generally makes the OO mechanisms "just work" where 
C++ programmers need to write explicit specifications. Also, the Eiffel 
compiler automatically extracts the information that C++ programmers 
must redundantly write into header files.
- Eiffel has its own set of scary problems. However, you have to look 
very carefully to find them, and there are few; contrast that with C++ 
with its blatant and numerous scary problems.

>>By all definitions, C++ is broken. That anybody can allude that C++ may 
>>be considered nonbroken by some people makes me seriously doubt that 
>>person's sanity.
> 
> At least C++ fits reasonably well with the traditional and current
> UNIX development model (separate compilation, processes are often
> short-lived).

OK, Eiffel's compilation model doesn't match that. You can do separate 
compilation, but only if you have a special linker (or are prepared to 
face really bloated binaries).

On the other hand, C++ templates are more difficult to compile 
separately than generic classes in Eiffel, so I don't see that C++ has 
any real advantage here.

Regards,
Jo
0
jo427 (1164)
6/4/2005 8:20:08 PM
Florian Weimer wrote:

> * Joachim Durchholz:
> 
> 
>> (Oh, yeah, it does have a semantics during construction: the object
>> under construction starts as that of the most basic class and
>> undergoes a set of transformation until it arrives at the
>> designated target class. Unfortunately, this semantic model is
>> Wrong with a capital W.)
> 
> What do you propose as an alternative?  Partially constructed
> objects?

Let the object be created as a member of its target class. The
constructor is obliged to fill it with data that fulfills the class's
invariant. In particular, it's obliged to fill in enough data before
calling functions that depend on that data - but that's normal with any
kind of step-by-step initialisation.

Besides, initialisation is rarely a serious problem. Objects tend to be
in a well-known state at that time, so there aren't many cases to code
and debug for.

Regards,
Jo
0
jo427 (1164)
6/4/2005 8:28:36 PM
Robert A Duff wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
>>Robert A Duff wrote:
>>
>>>[...] C++ can be used without dynamic
>>>allocation pretty easily.   I suppose Eiffel could, too, but it's
>>>perhaps more painful (declare everything "expanded"?).
>>
>>Well, you could, but "expanded" means you don't have polymorphism.
> 
> Yeah, that's what I meant by "painful".  Eiffel really wants everything
> to be in the heap; the rules for "expanded" seem kind of weird to me,
> and appear to be tacked on after the fact (in fact, I believe "expanded"
> was not in the original version of Eiffel).

That's indeed the case.

The semantics is also dodgy. Assinging from an expanded object will 
always copy it (even if it's submission as a parameter to a subroutine). 
The net effect is that expanded objects are virtually useless.

The motivation behind that move was to avoid having pointers that refer 
to the innards of an object (this would have broken the garbage 
collector of the language inventor's implementation), so here we have 
another classical case of a language that acquired design problems 
because of implementation consideration.

Note that the garbage collection problems could have been solved in an 
instand by simply adopting the existing, open-source Boehm-Demers-Weiser 
collector (that implementation compiled to C anyway, so it would have 
been a perfect match).

 > Eiffel is a pretty nice language design,

Um, well, Eiffel has some extremely good design decisions. It also has 
some incredibly bad ones.

It would be easy to design a "better Eiffel". Just reverse some of the 
more recent design decisions :-)
(Implementing it would be another story. I actually started work on such 
a project, but found it would be more work than I liked, and I also 
found that some problems in statically-typed OO were essentially 
unsolvable anyway - that's why I'm here in comp.lang.functional.)

 > but it wouldn't be my first choice for hard real time.

Nor mine :-)

Regards,
Jo
0
jo427 (1164)
6/4/2005 8:46:17 PM
Matthias Blume <find@my.address.elsewhere> writes:

| Gabriel Dos Reis <gdr@integrable-solutions.net> writes:
| 
| > Matthias Blume <find@my.address.elsewhere> writes:
| >
| > [...]
| >
| > | > |                                             In fact, so far that I
| > | > | have a hard time conducting a meaningful exchange of opinions on
| > | > | language design matters with anyone who uses such a radically
| > | > | different system.
| > | >
| > | > You never pose and ask yourself whether your system is broken, if I
| > | > may borrow words from you?
| > | 
| > | I do.  Of course, my system is based on my experience.  I have
| > | programmed in many languages, I have implemented several languages, I
| > | have designed some languages. 
| >
| > The point was not whether you designed some languages.  But whether
| > you designed a language that had sufficient impact on computer science
| > and the world, and how your system worked out when confronted with the
| > reality of the word (as opposed to an abstract one).
| 
| Obviously you knew the answer to this one. 

No, I did not.  As I said, I thought I missed something you've done of
that scale.  Which is why I asked.  Whether you take it not sincere is
up to you. 

[...]

| > Say differently, I'm trying to differentiate arm-chair designers
| > from real practitioners.
| 
| Well, guilty as charged.  Now, let me ask you:  What languages have
| /you/ designed?

None.  I'm just working on some those, trying to make improvements.
But then, I refrain from making the sorts of arrogants claims I've
seen here because the real world is just damned complex and theology
and lessons from arm-chair designers just do not cut it.

| > Sure I did and do from time to time.  But then, I always try to see
| > whether their authors are simply arrogant, or arm-chair designers, or
| > real practitioners.
| 
| But even when they are arrogant and/or armchair designers, they might
| just be right.

They might.  Still, it takes evidence for that.  And in your case, I'm
looking for that.  But don't bother.

-- Gaby
0
gdr (104)
6/4/2005 8:51:12 PM
Florian Weimer wrote:
> * Joachim Durchholz:
> 
>>It's broken in theory: parsing is a mess, its semantics is riddled with 
>>exceptions and special cases. I already gave constructor issues in a 
>>recent post, and that's just the start.
> 
> I was bitten by that one, too, but if you think about it, it's a
> direct consequence of having true constructors and destructors.  If
> you always invoke the member functions in the most derived class,
> you'd have partially constructed or destructed flying around, which
> would be a real nightmare.

It would be quite possible for a language to statically reject programs
in which references to partially constructed objects could escape their
constructor. Partially destructed objects would not be an issue in a
language that used safe memory management (GC or region-based) and
post-mortem finalization.

--
David Hopwood <david.nospam.hopwood@blueyonder.co.uk>
0
6/4/2005 8:57:02 PM
Gabriel Dos Reis <gdr@integrable-solutions.net> writes:

> Most people in this discussion seem to have posited axioms and are
> very firm on not examining things.  

That seems to include yourself as one prime example.  On the other
hand, I think I actually have examined quite a few things.  Do you
really think that there is anything out there that
   a) I have not yet examined, and
   b) once I examine it, it would make me think of C++ highly?

> |  > However, I also understand that some people prefer or
> | > decide to be ignorant of history and the facts.
> | 
> | Please, allegations don't belong into a technical discussion.
>  
> Well: that comes directly from one of Matthias' message.

No, it does not.  I have explicitly said that one should /not/ be
ignorant of facts, although being ignorant of facts that have nothing
to do with the topic at hand will not harm the conversation on that
particular topic.  I also said that history has nothing to do with the
topic of how C++ is broken.  That does not mean that I prefer or
decide to be ignorant of it, but if I am, it won't harm my judgment.
History does not excuse bad design.

> | It's certainly possible to improve something bad into something
> | not-quite-so-bad. The question is whether the end result is good
> | enough.
>
> At least *you* seem to understand my question, as opposed to some
> people here.

Again those unfounded allegations.  I said quite exlicitly that one
can make bad things better.  I just happen to think that what is
/actually/ been done in an attempt to make C++ better actually makes
it worse.

To refresh your memory: I said that the main problem of C++ is its
complexity, and adding more complexity ("concepts" anyone?) does not
only not solve this problem, it makes the problem worse.

> | The consensus here is that changing C++ into even a reasonable
> | language would require so deep alterations that the result wouldn't be
> | C++ anymore, and would be rejected for that reason.
>
> I think there is something that has been missed here.  There are at
> least two ways of making improvement: (1) radical changes, (2) extend
> the language with functionalities that provide for better
> alternatives, thus making making the broken part largely
> secondary. 

See, and that is /precisely/ the error you are making.  Adding stuff
to a language that suffers from having too much stuff already will
*never* make that problem go away.  You seem to think that one can add
enough "goodness" to C++, thereby marginalizing the existing "badness"
so it won't matter anymore.  But that is nothing more than wishful
thinking.

Matthias
0
find19 (1244)
6/4/2005 10:10:58 PM
Joachim Durchholz <jo@durchholz.org> writes:

| Gabriel Dos Reis wrote:
| 
| > Hartmann Schaffer <hs@hartmann.schaffernet> writes:
| > | Gabriel Dos Reis wrote:
| > | > ...
| > | > Just facts. But, you do not seem to like facts, especially those that
| > | > would expose the fiction in your claims.  You claimed:
| > | >    instead of realizing that the syntax design was broken
| > | > and I'm pointing out that, the author did know (at the time) and
| > | > write
| > | > about it several times and explains the reason of why he could not
| > | > have done the cleanup he wanted, in the real world of the language
| > | > users (as opposed to an imaginary perfect world).
| > | | so if you start with something that is broken, realize it, but
| > decide
| > | you can't change the brokenness because of some constraints, the
| > | result is not broken?
| > I don't think "brokenness" is a universal, absolute notion.  What
| > some people consider broken -- say Scheme, SML, Haskell, C++ -- may be
| > considered not broken by others.
| 
| That doesn't make either of them right.

But that wasn't the point.

| Besides, C++ *is* broken.
| 
| It's broken in theory: parsing is a mess, its semantics is riddled
| with exceptions and special cases. I already gave constructor issues
| in a recent post, and that's just the start.
| 
| It's broken according to broad consensus. It's even a common saying
| that "C++ gives you not enough rope to hang yourself, but a pistol to
| shoot nice large holes through your foot".

I think you can find something close to the origin of that "common
saying" here:

  http://www.research.att.com/~bs/bs_faq.html#really-say-that

  Did you really say that?

  "C makes it easy to shoot yourself in the foot; C++ makes it harder,
  but when you do it blows your whole leg off." Yes, I said something
  like that. What people tend to miss, is that what I said there about
  C++ is to a varying extent true for all powerful languages. As you
  protect people from simple dangers, they get themselves into new and
  less obvious problems. Someone who avoids the simple problems may
  simply be heading for a not-so-simple one. One problem with very
  supporting and protective environments is that the hard problems may
  be discovered too late or be too hard to remedy once discovered. Also,
  a rare problem is harder to find than a frequent one because you don't
  suspect it.

  "Within C++, there is a much smaller and cleaner language struggling
  to get out." Yes, that quote can be found on page 207 of The Design
  and Evolution of C++. And no, that smaller and cleaner language is not
  Java or C#. The quote occurs in a section entitled "Beyond Files and
  Syntax". I was pointing out that the C++ semantics is much cleaner
  than its syntax. I was thinking of programming styles, libraries and
  programming environments that emphasized the cleaner and more
  effective practices over archaic uses focussed on the low-level
  aspects of C.

  "I have always wished for my computer to be as easy to use as my
  telephone; my wish has come true because I can no longer figure out
  how to use my telephone" I said that after a frustrating attempt to
  use a "feature-rich" telephone sometime around 1990. I'm sure the
  sentiment wasn't original, and probably not even the overall phrasing;
  someone must have thought of that before me.

  "There are only two kinds of languages: the ones people complain about
  and the ones nobody uses". Again, I very much doubt that the sentiment
  is original. Of course, all "there are only two" quotes have to be
  taken with a grain o salt.

  "Proof by analogy is fraud". Page 692 of TC++PL. A good analogy is an
  excellent way of illustrating an idea, but far too often such
  analogies are not accompanied by solid reasoning, data, etc. 

| It's broken according to personal experience. I have done similar
| projects in C++ and in other languages, and C++ required me to write
| down details that would be handled automatically in other languages
| (hence more LoC, more time to write it, more bugs), it took me more
| time to look up semantic details to get the code express what I wanted
| it to express, it layed traps for me that cost me hours of debugging.
| 
| By all definitions, C++ is broken. That anybody can allude that C++
| may be considered nonbroken by some people makes me seriously doubt
| that person's sanity.
| 
|  > Furthermore, other people may
| > consider "brokenness" in the context of how the thing was made and
| > the constraints.
| 
| It may be that C++ was the least broken thing that could be done under
| the circumstances. I seriously doubt that, but it's entirely possible.
| 
| Still, this doesn't make C++ non-broken.
| 
|  > And I believe that for programming languages,
| > the consideration of contexts offer better insights into getting a
| > judgment.
| 
| Judgment on Bjarne Stroustrup's language design skills is what you've
| been highlighting.

Then you missed the whole point.  I've been trying to see how

| I'm under the impression that most people here
| think that that's largely irrelevant 

Most people in this discussion seem to have posited axioms and are
very firm on not examining things.  

| - what we think about is the
| merit of the language itself (and C++ is quite unanimously considered
| breakage here, else we'd be populating comp.lang.c++ instead of
| comp.lang.functional).

I don't read comp.lang.c++, but by no means not just because you're
not populating it means it is broken.  That does not mean I'm claiming
"C++ it nos broken")

|  > However, I also understand that some people prefer or
| > decide to be ignorant of history and the facts.
| 
| Please, allegations don't belong into a technical discussion.
 
Well: that comes directly from one of Matthias' message.  Are you 
suggesting that despite appearance he does not want technical discussion? 

| > To take your question at the other end, so if you start with something
| > that is broken, realize it, but decide you can't change *all* the
| > brokenness because of some constraints, can the  result still be an
| > improvement?
| 
| It's certainly possible to improve something bad into something
| not-quite-so-bad. The question is whether the end result is good
| enough.

At least *you* seem to understand my question, as opposed to some
people here.  Although I disagree with with your conclusion, partly
because I doubt one could reach meaningful conclusions without
actually looked in and understood the problems.  And conclusions based on
refusal to go beyond "common saying" don't belong into technical
discussion, if I may borrow from you :-)

| The consensus here is that changing C++ into even a reasonable
| language would require so deep alterations that the result wouldn't be
| C++ anymore, and would be rejected for that reason.

I think there is something that has been missed here.  There are at
least two ways of making improvement: (1) radical changes, (2) extend
the language with functionalities that provide for better
alternatives, thus making making the broken part largely
secondary. 

-- Gaby

0
gdr (104)
6/4/2005 10:36:14 PM
Gabriel Dos Reis wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> | Gabriel Dos Reis wrote:
> | 
> | > Hartmann Schaffer <hs@hartmann.schaffernet> writes:
> | > | Gabriel Dos Reis wrote:
> | > | > ...
> | > | > Just facts. But, you do not seem to like facts, especially those that
> | > | > would expose the fiction in your claims.  You claimed:
> | > | >    instead of realizing that the syntax design was broken
> | > | > and I'm pointing out that, the author did know (at the time) and
> | > | > write
> | > | > about it several times and explains the reason of why he could not
> | > | > have done the cleanup he wanted, in the real world of the language
> | > | > users (as opposed to an imaginary perfect world).
> | > | | so if you start with something that is broken, realize it, but
> | > decide
> | > | you can't change the brokenness because of some constraints, the
> | > | result is not broken?
> | > I don't think "brokenness" is a universal, absolute notion.  What
> | > some people consider broken -- say Scheme, SML, Haskell, C++ -- may be
> | > considered not broken by others.
> | 
> | That doesn't make either of them right.
> 
> But that wasn't the point.

I was a bit too terse here: I meant to say "That doesn't make either 
peoples' definition of brokenness right."

In other words: wether people disagree about the degree of brokenness in 
a language, this doesn't make either of them right. The kind of 
brokenness I'm interested in is a rather objective (though very hard to 
measure) one: how many pitfalls it offers for developers in general, how 
efficient one can program in it, how secure the resulting code is in 
relation to the effort invested in making it so.

> | Besides, C++ *is* broken.
> | 
> | It's broken in theory: parsing is a mess, its semantics is riddled
> | with exceptions and special cases. I already gave constructor issues
> | in a recent post, and that's just the start.

No objections here. Fine.

> | It's broken according to broad consensus. It's even a common saying
> | that "C++ gives you not enough rope to hang yourself, but a pistol to
> | shoot nice large holes through your foot".
> 
> I think you can find something close to the origin of that "common
> saying" here:
> 
>   http://www.research.att.com/~bs/bs_faq.html#really-say-that
> 
>   "C makes it easy to shoot yourself in the foot; C++ makes it harder,
>   but when you do it blows your whole leg off."

That's the other common saying about C++.

I think it doesn't reflect general consensus though. Whenever I have 
seen quotes on the relative (un)security of either language, it was more 
the ropes and holes-in-the-foot variant.

(C++ does make a few things safer. It just doesn't address the real 
problems.)

 >   Yes, I said something like that.

Actually I didn't quote you, I reported an observation about how C++ is 
perceived. (Probably that perception is more prevalent outside the C++ 
community itself, so we may be at odds about which view is the less 
controversial one.)

 >   What people tend to miss, is that what I said there about
>   C++ is to a varying extent true for all powerful languages.

That variation is so broad that this statement is almost meaningless.

For example, Haskell is powerful and makes it very, very difficult to 
shoot yourself into the foot (you need to call aptly-named 
UnsafePerformIO function).

 >   As you
>   protect people from simple dangers, they get themselves into new and
>   less obvious problems. Someone who avoids the simple problems may
>   simply be heading for a not-so-simple one.

Only because he keeps so much time debugging the simple problems that he 
doesn't even notice the not-so-simple ones. That's only an argument if 
you take peoples' perceptions for reality.

 >   One problem with very
>   supporting and protective environments is that the hard problems may
>   be discovered too late or be too hard to remedy once discovered.

That's a real problem in language design.

On the other hand, there's a wide margin between "overly protective" and 
"outright dangerous". I think C++ errs on the "outright dangerous" side.

I also think that C++ takes that argument as an excuse for not properly 
thinking about the consequences of design decisions before unleashing 
them on an unsuspecting world. (I'm not talking about consequences for 
compiler writers. I'm talking about consequences for the language 
semantics, the guarantees that the language gives a programmer. C++ 
gives very few guarantees.)

 >   Also,
>   a rare problem is harder to find than a frequent one because you don't
>   suspect it.

That argument cuts both sides. If you're preoccupied with frequent 
problems, the rare problems never even appear on your radar. You get 
into a false sense of security once you have fixed all those simple 
frequent problems.

Let me give a supporting experience.

In my C++ days, I spent 10% of my time designing and 90% coding and 
debugging.

In my Eiffel days, I spent 30-50% of my time designing and the rest with 
coding/debugging. Not because design is so complicated if you use 
Eiffel, but because coding and debugging were so much easier that we 
could affort more time thinking about design. The gap between design and 
implementation was far narrower than with C++, so we could toss around 
design changes and implement them just to see whether they's work better.

>   "Within C++, there is a much smaller and cleaner language struggling
>   to get out." Yes, that quote can be found on page 207 of The Design
>   and Evolution of C++. And no, that smaller and cleaner language is not
>   Java or C#.

Fully agreed with that.

 >   The quote occurs in a section entitled "Beyond Files and
>   Syntax". I was pointing out that the C++ semantics is much cleaner
>   than its syntax.

I could agree with that, but only from the perspective that a semantics 
could be both clean (cleanly defined, fully formalised) but still 
utterly broken (i.e. the clean definition still produces obscure bugs).

And C++'s semantics is indeed utterly broken. I haven't even begun to 
enumerate all the problems with its semantics, and I haven't seen you 
disagreeing with the examples that I gave, so I'm somewhat surprised 
that you still seem to think that it has good merit.

> | Judgment on Bjarne Stroustrup's language design skills is what you've
> | been highlighting.
> 
> Then you missed the whole point.  I've been trying to see how

how what?

> | I'm under the impression that most people here
> | think that that's largely irrelevant 
> 
> Most people in this discussion seem to have posited axioms and are
> very firm on not examining things.  

I think that argument cuts both sides.
Actually I'm tired of this kind of allegation, regardless of whom it's 
directed against.

> | - what we think about is the
> | merit of the language itself (and C++ is quite unanimously considered
> | breakage here, else we'd be populating comp.lang.c++ instead of
> | comp.lang.functional).
> 
> I don't read comp.lang.c++, but by no means not just because you're
> not populating it means it is broken.

Not, but it does mean that you have a self-selected group of people who 
don't like C++.

 > That does not mean I'm claiming "C++ it nos broken")

Yup, I noticed a conspicuous absence of such claims.

I'm still wondering what your point actually *is*. Or why you're 
entertaining this discussion.

> | > To take your question at the other end, so if you start with something
> | > that is broken, realize it, but decide you can't change *all* the
> | > brokenness because of some constraints, can the  result still be an
> | > improvement?
> | 
> | It's certainly possible to improve something bad into something
> | not-quite-so-bad. The question is whether the end result is good
> | enough.
> 
> At least *you* seem to understand my question, as opposed to some
> people here.

Thanks.

Actually I'm pretty sure most people understand your position a lot 
better than you realise, there's just a lot of mutual missing the topic 
at work here. I.e. most here assume that C++ is broken beyond repair (a 
view that I share), and you seem to counter that argument with tales of 
how C++ originated and the constraints that it was designed under (which 
are probably correct but don't address the main objection).

 > Although I disagree with with your conclusion, partly
> because

Now I'd be interested what else are the reasons why you disagree.

 > I doubt one could reach meaningful conclusions without
> actually looked in and understood the problems.

Well, I have learned enough C++ to know it's an unsafe language, with 
many, many surprising twists in its semantics. Maybe a correct 
categorisation of C++ is "that it makes it more difficult to make simple 
errors, while making it d**n easy to make subtle errors" - an 
improvement that I don't really care for.

I know (partly from close observation, partly from direct participation) 
that designing a better language is difficult. Designing a good 
statically-typed OO language is very difficult. Designing such a 
language that's also largely compatible with C++ is impossible ("good" 
and "compatible with C" are almost diametrally opposing design goals).

However, I don't think that the realisation that the C++ design goals 
were a mission impossible saves the language in any way. It would have 
been better if somebody had designed an OO language that's syntactically 
similar enough to C that C programmers feel largely at home, and that 
can easily interface with C libraries so that existing software can be 
leveraged. (Of course, there's also the problem that knowledge about OO 
type systems wasn't as good as it is today. Multiple inheritance wasn't 
well-understood at that time - actually most language designers don't 
understand it today, and simply implement a mechanism that "resolves 
conflicts" in some arbitary fashion.)

> | The consensus here is that changing C++ into even a reasonable
> | language would require so deep alterations that the result wouldn't be
> | C++ anymore, and would be rejected for that reason.
> 
> I think there is something that has been missed here.  There are at
> least two ways of making improvement: (1) radical changes, (2) extend
> the language with functionalities that provide for better
> alternatives, thus making making the broken part largely
> secondary. 

Well, sure. The problem is that the broken parts of a language remain in 
use, so it doesn't really fix the problem.
Besides, adding to a language makes it even more complex, offering 
additional ways for fine semantic points to creep in - and every fine 
point in semantics is a source of subtle bugs.

C++ simply has grown into a too complex beast. The only way to fix it 
would be radical change - which, for various reasons, isn't feasible 
today. I think that C++ will go the same route as PL/I: existing 
projects will continue to use it, but its use in new projects will 
gradually decline until it's generally considered a dinosaur.

Regards,
Jo
0
jo427 (1164)
6/4/2005 10:42:48 PM
Joachim Durchholz <jo@durchholz.org> writes:

[...]

| That the syntax is baroque is largely a C legacy, and perhaps
| unavoidable. Still, there is gratuitious baroqueness in C++'s syntax,
| easily demonstrated through the observation that there are several
| useful C parsers available now, but _not_a_single_C++_parser_.

Facts:

    http://gcc.gnu.org/
    http://www.edg.com/

and many others.

-- Gaby
0
gdr (104)
6/4/2005 10:43:30 PM
Gabriel Dos Reis wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> [...]
> 
> | That the syntax is baroque is largely a C legacy, and perhaps
> | unavoidable. Still, there is gratuitious baroqueness in C++'s syntax,
> | easily demonstrated through the observation that there are several
> | useful C parsers available now, but _not_a_single_C++_parser_.
> 
> Facts:
> 
>     http://gcc.gnu.org/
>     http://www.edg.com/

I stand corrected.
Mainly because I was typing faster than thinking: I meant free (in both 
senses of the word) parsers.

GCC almost cuts it, but extracting the parser from the compiler is an 
almost impossible task.
edg seems to be a commercial product.

Why that emphasis on free parsers? Because they tend to be done by small 
teams or single persons. C++ is too complicated to be tackled if 
manpower is limited. In fact gcc strenthens that point: the only free 
software that handles C++ is gcc, a multi-person-century project; there 
are no lean-and-hungry C++ parsers around, but there are several for C 
(two usable ones listed on the comp.compilers archives, I think).

Regards,
Jo
0
jo427 (1164)
6/4/2005 10:48:12 PM
* David Hopwood:

> It would be quite possible for a language to statically reject programs
> in which references to partially constructed objects could escape their
> constructor.

Yes, but with virtual functions, you need whole-program analysis and
linker support.  This doesn't play nice with DSOs.

> Partially destructed objects would not be an issue in a
> language that used safe memory management (GC or region-based) and
> post-mortem finalization.

I think the key issue is the way destructors are combined.  If you
don't want a default combination, other solutions are fine.  But in my
experience, destructors were the only virtual members I had to
override in a non-trivial way (in all the other cases I remember, I
overrode the function completely, either a no-op function or an
abstract one).  That's why some special treatment might make sense.
0
fw12 (438)
6/4/2005 10:51:54 PM
Joachim Durchholz <jo@durchholz.org> writes:

[...]

| Anyway. It's not really a problem. Those complicated initialisation
| rules for C++ are dealing with a problem that simply doesn't exist.

Again, having work sufficiently enough with C++, I'm interested in the
data upon which you base that claim.

-- Gaby
0
gdr (104)
6/4/2005 11:09:35 PM
* Joachim Durchholz:

> Why that emphasis on free parsers? Because they tend to be done by small 
> teams or single persons. C++ is too complicated to be tackled if 
> manpower is limited. In fact gcc strenthens that point: the only free 
> software that handles C++ is gcc, a multi-person-century project;

The current C++ parser was written by Mark Mitchell.  AFAIK, it took
him much less than two person-years to write it.  Gaby might have
better figures.
0
fw12 (438)
6/4/2005 11:27:54 PM
* Joachim Durchholz:

> I'm speaking from my Eiffel experience here. Eiffel's policy is: a 
> function is always virtual (there are exceptions). Constructors are 
> otherwise normal functions, and they start with an object that's 
> initialized to all zeros.

This is only possible if all objects have a meaningful default value.
C++ references don't.

> Anyway. It's not really a problem. Those complicated initialisation 
> rules for C++ are dealing with a problem that simply doesn't exist.

I disagree, initialization of interacting subsystems (and a class
hierarchy is just that) is a difficult problem, and language support
is more than welcome.

For example, Ada's elaboration semantics make life so much easier in
many cases (half of the singleton pattern becomes trivial).

>>> It's broken according to broad consensus. It's even a common saying
>>> that "C++ gives you not enough rope to hang yourself, but a pistol
>>> to shoot nice large holes through your foot".
>> By this definition, most (all?) successful technology is broken.
> 
> (Let me restrict to "programming languages in the mainstream" - 
> "technology" is too general here, and "successful" is a somewhat 
> imprecise term.)

I meant "successful" in the sense of "success in acquiring developer
mindshare" or something like that, so proximity to mainstream is
equivalent.

> Lisp. Python.

Lisp is not successful and widely believed to be broken (parentheses,
garbage collection, dynamic type checking).  Some of the C++ criticism
in this thread certainly is at the parentheses level, and most at GC,
some at dynamic checking.

Python is only non-broken if you don't care for efficiency.  It's
very, very hard to create an optimizing Python compiler, much harder
than for Lisp, and you are tied to reference counting and can't use a
modern garbage collector.  Applying double standards, we could call
this a reasonable tradeoff, though.

> That experience strengthened my distaste for C++. I had an opportunity 
> to go into an Eiffel job and took it. My findings were:
> - All those typical problems of C++ programming (memory leaks, exception 
> handling issues, diamond inheritance issues, syntactic and semantic 
> surprises) simply vanished.
> - Despite Eiffel being in the verbose tradition of Pascal Ada, Eiffel 
> programs are far shorter than equivalent C++ programs. Part of it is 
> that Eiffel has automatic garbage collection (this takes off quite a lot 
> of lines of code, and often simplifies the design considerably),

You used the wrong C++ libraries, it seems.  Even garbage collection
is available for C++.  Maybe it's not part of the language standard,
but the Boehm-Demers-Weiser collector is probably as portable as your
average Eiffel implementation. 8-)

> Also, the Eiffel compiler automatically extracts the information
> that C++ programmers must redundantly write into header files.

This is purely a matter of taste.  I'm strongly in favor of a real
module system which separates declarations and definitions.  (This is
no argument in favor of C++, of course.)

> On the other hand, C++ templates are more difficult to compile 
> separately than generic classes in Eiffel, so I don't see that C++ has 
> any real advantage here.

You pay the costs caused by templates only when you use them.
0
fw12 (438)
6/4/2005 11:29:30 PM
* Joachim Durchholz:

>> What do you propose as an alternative?  Partially constructed
>> objects?
>
> Let the object be created as a member of its target class. The
> constructor is obliged to fill it with data that fulfills the class's
> invariant. In particular, it's obliged to fill in enough data before
> calling functions that depend on that data - but that's normal with any
> kind of step-by-step initialisation.

So you'd like to disallow calling virtual member functions from the
constructor altogether?  This doesn't sound too bad, but based on your
previous postings, I concluded you wanted something more flexible.

> Besides, initialisation is rarely a serious problem.

Tell that to someone who had to fight with circular dependencies among
singletons.
0
fw12 (438)
6/4/2005 11:34:22 PM
Gabriel Dos Reis wrote:
> ...
> To take your question at the other end, so if you start with something
> that is broken, realize it, but decide you can't change *all* the
> brokenness because of some constraints, can the  result still be an
> improvement? 

to not quite as badly broken?  would still be called broken

hs
0
hs60 (77)
6/5/2005 12:00:47 AM
Joachim Durchholz <jo@durchholz.org> writes:

[...]

| > | Besides, C++ *is* broken.
| > | | It's broken in theory: parsing is a mess, its semantics is
| > riddled
| > | with exceptions and special cases. I already gave constructor issues
| > | in a recent post, and that's just the start.
| 
| No objections here. Fine.

Oh no:  Absence of reply does not mean agreement or disagreement.
I just haven't read your constructor issues.  From your other
conversion with Florian, I guess it would have to do with calling
virtual functions in a constructor.  Is that right?

[...]

|  >   Yes, I said something like that.
| 
| Actually I didn't quote you,

I think you're (mis)attributing the quote from the website to me :-)

[...]

|  >   One problem with very
| >   supporting and protective environments is that the hard problems may
| >   be discovered too late or be too hard to remedy once discovered.
| 
| That's a real problem in language design.
| 
| On the other hand, there's a wide margin between "overly protective"
| and "outright dangerous". I think C++ errs on the "outright dangerous"
| side.
| 
| I also think that C++ takes that argument as an excuse for not
| properly thinking about the consequences of design decisions before
| unleashing them on an unsuspecting world.

Well, I've been in the trenches for some time to know from experience
and from those who have been there long before me that your claim is
largely unfounded.  For almost all problems I know of, I don't think
C++ designers did not properly think about design decision consequences.

[...]

| Let me give a supporting experience.
| 
| In my C++ days, I spent 10% of my time designing and 90% coding and
| debugging.

Then, let me give you counter supportive exprience:  I spend 90% of my
time designing and 10% coding.  It is largely known (at least in the
C++ community, but I would have thought it isn't that language
specific) that the far vast majority of time spent on project (nearly
90%) is on design not code. This is the case for collegues I have
high (technical) estime for.  That certainly is the case of (all?)
successful C++ project I know of.  
Those which required more than 10% coding were problematic if not
failure. 

[...]

| And C++'s semantics is indeed utterly broken. I haven't even begun to
| enumerate all the problems with its semantics,

Please do :-)  As I said elsewhere, I thought I would be discussing
semantics intead of angle brackets, curly braces and bananas.

| and I haven't seen you
| disagreeing with the examples that I gave, so I'm somewhat surprised
| that you still seem to think that it has good merit.

Which examples?  If you're refering to "constructors", I haven't seen
see them.  

[...]

| > | - what we think about is the
| > | merit of the language itself (and C++ is quite unanimously considered
| > | breakage here, else we'd be populating comp.lang.c++ instead of
| > | comp.lang.functional).
| > I don't read comp.lang.c++, but by no means not just because you're
| > not populating it means it is broken.
| 
| Not, but it does mean that you have a self-selected group of people
| who don't like C++.

You mean like some people on comp.lang.functional? ;-)

The only reason why I do not read comp.lang.c++ is that the traffic is
just too high for me to handle AND to read claims on
comp.lang.functional or comp.lang.ml etc :-)

|  > That does not mean I'm claiming "C++ it nos broken")
| 
| Yup, I noticed a conspicuous absence of such claims.
| 
| I'm still wondering what your point actually *is*.

That in the face of the real world, confrontation with reality, the
notion of "brokenness" is not as clear cut as some theologies are
putting it.  I don't believe it is a 0 or 1 thing.  Furthermore, I
think considerations of the constraints, goals and understanding of the
problems are essential for making that judgment as objective
as possible.  I just don't make it an axiom :-)

[...]

| > | The consensus here is that changing C++ into even a reasonable
| > | language would require so deep alterations that the result wouldn't be
| > | C++ anymore, and would be rejected for that reason.
| > I think there is something that has been missed here.  There are at
| > least two ways of making improvement: (1) radical changes, (2) extend
| > the language with functionalities that provide for better
| > alternatives, thus making making the broken part largely
| > secondary.
| 
| Well, sure. The problem is that the broken parts of a language remain
| in use, so it doesn't really fix the problem.

At that point, a question is why they are in use.  If there are needs
that those parts address then, better address those needs than simply
removing the broken parts -- taking analogy from a previous message,
the broken mirror is not fixed just because it is thrown away.
If there are in use because of insufficient support from environement
(better libraries, education, etc.) then it is not a problem of not
retiring the broken parts.  Rather offer better libraiies, education,
etc.  

The report that a language X programmer would spend 90% of its time
coding and 10% designing is effectivelly worrisome, but that is barely
the language fault.  I think it is more a problem of experience or
"education" (please, this is *no* insult) than an inherent brokenness
of the language.

I know from experience (writing programs and implementing translator)
that there are subsets of C++ that are safe, and they are subsets that
are unsafe.  The unsafe parts is largely superseded by the safe
parts.  And they are cases where the unsafe parts are needed (that is
the case for all major programming languages that support system
programming I know of).  But the unsafe part can be isolated.  And
that is a point that some people have trouble with.  C++ is
successfully used on daily basis in high critical missions where
safety is a major issue.  That is done by isolating the sae part form
the unsafe part.  And not, they don't spend 90% of time coding and
debugging ;-) 

-- Gaby
0
gdr (104)
6/5/2005 1:43:25 AM
Joachim Durchholz <jo@durchholz.org> writes:

[...]

| Why that emphasis on free parsers? Because they tend to be done by
| small teams or single persons. C++ is too complicated to be tackled if
| manpower is limited. In fact gcc strenthens that point: the only free
| software that handles C++ is gcc, a multi-person-century project;

The new GCC/g++ parser was written by a single person: Mark Mitchell
of CodeSourcery.

-- Gaby
0
gdr (104)
6/5/2005 1:46:01 AM
Florian Weimer <fw@deneb.enyo.de> writes:

| * Joachim Durchholz:
| 
| > Why that emphasis on free parsers? Because they tend to be done by small 
| > teams or single persons. C++ is too complicated to be tackled if 
| > manpower is limited. In fact gcc strenthens that point: the only free 
| > software that handles C++ is gcc, a multi-person-century project;
| 
| The current C++ parser was written by Mark Mitchell.  AFAIK, it took
| him much less than two person-years to write it.  Gaby might have
| better figures.

Yours are correct.

-- Gaby
0
gdr (104)
6/5/2005 1:46:55 AM
Hartmann Schaffer <hs@hartmann.schaffernet> writes:

| Gabriel Dos Reis wrote:
| > ...
| > To take your question at the other end, so if you start with something
| > that is broken, realize it, but decide you can't change *all* the
| > brokenness because of some constraints, can the  result still be an
| > improvement?
| 
| to not quite as badly broken?  would still be called broken

The point is that the notion of "brokenness" is not a 0 or 1 thingy.
Matthias even seems to agree :-) 

-- Gaby
0
gdr (104)
6/5/2005 1:49:13 AM
Just to fan the flames a bit more... I'm wonder what people think about 
"D"  http://www.digitalmars.com/d/
It seems a very serious attempted to "fix" C++ by starting from scratch.
It seems to lack a multi-million dollar marketing buget.. but beyond 
that.. it seems quite mature...
0
danwang74 (207)
6/5/2005 2:13:32 AM
Gabriel Dos Reis wrote:
> "Daniel C. Wang" <danwang74@gmail.com> writes:
> 
> | Just to fan the flames a bit more... I'm wonder what people think
> | about "D"  http://www.digitalmars.com/d/
> | It seems a very serious attempted to "fix" C++ by starting from scratch.
> 
> Google for discussions about D and C++ on C++ newsgroups ;-)
> 
> | It seems to lack a multi-million dollar marketing buget.. 
> 
> AT&T did not put $$$ marketing budget behind C++. 
> 
> -- Gaby

Defensive aren't we.. :) note I wasn't making any specific accusation, 
in fact I was thinking of C# and Java more than C++ .
0
danwang74 (207)
6/5/2005 2:55:15 AM
"Daniel C. Wang" wrote:
> 
> Just to fan the flames a bit more... I'm wonder what people think about
> "D"  http://www.digitalmars.com/d/
> It seems a very serious attempted to "fix" C++ by starting from scratch.
> It seems to lack a multi-million dollar marketing buget.. but beyond
> that.. it seems quite mature...

D is influenced by C, C++ and Java. I cannot see any influence
of Python let alone the functional programming languges. In
paricular, D is missing builtin lists, ML style variant types
and ML style pattern matching. Its biggest problem is that its
whole thinking is locked into a Java/C++ style of Object 
Orientated Design Pattern madness.

D attempts to fix a few of the more obvious flaws in C++ without
fixing the non-obvious flaws. Like C, C++ and Java, D allows
unsafe casts and unsafe conversion between types. D's template
system is a slight improvement over C++ but doesn't go anywhere
near far enough.

Erik
-- 
+-----------------------------------------------------------+
  Erik de Castro Lopo  nospam@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
"There is no reason why anyone would want a computer in their home"
Ken Olson, DEC, 1977
0
nospam140 (357)
6/5/2005 3:07:34 AM
Erik de Castro Lopo wrote:
{stuff deleted}
> D attempts to fix a few of the more obvious flaws in C++ without
> fixing the non-obvious flaws. Like C, C++ and Java, D allows
> unsafe casts and unsafe conversion between types. D's template
> system is a slight improvement over C++ but doesn't go anywhere
> near far enough.

So is it worth redesiging D's template system to "get it right" or would 
   people consider that a waste of effort?


Or to say it more generically, if one wanted to actually improve the 
state of programming languages for your every day hacker today, where 
should a language designer put their effort?

C++,
D,
Java,
C#

Note that C# and Java both recently picked up generics in a relatively 
principled way. Given that C# and Java both have large multi-billion 
dollar companies behind them with vested interests and C++  seems 
unpalatable to many is D a good platform for language designers?

I haven't mentioned any functional languages, because I'm becoming 
skeptical that they will have an real *direct* impact on programming for 
your average joe/jane programmer. I suspect they'll have a much bigger 
indirect impact in the long run.


0
danwang74 (207)
6/5/2005 3:42:58 AM
"Daniel C. Wang" <danwang74@gmail.com> writes:

| Just to fan the flames a bit more... I'm wonder what people think
| about "D"  http://www.digitalmars.com/d/
| It seems a very serious attempted to "fix" C++ by starting from scratch.

Google for discussions about D and C++ on C++ newsgroups ;-)

| It seems to lack a multi-million dollar marketing buget.. 

AT&T did not put $$$ marketing budget behind C++. 

-- Gaby
0
gdr (104)
6/5/2005 3:53:06 AM
"Daniel C. Wang" <danwang74@gmail.com> writes:

| Gabriel Dos Reis wrote:
| > "Daniel C. Wang" <danwang74@gmail.com> writes:
| > | Just to fan the flames a bit more... I'm wonder what people think
| > | about "D"  http://www.digitalmars.com/d/
| > | It seems a very serious attempted to "fix" C++ by starting from scratch.
| > Google for discussions about D and C++ on C++ newsgroups ;-)
| > | It seems to lack a multi-million dollar marketing buget.. AT&T did
| > not put $$$ marketing budget behind C++. -- Gaby
| 
| Defensive aren't we.. :)

No no no.

| note I wasn't making any specific accusation,
| in fact I was thinking of C# and Java more than C++ .

I was merely pointing out that as in the case of D you're reporting,
AT&T did not put $$$ marketing budget behind C++.  
Is that being defensive?

-- Gaby
0
gdr (104)
6/5/2005 4:23:01 AM
"Daniel C. Wang" wrote:
> 
> Erik de Castro Lopo wrote:
> {stuff deleted}
> > D attempts to fix a few of the more obvious flaws in C++ without
> > fixing the non-obvious flaws. Like C, C++ and Java, D allows
> > unsafe casts and unsafe conversion between types. D's template
> > system is a slight improvement over C++ but doesn't go anywhere
> > near far enough.
> 
> So is it worth redesiging D's template system to "get it right" or would
>    people consider that a waste of effort?

Because of all the other flaws, I believe D is a wasted effort
regardless of whether its template system is good or bad.

> Or to say it more generically, if one wanted to actually improve the
> state of programming languages for your every day hacker today, where
> should a language designer put their effort?
> 
> C++,
> D,
> Java,
> C#

None of the above.

I've only looked at it a little, but Nemerle

    http://www.nemerle.org/

seems to be the only attempt I know of that tries to bridge the
gap between C/C++/Java and the functional languages.

> I haven't mentioned any functional languages, because I'm becoming
> skeptical that they will have an real *direct* impact on programming for
> your average joe/jane programmer. I suspect they'll have a much bigger
> indirect impact in the long run.

IMHO, any language that allows unsafe casts and automatic
type conversions is unusable for large and/or complicated 
projects. Any language which is designed for tackling these
big problems must also have built in lists, bounds checked
arrays and safe string handling as part of the language core 
rather than as a grafted on extra like with C++ and to a lesser
extend Java and D. ML  style variant types and pattern matching 
are also a must have for my idea language.

You'll notice that none of the features above are strictly
functional language features. I'm not married to functional
programming, but for some tasks the functional approach
does work better than the imperative approach and vice versa.
It would therefore be nice to have functional and imperative
features on an equal footing unlike Ocaml where the constructs
for imperative programming seem like like second class features.

Erik
-- 
+-----------------------------------------------------------+
  Erik de Castro Lopo  nospam@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
Spammer:     Any of you guys looking for a permanent position in Scotland?
Kaz Kylheku: No, I'm looking for a thug in Scotland who might be interested
             in beating up off-topic Usenet spammers, on a pro bono basis.
0
nospam140 (357)
6/5/2005 5:01:31 AM
Quoth Erik de Castro Lopo <nospam@mega-nerd.com>:
....
| I've only looked at it a little, but Nemerle
|
|     http://www.nemerle.org/
|
| seems to be the only attempt I know of that tries to bridge the
| gap between C/C++/Java and the functional languages.

I think Felix sounds more like that than you probably meant -
http://felix.sourceforge.net/

	Donn Cave, donn@drizzle.com
0
donn (251)
6/5/2005 5:31:10 AM
Donn Cave wrote:
> 
> Quoth Erik de Castro Lopo <nospam@mega-nerd.com>:
> ...
> | I've only looked at it a little, but Nemerle
> |
> |     http://www.nemerle.org/
> |
> | seems to be the only attempt I know of that tries to bridge the
> | gap between C/C++/Java and the functional languages.
> 
> I think Felix sounds more like that than you probably meant -
> http://felix.sourceforge.net/

I am aware of Felix. I even lurk on the mailing list ;-).

However, the vast majority of the problems I am interested 
in are computationally expensive and I really don't think
that any language that runs on top of a VM (like Felix)
will ever match code that compiles to native binaries.

Despite John Skaller's success in to make Felix run as 
fast as the native ocaml and C compiled binaries for 
trivial test programs, I think that for real world cases
he has a long way to go.

Erik
-- 
+-----------------------------------------------------------+
  Erik de Castro Lopo  nospam@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
"A subversive is anyone who can out-argue their government"
0
nospam140 (357)
6/5/2005 5:42:07 AM
Erik de Castro Lopo wrote:
> "Daniel C. Wang" wrote:
{stuff deleted}
>>Or to say it more generically, if one wanted to actually improve the
>>state of programming languages for your every day hacker today, where
>>should a language designer put their effort?
>>
{stuff deleted}
> 
> IMHO, any language that allows unsafe casts and automatic
> type conversions is unusable for large and/or complicated 
> projects. Any language which is designed for tackling these
> big problems must also have built in lists, bounds checked
> arrays and safe string handling as part of the language core 
> rather than as a grafted on extra like with C++ and to a lesser
> extend Java and D. ML  style variant types and pattern matching 
> are also a must have for my idea language.
{stuff deleted}

Hmm.. my question was not what would be the best language that you would 
enjoy programming in, but where can one have a big impact on the design 
of a language that for whatever reason has mindshare of a large group of 
every day programmers.

After, reflecting on how generics made their way into Java and C#, I'm 
very skeptical about the value of everyone designing new languages from 
scratch and trying to build a user base around them. Desiging a new 
language is an interesting exercise, but I think that it is highly 
unlikely that most new languages will have any real *direct* impact in 
the long run. However, there are real problmatic issues in exsiting 
languages with existing user bases for which language designers can have 
a tangible *direct* impact on.

BTW using the visitor pattern and "inner classes/closures" really isn't 
so bad. Most OO languages have the moral equivlant of variants.  The 
lack of pattern matching is extremly annoying, but when it gets too 
annoying one can always write a pre-processor.


0
danwang74 (207)
6/5/2005 6:49:25 AM
On 2005-06-05, Erik de Castro Lopo <nospam@mega-nerd.com> wrote:
> Donn Cave wrote:
>> 
>> Quoth Erik de Castro Lopo <nospam@mega-nerd.com>:
>> ...
>> | I've only looked at it a little, but Nemerle
>> |
>> |     http://www.nemerle.org/
>> |
>> | seems to be the only attempt I know of that tries to bridge the
>> | gap between C/C++/Java and the functional languages.
>> 
>> I think Felix sounds more like that than you probably meant -
>> http://felix.sourceforge.net/
>
> I am aware of Felix. I even lurk on the mailing list ;-).
>
> However, the vast majority of the problems I am interested 
> in are computationally expensive and I really don't think
> that any language that runs on top of a VM (like Felix)
> will ever match code that compiles to native binaries.

Felix does not run on a VM. Felix generates C++ code, which is then
compiled by the C++ compiler. From the Felix page:

The Felix compiler is written in Objective Caml, and generates ISO C++
which should compile on any platform.

The running time is quite similar to code written for C++ or ocamlopt
http://felix.sourceforge.net/current/speed/en_flx_perf.html

Disclaimer: I never coded in Felix.

Regards.
-- 
Basile STARYNKEVITCH         http://starynkevitch.net/Basile/ 
email: basile(at)starynkevitch(dot)net 
8, rue de la Fa�encerie, 92340 Bourg La Reine, France
0
6/5/2005 8:12:41 AM
Florian Weimer <fw@deneb.enyo.de> writes:

> By this definition, most (all?) successful technology is broken.

So what? Most commercially successful technology *is* broken - most of
the time beyond all repair.

'Andreas
-- 
Wherever I lay my .emacs, there's my $HOME.
0
6/5/2005 8:38:28 AM
"Basile Starynkevitch [news]" wrote:
> 
> Felix does not run on a VM. Felix generates C++ code, which is then
> compiled by the C++ compiler. From the Felix page:

I'm sorry, you are correct.

Erik
-- 
+-----------------------------------------------------------+
  Erik de Castro Lopo  nospam@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
Linux, the UNIX defragmentation tool.
0
nospam140 (357)
6/5/2005 8:50:59 AM
"Daniel C. Wang" wrote:
> 
> Hmm.. my question was not what would be the best language that you would
> enjoy programming in, but where can one have a big impact on the design
> of a language that for whatever reason has mindshare of a large group of
> every day programmers.

Unfortunately, this is the attitude that has landed us
with C++ and Java. Both languages build on an existing
language without doing anything that fixes the failings
of the language they build on.

C++ and Java are both supposed to be high level languages
but both still have potentially unsafe casts. This is still
the case with Java which was based on C++ where I thought 
the lesson should have already been learned.

> After, reflecting on how generics made their way into Java and C#,

I know very little about C#. With regards to Java, I know
that maniupulating lists in Java is significantly more
painful that doing the same in say Ocaml. The reason is
that Ocaml has lists manipulation built into the language.
Java with generics still falls far short of Ocaml (or say
Python) with respect to list handling. The Visitor pattern
is simply not a adequate substitute.

> I'm
> very skeptical about the value of everyone designing new languages from
> scratch and trying to build a user base around them.

That may well be the case, but I believe that Java and
C++ (and probably C#) are unfixable with repsect to
sane list handling (to name one very common programming
task).


> Desiging a new
> language is an interesting exercise, but I think that it is highly
> unlikely that most new languages will have any real *direct* impact in
> the long run. However, there are real problmatic issues in exsiting
> languages with existing user bases for which language designers can have
> a tangible *direct* impact on.

Adding sane Ocaml/ML style list handling to mainstream 
Java is significantly more difficult than writing a new
language :-).

> BTW using the visitor pattern and "inner classes/closures" really isn't
> so bad.

I've seen it done and it works OK for trivial examples,
but is a royal PITA for large real world examples.

> Most OO languages have the moral equivlant of variants.

Its hackery at best. If you work on a large project with
many sub-teams and two teams independantly decide that they 
need variant types, you will end up with two incompatible
implementations. If variants are built into the language
people just use the builtin version instead of hacking
their own.

> The
> lack of pattern matching is extremly annoying, but when it gets too
> annoying one can always write a pre-processor.

Yet more hackery. The same arguments apply.

Erik
-- 
+-----------------------------------------------------------+
  Erik de Castro Lopo  nospam@mega-nerd.com (Yes it's valid)
+-----------------------------------------------------------+
Microsoft is finally bringing all of its Windows operating system families
under one roof. It will combine all of the features of CE, stability and
support of ME and the speed of NT.
It will be called Windows CEMENT...
0
nospam140 (357)
6/5/2005 9:05:45 AM
Florian Weimer wrote:
> * Joachim Durchholz:
> 
>>I'm speaking from my Eiffel experience here. Eiffel's policy is: a 
>>function is always virtual (there are exceptions). Constructors are 
>>otherwise normal functions, and they start with an object that's 
>>initialized to all zeros.
> 
> This is only possible if all objects have a meaningful default value.
> C++ references don't.

I'm not far enough into references to comment on that. All I can say is 
that I never missed them in other languages, and that's a strong 
indicator that they solve a problem that isn't one in other languages.

>>Anyway. It's not really a problem. Those complicated initialisation 
>>rules for C++ are dealing with a problem that simply doesn't exist.
> 
> I disagree, initialization of interacting subsystems (and a class
> hierarchy is just that) is a difficult problem, and language support
> is more than welcome.
 >
> For example, Ada's elaboration semantics make life so much easier in
> many cases (half of the singleton pattern becomes trivial).

OK, I'll take your word for that.

Then my stance on C++ constructor semantics becomes that it belongs to 
the problem set, not the solution set.

>>>>It's broken according to broad consensus. It's even a common saying
>>>>that "C++ gives you not enough rope to hang yourself, but a pistol
>>>>to shoot nice large holes through your foot".
>>>
>>>By this definition, most (all?) successful technology is broken.
>>
>>Lisp. Python.
> 
> Lisp is not successful and widely believed to be broken (parentheses,
> garbage collection, dynamic type checking).  Some of the C++ criticism
> in this thread certainly is at the parentheses level, and most at GC,
> some at dynamic checking.

Lisp in itself isn't broken. Lisp has some drawbacks (parenthese 
madness), and current-day lisps have broken macro and library stuff, but 
the language itself is actually quite sane.
GC actually is the opposite of brokenness: it makes the language safer 
and easier to program in. (It also restricts its usefulness for HRT, but 
being unsuitable for a specific niche doesn't make a language broken.)
Dynamic typing is something that I myself don't particularly like, but 
there are people who are successfully working with dynamically-typed 
languages, so this in itself isn't breakage, too.

So, while Lisp certainly isn't for everybody's taste or every 
application area, it isn't broken per se.

> Python is only non-broken if you don't care for efficiency.  It's
> very, very hard to create an optimizing Python compiler, much harder
> than for Lisp, and you are tied to reference counting and can't use a
> modern garbage collector.  Applying double standards, we could call
> this a reasonable tradeoff, though.

OK, reference counting is indeed brokenness.

Let me take back a bit of my statements above. A certain amount of 
brokenness seems to be inevitable; it's just that C++ is broken in so 
many ways that it's one of the worst languages that I have seen. (It's 
not the worst though. RPG IV is worse: not as much breakage as in C++, 
but that's only because it's so ridiculously inexpressive that the 
language simply didn't have as many murky corners to hide brokenness in.)

>>That experience strengthened my distaste for C++. I had an opportunity 
>>to go into an Eiffel job and took it. My findings were:
>>- All those typical problems of C++ programming (memory leaks, exception 
>>handling issues, diamond inheritance issues, syntactic and semantic 
>>surprises) simply vanished.
>>- Despite Eiffel being in the verbose tradition of Pascal Ada, Eiffel 
>>programs are far shorter than equivalent C++ programs. Part of it is 
>>that Eiffel has automatic garbage collection (this takes off quite a lot 
>>of lines of code, and often simplifies the design considerably),
> 
> You used the wrong C++ libraries, it seems.

Libraries don't help if you have to write your own algorithms.
We had to write a series of simple tests, and finding and learning a 
library would have been more effort than simply programming it by 
ourselves. (That's even true in hindsight. The test framework that I set 
up took me two weeks to write, and the test programmer said it worked 
smoothly for him. Finding and learning a test library would have taken 
more than two person-weeks.)

 > Even garbage collection
> is available for C++.  Maybe it's not part of the language standard,
> but the Boehm-Demers-Weiser collector is probably as portable as your
> average Eiffel implementation. 8-)

Actually BDW GC is an option or mandatory for all Eiffel implementations 
IIRC.

>>Also, the Eiffel compiler automatically extracts the information
>>that C++ programmers must redundantly write into header files.
> 
> This is purely a matter of taste.  I'm strongly in favor of a real
> module system which separates declarations and definitions.  (This is
> no argument in favor of C++, of course.)

Declarations are automatically inferrable from definitions, so that 
should be done. Having to keep the two consistent is a major time sink.

I'm speaking from having been on both sides of the fence: Turbo Pascal, 
Modula-3, and C++ require explicit module interfaces, Eiffel doesn't 
(and Eiffel compilers will generate human-readable interfaces on request).
My experience was: having the interfaces is excellent, but having to 
maintain them redundantly with the code simply isn't worth it - an 
eyeball code review will find more errors. Eiffel offered the best of 
both worlds, because I didn't have to wade through tons of source code 
to see the interface. (BTW Eiffel interfaces are even better than C++ 
ones: on request, the compiler will reproduce the full interface, 
including members that were inherited from superclasses. You don't need 
that too often, but it's indispensable when you're inspecting whether a 
class has all the members that you expect it to have, and to diagnose 
inheritance conflicts.)

>>On the other hand, C++ templates are more difficult to compile 
>>separately than generic classes in Eiffel, so I don't see that C++ has 
>>any real advantage here.
> 
> You pay the costs caused by templates only when you use them.

Same with Eiffel's generic classes, so what?

Regards,
Jo
0
jo427 (1164)
6/5/2005 9:36:09 AM
Erik de Castro Lopo wrote:
> "Daniel C. Wang" wrote:
> 
>>Hmm.. my question was not what would be the best language that you would
>>enjoy programming in, but where can one have a big impact on the design
>>of a language that for whatever reason has mindshare of a large group of
>>every day programmers.
> 
> 
> Unfortunately, this is the attitude that has landed us
> with C++ and Java. Both languages build on an existing
> language without doing anything that fixes the failings
> of the language they build on.

huh? I don't understand why you lump Java and C++ in the same bucket. 
 From a language design Java isn't as horribly broken as C++. Java fixed 
several problems with C++.

> C++ and Java are both supposed to be high level languages
> but both still have potentially unsafe casts. This is still
> the case with Java which was based on C++ where I thought 
> the lesson should have already been learned.

Java has casts none of them are unsafe/unchecked. If you look into the 
history of Java you'll discover that Java has much more in common with 
LISP than C++. It has C like syntax mainly because there's really no 
point in being different for no good reason.
0
danwang74 (207)
6/5/2005 10:10:53 AM
Gabriel Dos Reis wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
> [...]
> 
> | > | Besides, C++ *is* broken.
> | > | | It's broken in theory: parsing is a mess, its semantics is
> | > riddled
> | > | with exceptions and special cases. I already gave constructor issues
> | > | in a recent post, and that's just the start.
> | 
> | No objections here. Fine.
> 
> Oh no:  Absence of reply does not mean agreement or disagreement.

Well, it *would* have helped if you had answered then.

> I just haven't read your constructor issues.  From your other
> conversion with Florian, I guess it would have to do with calling
> virtual functions in a constructor.  Is that right?

Indeed.

> |  >   Yes, I said something like that.
> | 
> | Actually I didn't quote you,
> 
> I think you're (mis)attributing the quote from the website to me :-)

Nope, I'm quoting from your answers.

> |  >   One problem with very
> | >   supporting and protective environments is that the hard problems may
> | >   be discovered too late or be too hard to remedy once discovered.
> | 
> | That's a real problem in language design.
> | 
> | [...]
> | I also think that C++ takes that argument as an excuse for not
> | properly thinking about the consequences of design decisions before
> | unleashing them on an unsuspecting world.
> 
> Well, I've been in the trenches for some time to know from experience
> and from those who have been there long before me that your claim is
> largely unfounded.  For almost all problems I know of, I don't think
> C++ designers did not properly think about design decision consequences.

I'll readily agree that they spent a great deal of thinking about 
consequences. They simply messed up priorities, and took the above 
argument as an excuse for not getting it right.

> | Let me give a supporting experience.
> | 
> | In my C++ days, I spent 10% of my time designing and 90% coding and
> | debugging.
> 
> Then, let me give you counter supportive exprience:  I spend 90% of my
> time designing and 10% coding.  It is largely known (at least in the
> C++ community, but I would have thought it isn't that language
> specific) that the far vast majority of time spent on project (nearly
> 90%) is on design not code. This is the case for collegues I have
> high (technical) estime for.  That certainly is the case of (all?)
> successful C++ project I know of.

Seems like a self-selected sample then - most projects are failures. If 
you restrict yourself to projects where people are getting it right, you 
automatically exclude those where the language prevented them from being 
successful.

> | And C++'s semantics is indeed utterly broken. I haven't even begun to
> | enumerate all the problems with its semantics,
> 
> Please do :-)  As I said elsewhere, I thought I would be discussing
> semantics intead of angle brackets, curly braces and bananas.

I did, but you didn't pick that up.

Anyway, I didn't want to enter into a detailed discussion of C++'s 
problems. If you disagree about the semantic problems, that's fine by me.

You might take interest in Ian Joyner's C++ Critique (accessible in 
several places via Google). He's going overboard nitpicking in many 
cases, but discounting that you still have an impressive list of 
misfeatures.
> |  > That does not mean I'm claiming "C++ it nos broken")
> | 
> | Yup, I noticed a conspicuous absence of such claims.
> | 
> | I'm still wondering what your point actually *is*.
> 
> That in the face of the real world, confrontation with reality, the
> notion of "brokenness" is not as clear cut as some theologies are
> putting it.

OK, here's my personal definition:

A language is "broken" wherever it causes or promotes unsafe 
programming. This includes things like violations of the principle of 
least surprise, encouragement of unsafe practices, or the absence of 
safety nets (and making it difficult to install reliable safety nets in 
the form of library code).

 > I don't believe it is a 0 or 1 thing.

Of course not. Languages can be more or less broken. A certain amount of 
breakage seems to be unavoidable - not because a non-broken language is 
impossible but because of the way that languages are designed and evolve.

On the other hand, I think that by the above definition, a reasonably 
precise estimate of a language's brokenness is possible. For me, on a 
scale between 0 and 1, C++'s brokenness ranges somewhere around 0.8, and 
that's pretty bad. (RPG IV is 0.97 or something. Pascal would be 0.4, 
Eiffel 0.3. Eiffel could be brought to, say, 0.2 - there are principal 
limits to what one can to with an imperative dynamic-dispatching 
language. C++ has far more room for improvement, but I fear that any 
changes for the better would require too much incompatibility.)

 > Furthermore, I
> think considerations of the constraints, goals and understanding of the
> problems are essential for making that judgment as objective
> as possible.  I just don't make it an axiom :-)

Again: the goals and constraints are secondary for my definition of 
brokenness.

Besides, I strongly disagree about the constraints and goals that Bjarne 
chose. Not that they were unreasonable - but there was a conspicuous 
absense of goals like "regular semantics", "flat learning curve for 
programmers-to-be", "pitfall plugging". The result shows it.

> | > | The consensus here is that changing C++ into even a reasonable
> | > | language would require so deep alterations that the result wouldn't be
> | > | C++ anymore, and would be rejected for that reason.
> | > I think there is something that has been missed here.  There are at
> | > least two ways of making improvement: (1) radical changes, (2) extend
> | > the language with functionalities that provide for better
> | > alternatives, thus making making the broken part largely
> | > secondary.
> | 
> | Well, sure. The problem is that the broken parts of a language remain
> | in use, so it doesn't really fix the problem.
> 
> At that point, a question is why they are in use.  If there are needs
> that those parts address then, better address those needs than simply
> removing the broken parts -- taking analogy from a previous message,
> the broken mirror is not fixed just because it is thrown away.

<grin> but there is nothing but throwing away that you can do with a 
broken mirror.

I'm well aware that every analogy breaks at some point. In particular, 
improving C++ isn't an entirely fruitless exercise: it will remain with 
us until the next hype washes it away, in a decade or two, and improving 
C++ for that period of time can be of help. Just don't expect these 
improvement to make computing history.

> If there are in use because of insufficient support from environement
> (better libraries, education, etc.) then it is not a problem of not
> retiring the broken parts.  Rather offer better libraiies, education,
> etc.  

Programmers will learn only under extreme pressure.
Better libraries are of limited use if the language is broken.

> The report that a language X programmer would spend 90% of its time
> coding and 10% designing is effectivelly worrisome, but that is barely
> the language fault.  I think it is more a problem of experience or
> "education" (please, this is *no* insult) than an inherent brokenness
> of the language.

If a language requires 5+ years for getting to that point, it's an 
economic disaster.
For a comparison, in Eiffel, I started with 50% design and 50% coding; 
after half a year, I was at 65% and 35%, arriving at the 70/30 ratio I 
alluded to in the end.
(A 90/10 ratio was unattainable for the kind of stuff we were doing: it 
was a GUI library that tried to regularize the Windows controls' APIs.)

Regards,
Jo
0
jo427 (1164)
6/5/2005 10:23:49 AM
"Daniel C. Wang" <danwang74@gmail.com> writes:

> Java has casts none of them are unsafe/unchecked. If you look into the
> history of Java you'll discover that Java has much more in common with
> LISP than C++. It has C like syntax mainly because there's really no
> point in being different for no good reason.

Java indeed doesn't have operations which lead to undefined behavior,
but it too doesn't detect some obvious errors in the name of efficiency:
arithmetic overflow.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/5/2005 10:28:10 AM
Daniel C. Wang wrote:

> Just to fan the flames a bit more... I'm wonder what people think about 
> "D"  http://www.digitalmars.com/d/
> It seems a very serious attempted to "fix" C++ by starting from scratch.
> It seems to lack a multi-million dollar marketing buget.. but beyond 
> that.. it seems quite mature...

Not powerful enough: no multiple inheritance.
Not flexible enough: no dynamic class loading. (That's a hard problem 
though.)
Nit to pick: yet another string concatenation operator. (Ah, you can't 
use & or . in a C-style language.)
Good: contracts. Seems like solid basic support, though one could add 
all sorts of fancy things.

In all, it seems a reasonable point on the engineering trade-off spectrum.

Just a first impression. The devil is often in the details (well, for 
C++, it was also in the grand picture.)

Regards,
Jo
0
jo427 (1164)
6/5/2005 10:42:15 AM
Daniel C. Wang wrote:
> Or to say it more generically, if one wanted to actually improve the 
> state of programming languages for your every day hacker today, where 
> should a language designer put their effort?
> 
> C++,
> D,
> Java,
> C#
> 
> Note that C# and Java both recently picked up generics in a relatively 
> principled way. Given that C# and Java both have large multi-billion 
> dollar companies behind them with vested interests and C++  seems 
> unpalatable to many is D a good platform for language designers?

I think that D, Java, and C# are roughly equivalent: solid enough for 
useful work.

Politically, Java is probably the best platform. It's well-supported and 
here to stay.

Working with C++ requires a whole lot of arcane knowledge and black 
magic. You'd probably end up spending so much thought space on C++ that 
your mind isn't open for real improvements anymore.

> I haven't mentioned any functional languages, because I'm becoming 
> skeptical that they will have an real *direct* impact on programming for 
> your average joe/jane programmer. I suspect they'll have a much bigger 
> indirect impact in the long run.

I like to think (read: hope) that they will be the next big hype.

Regards,
Jo
0
jo427 (1164)
6/5/2005 11:01:49 AM
Florian Weimer wrote:

> * Joachim Durchholz:
> 
>>> What do you propose as an alternative?  Partially constructed 
>>> objects?
>> 
>> Let the object be created as a member of its target class. The 
>> constructor is obliged to fill it with data that fulfills the
>> class's invariant. In particular, it's obliged to fill in enough
>> data before calling functions that depend on that data - but that's
>> normal with any kind of step-by-step initialisation.
> 
> So you'd like to disallow calling virtual member functions from the 
> constructor altogether?

No, that's a decision for the programmer to make. He shouldn't do
virtual calls until the preconditions for those calls are met.

(This isn't too bad. Been there, done that.)

>> Besides, initialisation is rarely a serious problem.
> 
> Tell that to someone who had to fight with circular dependencies
> among singletons.

That's initialisation of large global data structures. I don't think
that the way constructors work have any influence on that problem - it's
a hard problem by nature.

Regards,
Jo
0
jo427 (1164)
6/5/2005 11:07:52 AM
Florian Weimer wrote:

> * Joachim Durchholz:
> 
>>Why that emphasis on free parsers? Because they tend to be done by small 
>>teams or single persons. C++ is too complicated to be tackled if 
>>manpower is limited. In fact gcc strenthens that point: the only free 
>>software that handles C++ is gcc, a multi-person-century project;
> 
> The current C++ parser was written by Mark Mitchell.  AFAIK, it took
> him much less than two person-years to write it.  Gaby might have
> better figures.

Ah, then things have changed. It's been a while since I frequented 
comp.compilers.

Two man-years is still an impressive figure though... parsers for 
languages like SML or Eiffel are more like man-weeks. And I can't 
convince myself that several orders of magnitude of increased difficulty 
are really worth the results.

Regards,
Jo
0
jo427 (1164)
6/5/2005 11:10:15 AM
Joachim Durchholz <jo@durchholz.org> writes:

>>> Besides, initialisation is rarely a serious problem.
>> Tell that to someone who had to fight with circular dependencies
>> among singletons.
>
> That's initialisation of large global data structures. I don't think
> that the way constructors work have any influence on that problem -
> it's a hard problem by nature.

I'm not sure it's such a hard problem by nature. Could you give an
example where it's hard conceptually, yet possible at all? I want to
see how my language would solve that.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/5/2005 11:38:11 AM
Marcin 'Qrczak' Kowalczyk wrote:

> Joachim Durchholz <jo@durchholz.org> writes:
> 
>>>>Besides, initialisation is rarely a serious problem.
>>>
>>>Tell that to someone who had to fight with circular dependencies
>>>among singletons.
>>
>>That's initialisation of large global data structures. I don't think
>>that the way constructors work have any influence on that problem -
>>it's a hard problem by nature.
> 
> I'm not sure it's such a hard problem by nature. Could you give an
> example where it's hard conceptually, yet possible at all? I want to
> see how my language would solve that.

Not off the top of my head. I had similar problems only with large programs.

I think it's a problem with circularly dependent globals being 
initialised. Programmers assume that globals are always available, and 
that assumption clearly breaks during initialisation, so that's an 
intrinsically hard problem.

OTOH circular dependencies are an indicator that the module structure is 
wrong: most of the time, it's not the modules in their entirety but just 
some specific parts of them that are circularly dependent. Those 
entities should go into a common base module so that the circular 
dependency becomes local and tractable.

Another way to circumvent the problem is by ad-hoc initialisation: the 
module fully initialises itself only on first call, and only to the 
extent needed for a given task. If that still remains a circular 
dependency, you actually have a cross-module endless recursion, which is 
a conceptual error anyway :-)

Regards,
Jo
0
jo427 (1164)
6/5/2005 11:48:33 AM
Florian Weimer wrote:
> Python is only non-broken if you don't care for efficiency.  It's
> very, very hard to create an optimizing Python compiler, much harder
> than for Lisp, and you are tied to reference counting and can't use a
> modern garbage collector.

Nothing in the Python language specification requires reference counting.
Don't confuse the CPython implementation with the language. Jython has
full GC.

-- 
David Hopwood <david.nospam.hopwood@blueyonder.co.uk>
0
6/5/2005 2:15:18 PM
Joachim Durchholz wrote:

> OTOH circular dependencies are an indicator that the module structure is
> wrong: most of the time, it's not the modules in their entirety but just
> some specific parts of them that are circularly dependent. Those
> entities should go into a common base module so that the circular
> dependency becomes local and tractable.

Why? I've seen this opinion expressed from time to time but never seen
a convincing justification. Mutual recursion between modules (or some
of the entities defined in those modules) is perfectly reasonable,
natural and useful.

IMNSHO this is merely folklore promulgated by language designers
and/or implementors that can't be bothered to fix their compilers to
handle mutual recursion properly :-)

Regards
--
Adrian Hey
   
0
ahey (217)
6/5/2005 2:38:22 PM
Adrian Hey wrote:

> Joachim Durchholz wrote:
> 
>>OTOH circular dependencies are an indicator that the module structure is
>>wrong: most of the time, it's not the modules in their entirety but just
>>some specific parts of them that are circularly dependent. Those
>>entities should go into a common base module so that the circular
>>dependency becomes local and tractable.
> 
> Why? I've seen this opinion expressed from time to time but never seen
> a convincing justification. Mutual recursion between modules (or some
> of the entities defined in those modules) is perfectly reasonable,
> natural and useful.

I agree that mutual recursion between modules can be useful.

However, the kind of recursion that creates initialisation agonies is 
typically caused by wrong modularisation.

> IMNSHO this is merely folklore promulgated by language designers
> and/or implementors that can't be bothered to fix their compilers to
> handle mutual recursion properly :-)

Well, initialisation is an issue only with global variables, so I 
suspect the real problem is indeed not in recursion but in globals. But 
then we were dealing with practical languages, warts and all...

Regards,
jo
0
jo427 (1164)
6/5/2005 2:51:13 PM
Gabriel Dos Reis wrote:
> "Daniel C. Wang" <danwang74@gmail.com> writes:
> 
> | Just to fan the flames a bit more... I'm wonder what people think
> | about "D"  http://www.digitalmars.com/d/
> | It seems a very serious attempted to "fix" C++ by starting from scratch.
> 
> Google for discussions about D and C++ on C++ newsgroups ;-)

<http://groups.google.co.uk/groups?as_q=D+language&num=100&as_ugroup=comp.lang.c%2B%2B.*>

As might be expected, that search gets you mostly noise. OTOH, the first thread
seems to be quite positive about D. What was your point?

-- 
David Hopwood <david.nospam.hopwood@blueyonder.co.uk>
0
6/5/2005 3:29:28 PM
Erik de Castro Lopo wrote:
> "Daniel C. Wang" wrote:
> 
>>Hmm.. my question was not what would be the best language that you would
>>enjoy programming in, but where can one have a big impact on the design
>>of a language that for whatever reason has mindshare of a large group of
>>every day programmers.
> 
> Unfortunately, this is the attitude that has landed us
> with C++ and Java. Both languages build on an existing
> language without doing anything that fixes the failings
> of the language they build on.
> 
> C++ and Java are both supposed to be high level languages
> but both still have potentially unsafe casts. This is still
> the case with Java which was based on C++ where I thought 
> the lesson should have already been learned.

What precisely do you mean by unsafe here? Java, unlike C++, is
strongly typed:
  - all constructs have well-defined behaviour,
  - the run-time type of the content of any variable is always
    consistent with its declared type,
  - type errors can only occur in constructs where they are documented
    to occur (e.g. casts, array stores, etc.), and in that case they
    result in an exception.

Note that I'm not particularly defending the overall design of Java's
type system, just wondering why you call it unsafe.

-- 
David Hopwood <david.nospam.hopwood@blueyonder.co.uk>
0
6/5/2005 4:03:12 PM
Marcin 'Qrczak' Kowalczyk wrote:
{stuff deleted}
> 
> Java indeed doesn't have operations which lead to undefined behavior,
> but it too doesn't detect some obvious errors in the name of efficiency:
> arithmetic overflow.


Java had bignums and even BCD based bignums for those who care. I think, 
SML is the only language I know of which requires trapping arithmitic on 
the native int type. heck, if I'm not mistaken even OCaml doesn't trap! 
Anyway, the overflow issue hardly makes the language broken.
0
danwang74 (207)
6/5/2005 5:04:44 PM
Joachim Durchholz wrote:
{stuff deleted}
> Not powerful enough: no multiple inheritance.
It has interfaces ala Java.  I consider the lack of multiple inheritance 
a feature. (Guess,  you can't make everyone happy..)
> Not flexible enough: no dynamic class loading. (That's a hard problem 
> though.)
A practial problem, but it can load libraries dyanmically as much as a C 
and C++ program can.

> Nit to pick: yet another string concatenation operator. (Ah, you can't 
> use & or . in a C-style language.)
> Good: contracts. Seems like solid basic support, though one could add 
> all sorts of fancy things.
> 
> In all, it seems a reasonable point on the engineering trade-off spectrum.
My impression too.. which was why I brought it up. Compared to C++ it 
does not seem so horribly broke, and it is amining at a similar niche as 
C++.

> Just a first impression. The devil is often in the details (well, for 
> C++, it was also in the grand picture.)



0
danwang74 (207)
6/5/2005 5:09:36 PM
"Daniel C. Wang" <danwang74@gmail.com> writes:

> Java had bignums and even BCD based bignums for those who care.
> I think, SML is the only language I know of which requires trapping
> arithmitic on the native int type.

In C# and Turbo Pascal checking is switchable. I don't know Delphi,
but perhaps it's like in Turbo Pascal.

In many languages bignums are produced automatically when fixnums
overflow: Lisp, Scheme, Erlang, Python (used to be an exception),
Ruby, Smalltalk.

Java bignums are awkward to use because arithmetic and comparisons
must look as method calls. They are also less efficient than a
combination of fixnums and bignums because they must all be allocated
dynamically.

It seems that dynamic typing promotes arithmetic safety. Most
dynamically typed languages don't have integers constrained to machine
word size, while most statically typed ones make wrapping-around or
at most exception-throwing limited ints the default.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/5/2005 6:09:21 PM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:

> It seems that dynamic typing promotes arithmetic safety. Most
> dynamically typed languages don't have integers constrained to machine
> word size, while most statically typed ones make wrapping-around or
> at most exception-throwing limited ints the default.

I'm not going to argue about "most" languages, but isn't statically
typed languages using arbitrary precision integers fairly equivalent
to dynamically typed ones?

-kzm
-- 
If I haven't seen further, it is by standing in the footprints of giants
0
news2 (145)
6/5/2005 6:15:31 PM
Marcin 'Qrczak' Kowalczyk wrote:
{stuff deleted}
> It seems that dynamic typing promotes arithmetic safety. Most
> dynamically typed languages don't have integers constrained to machine
> word size, while most statically typed ones make wrapping-around or
> at most exception-throwing limited ints the default.

Arithmetic safety is not needed for type-safety. For applications that 
require the performance hit needed for arithmetic safety they should 
have a way out. However, using an infinite precision rep by default 
seems to be wrong headed with respect to performance. In general most 
dynamic programming language trade off conveince for performance. 
Sometimes this is not the right tradeoof and performance should be 
considered.  In anycase Java seems to have a resonable solution to the 
issue.
0
danwang74 (207)
6/5/2005 6:39:40 PM
Ketil Malde <ketil+news@ii.uib.no> writes:

>> It seems that dynamic typing promotes arithmetic safety. Most
>> dynamically typed languages don't have integers constrained to machine
>> word size, while most statically typed ones make wrapping-around or
>> at most exception-throwing limited ints the default.
>
> I'm not going to argue about "most" languages, but isn't statically
> typed languages using arbitrary precision integers fairly equivalent
> to dynamically typed ones?

Yes, in theory. But in practice in most of them arbitrary precision
integers look much more awkward than machine word integers (C, Java,
SML, OCaml), or while in theory they could integrate well, the
standard language doesn't provide them at all (C++, Clean).

The only statically typed language I know where arbitrary precision
integers are as convenient as machine word integers is Haskell.

I don't know about C#, Eiffel and Mercury. They all should be able to
suppor them well, but I don't know whether they actually do (and I'm
too lazy to check now).

Also, they are usually less efficient than in dynamically typed
languages, because in latter ones it's very common to represent small
integers unboxed, tagged in some bits, and only large integers as
pointers. Yes, it's a special case in the runtime, but it's common
enough to be worth the effort.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/5/2005 7:23:39 PM
Marcin 'Qrczak' Kowalczyk wrote:

> "Daniel C. Wang" <danwang74@gmail.com> writes:
> 
> 
>>Java had bignums and even BCD based bignums for those who care.
>>I think, SML is the only language I know of which requires trapping
>>arithmitic on the native int type.
> 
> In C# and Turbo Pascal checking is switchable. I don't know Delphi,
> but perhaps it's like in Turbo Pascal.

It's switchable in Delphi IIRC.

> It seems that dynamic typing promotes arithmetic safety. Most
> dynamically typed languages don't have integers constrained to machine
> word size, while most statically typed ones make wrapping-around or
> at most exception-throwing limited ints the default.

That's probably a consequence of having incurred some representational 
overhead already, so overflowing into bignums isn't a big incremental 
overhead anymore.

Regards,
Jo
would like static typing and arithmetic safety combined
0
jo427 (1164)
6/5/2005 10:06:07 PM
Marcin 'Qrczak' Kowalczyk wrote:

> I don't know about C#, Eiffel and Mercury. They all should be able to
> suppor them well, but I don't know whether they actually do (and I'm
> too lazy to check now).

Eiffel doesn't. It was compiling to C, and simply inherited C's 
arithmetic properties.
Large integer types do exist as library classes, but they aren't 
integrated into the standard integer type in any way.

Some Eiffel implementations offer various machine integer types, 
together with some ad-hoc transformation rules.

Regards,
Jo
0
jo427 (1164)
6/5/2005 10:08:56 PM
Marcin 'Qrczak' Kowalczyk wrote:
> It seems that dynamic typing promotes arithmetic safety. Most
> dynamically typed languages don't have integers constrained to machine
> word size, while most statically typed ones make wrapping-around or
> at most exception-throwing limited ints the default.

This is a correlation between preferences of language designers; it
doesn't indicate any necessary dependence between the language features.

-- 
David Hopwood <david.nospam.hopwood@blueyonder.co.uk>
0
6/5/2005 11:03:51 PM
"Gabriel Dos Reis" <gdr@integrable-solutions.net> wrote in message
news:m3mzq51mu5.fsf@uniton.integrable-solutions.net...
> "Daniel C. Wang" <danwang74@gmail.com> writes:
>
> | Just to fan the flames a bit more... I'm wonder what people think
> | about "D"  http://www.digitalmars.com/d/
> | It seems a very serious attempted to "fix" C++ by starting from scratch.
>
> Google for discussions about D and C++ on C++ newsgroups ;-)

There are also tens of thousands of messages on the D newsgroups at
news.digitalmars.com. Google refuses to index it, but that's for the good,
as it flies below the radar of the spammers <g>.

> | It seems to lack a multi-million dollar marketing buget..

True. The D marketing budget is $0. The progress D is making is entirely due
to the volunteer efforts of the D community.


0
walter22 (101)
6/6/2005 7:15:44 AM
"Gabriel Dos Reis" <gdr@integrable-solutions.net> wrote in message
news:m31x7hsa8q.fsf@uniton.integrable-solutions.net...
> I was merely pointing out that as in the case of D you're reporting,
> AT&T did not put $$$ marketing budget behind C++.

AT&T did the best, most effective kind of marketing - they paid the salaries
of brilliant engineers like Andrew Koenig and Bjarne Stroustrup as they
worked on and evangelized C++. I read their papers and attended their
presentations in C++'s early days, and they were very, very effective.


0
walter22 (101)
6/6/2005 7:22:22 AM
"Joachim Durchholz" <jo@durchholz.org> wrote in message
news:d7uku7$c0a$1@online.de...
> Not powerful enough: no multiple inheritance.

It'll do multiple inheritance of interfaces. Yes, this isn't full multiple
inheritance as practiced by C++.

> Nit to pick: yet another string concatenation operator. (Ah, you can't
> use & or . in a C-style language.)

A lot of people are at first put off by using ~ as an array concatenation
operator, and ~= as array append. The fun thing is, though, is once you
write a bit of code with it, it's the other operators like & and + for
concatenation that seem wrong.

After all, array concatenation is conceptually nothing like "and" or "add".
If you had a vector of floats, and you used '+' on two of them, would you
get a concatenation or an element-wise add? I submit that the latter is what
one would expect. Overloading '+' to mean "add" in some contexts, and
"concatenate" in others is needless confusion.

-Walter
www.digitalmars.com/d/ the D Programming Language


0
walter22 (101)
6/6/2005 7:30:26 AM
Walter wrote:

> "Joachim Durchholz" <jo@durchholz.org> wrote in message
> news:d7uku7$c0a$1@online.de...
> 
>> Not powerful enough: no multiple inheritance.
> 
> It'll do multiple inheritance of interfaces. Yes, this isn't full multiple
> inheritance as practiced by C++.

Exactly. Interfaces are the poor designer's excuse. "Sorry, we don't 
understand MI properly, please roll your own."

>>Nit to pick: yet another string concatenation operator. (Ah, you can't
>>use & or . in a C-style language.)
> 
> A lot of people are at first put off by using ~ as an array concatenation
> operator, and ~= as array append. The fun thing is, though, is once you
> write a bit of code with it, it's the other operators like & and + for
> concatenation that seem wrong.

That's normal: those operators that you don't use on a day-to-day basis 
first start to look strange, then wrong.

> After all, array concatenation is conceptually nothing like "and" or "add".

Well, yes, if you think that & is bitwise and. I recall & being used as 
concatenation operator, and * for set intersection (which is the proper 
semantics of bitwise and, and indeed has analogies with multiplication).

Regards,
Jo
0
jo427 (1164)
6/6/2005 8:51:14 PM
"Joachim Durchholz" <jo@durchholz.org> wrote in message
news:d82d03$pq1$1@online.de...
> Walter wrote:
> > "Joachim Durchholz" <jo@durchholz.org> wrote in message
> > news:d7uku7$c0a$1@online.de...
> >
> >> Not powerful enough: no multiple inheritance.
> > It'll do multiple inheritance of interfaces. Yes, this isn't full
multiple
> > inheritance as practiced by C++.
> Exactly. Interfaces are the poor designer's excuse. "Sorry, we don't
> understand MI properly, please roll your own."

Since I've written a C++ compiler that does MI, and I know exactly how it
works, I'm afraid you'll need another reason <g>.


> > After all, array concatenation is conceptually nothing like "and" or
"add".
> Well, yes, if you think that & is bitwise and.

Even if you think of & as a logical and, it still doesn't imply
concatenation.


> I recall & being used as
> concatenation operator, and * for set intersection (which is the proper
> semantics of bitwise and, and indeed has analogies with multiplication).

None of the existing C or C++ operators makes any logical sense for
concatenation. That's why D uses a new one.

-Walter
www.digitalmars.com C, C++, D compilers


0
walter22 (101)
6/6/2005 9:28:36 PM
Joachim Durchholz wrote:
> Walter wrote:
> 
>> "Joachim Durchholz" <jo@durchholz.org> wrote in message
>> news:d7uku7$c0a$1@online.de...
>>
>>> Not powerful enough: no multiple inheritance.
>>
>>
>> It'll do multiple inheritance of interfaces. Yes, this isn't full 
>> multiple
>> inheritance as practiced by C++.
> 
> 
> Exactly. Interfaces are the poor designer's excuse. "Sorry, we don't 
> understand MI properly, please roll your own."

I know zip about D, but I should say that it's been maybe a decade since 
I've used multiple inheritance in C++. In some strange sense that I have 
yet to be able to articulate, templates have made multiple inheritance 
unnecessary. Inheritance plus virtual functions is purely about 
type-safe dynamic dispatch. Inheritance in and of itself, I have become 
convinced, is a distraction.

[...]

-thant

-- 
We have now sunk to a depth at which restatement of the obvious is the
first duty of intelligent men. -- George Orwell (attributed)

0
thant (332)
6/6/2005 9:31:44 PM
Walter wrote:

> "Joachim Durchholz" <jo@durchholz.org> wrote in message 
> news:d82d03$pq1$1@online.de...
> 
>> Walter wrote:
>> 
>>> "Joachim Durchholz" <jo@durchholz.org> wrote in message 
>>> news:d7uku7$c0a$1@online.de...
>>> 
>>> 
>>>> Not powerful enough: no multiple inheritance.
>>> 
>>> It'll do multiple inheritance of interfaces. Yes, this isn't full
>>> 
> 
> multiple
> 
>>> inheritance as practiced by C++.
>> 
>> Exactly. Interfaces are the poor designer's excuse. "Sorry, we
>> don't understand MI properly, please roll your own."
> 
> Since I've written a C++ compiler that does MI, and I know exactly
> how it works, I'm afraid you'll need another reason <g>.

C++ doesn't get it right anyway.

Eiffel comes close but doesn't handle it correctly, too. See
http://durchholz.org/jo/eiffel-critique/replicated-inheritance.html for
a discussion of the issues involved.
Note that that page originally was a part of an Eiffel critique that I
never finished. This is partly a liability (because it spends a good
deal of discussion and critique of Eiffel specifics), and partly a boon
(it uses assertions and DbC as a kind of Occam's razor to infer
relatively rigidly what MI really should do). There's also a formatting
foul-up that I'm just too lazy to fix right now ;-)

>>> After all, array concatenation is conceptually nothing like "and"
>>> or "add".
>> 
>> Well, yes, if you think that & is bitwise and.
> 
> Even if you think of & as a logical and, it still doesn't imply 
> concatenation.

No, I've been thinking of it as concatenation :-)

>> I recall & being used as concatenation operator, and * for set
>> intersection (which is the proper semantics of bitwise and, and
>> indeed has analogies with multiplication).
> 
> None of the existing C or C++ operators makes any logical sense for 
> concatenation. That's why D uses a new one.

Indeed. I just wanted to say that & would be a good choice since it's
used for concatenation in other languages, except that & already has a
different meaning in C-style languages (and the same goes for ".").

Regards,
Jo
0
jo427 (1164)
6/6/2005 9:42:42 PM
Joachim Durchholz <jo@durchholz.org> writes:
>The 
>standard strategy for compiling FPLs nowadays seems to be machine code 
>generation.

That depends on what you intend "nowadays" to mean. I see plenty of systems
using both approaches.

>Contrary to popular belief, C is not a good portable assembler.

It is clear that C is not a perfect portable assembler, and equally clear
that it is at least an adequate portable assembler for many purposes.

However, that is not the actual question. The actual question is: is it
better to generate C than to generate assembler?

The advantages of generating assembler:

	speed
	possibly size
	direct access to all hardware features (not usually very important)
	control over low level details; e.g. can generate map from function
		names to locations for a specialized debugger

The advantages of generating C:

	portability (significant even today, as the lack of x86-64 code
		generators for languages that target assembler demonstrates;
		may not be very significant in a few years)
	don't have to write the parts of the compiler that are very close
		to the metal (instruction selection, exploiting pipelining,
		register allocation etc); important since the "metal" (the
		chip microarchitectures) are constantly changing
	don't have to write the parts of the compiler that work with the linker
		(don't have to even know what the object file format is)
	can exploit existing infrastructure for debugging generated code
		when debugging the compiler
	even easier to create interoperability with C code

Which you choose depends on your objectives and limitations.

How great the speed of advantage of assembler is depends on how much effort
you put into the code generator that generates assembler. If you do a minimum
job, it is very likely that generating C will yield faster code. The lack
of tail call optimization in C need not be a problem. It is easy to compile
tail recursion into while loops, only slightly harder to compiler mutual tail
recursion into while loops, and one can avoid mapping calls in the source
language into calls in C by using GNU C extensions (taking the addresses
of labels).

Zoltan Somogyi <zs@cs.mu.OZ.AU> http://www.cs.mu.oz.au/~zs/
Department of Computer Science and Software Engineering, Univ. of Melbourne
0
zs22 (13)
6/8/2005 8:46:38 AM
Zoltan Somogyi wrote:
> 
> 	direct access to all hardware features (not usually very important)

Such access can be important e.g. for implementing overflow checks 
efficiently etc., or in the same vein, optimised representations for 
infinite precision integers, as we have been discussing.

> The lack
> of tail call optimization in C need not be a problem. It is easy to compile
> tail recursion into while loops, only slightly harder to compiler mutual tail
> recursion into while loops, and one can avoid mapping calls in the source
> language into calls in C by using GNU C extensions (taking the addresses
> of labels).

Right, but this still means that general tail calls cannot be 
implemented in Standard C. Moreover, the GCC label trick requires coding 
up your own parameter passing, stack management and register allocation, 
effectively giving up the most important advantages of using an 
intermediate compiler. It is also likely to be less efficient (and 
tuning it will again be highly platform-specific). And how good does it 
scale to separate compilation?

But of course, there is C--, which addresses all these deficiencies.

Cheers,

   - Andreas

-- 
Andreas Rossberg, rossberg@ps.uni-sb.de

Let's get rid of those possible thingies!  -- TB
0
rossberg (600)
6/8/2005 11:21:50 AM
"Zoltan Somogyi" <zs@students.cs.mu.OZ.AU> wrote in message
news:42a6b06b$1@news.unimelb.edu.au...
> The advantages of generating assembler:
>
> speed
> possibly size
> direct access to all hardware features (not usually very important)
> control over low level details; e.g. can generate map from function
> names to locations for a specialized debugger

You forgot a few

1) Proper tail recursion, and some langauges require this.
2) Compatability with the garbage collection system. Some garbage collection
systems require particular stack layouts and particular use of registers.
3) Maintanence of other invariants that are needed for the runtime system.
(e.g. exception handling). I know of at least one system where they manage
to maintain these invaraints using C, but only when all compiler
optimazations (and I mean ALL) are turned off.
4) Handling of optional parameters, keyword parameters, and other types of
parameters that C doesn't have.

Some stuff I don't know about, but I guess are tricky in C.
Full closures, though I guess with enough pointers you can get around this.
Coroutines (longjump? How do you maintain the multiple stacks? Does PORTABLE
C support this?)

Rene.


0
6/8/2005 11:26:31 AM
Zoltan Somogyi <zs@students.cs.mu.OZ.AU> writes:

> The lack of tail call optimization in C need not be a problem.
> It is easy to compile tail recursion into while loops, only slightly
> harder to compiler mutual tail recursion into while loops, and one
> can avoid mapping calls in the source language into calls in C by
> using GNU C extensions (taking the addresses of labels).

I wouldn't know how to do separate compilation and indirect jumps
using addresses of labels.

Here is what my compiler is doing (the design is based on GHC):

The portable version uses the well known trampoline trick, where each
function returns a function pointer which it wishes to jump to, and a
central interpreter loop repeatedly calls a function, then its result
etc. until exited by longjmp.

Then on selected platforms (x86 and x86_64) a Perl script translates
the assembler output of the C compiler, and converts returning a
function pointer into a direct jump (this is not always trivial,
e.g. jumps into a common epilogue are replaced with duplicated code).
Such jumps are marked by a comment in inline asm so the Perl script
can distinguish them from other function returns.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/8/2005 11:36:37 AM
"Rene de Visser" <Rene_de_Visser@hotmail.de> writes:

> 1) Proper tail recursion, and some langauges require this.
> 2) Compatability with the garbage collection system. Some garbage collection
> systems require particular stack layouts and particular use of registers.
> 3) Maintanence of other invariants that are needed for the runtime system.
> (e.g. exception handling). I know of at least one system where they manage
> to maintain these invaraints using C, but only when all compiler
> optimazations (and I mean ALL) are turned off.
> 4) Handling of optional parameters, keyword parameters, and other types of
> parameters that C doesn't have.

This can all be implemented portably in C; I've done this. C can be
used as an assembler.

> Some stuff I don't know about, but I guess are tricky in C. Full
> closures, though I guess with enough pointers you can get around
> this. Coroutines (longjump? How do you maintain the multiple stacks?
> Does PORTABLE C support this?)

Managing our own stack solves many problems at once: finding pointers
for GC, exception handling, threads, stack reallocation on overflow.
It includes a constant cost (e.g. the stack pointer is in a global
variable instead of a physical register), but it's worth the effort
if we want a language which does things C cannot do well directly,
like the above.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/8/2005 12:50:02 PM
Marcin 'Qrczak' Kowalczyk wrote:

> "Rene de Visser" <Rene_de_Visser@hotmail.de> writes:
> 
> 
>>1) Proper tail recursion, and some langauges require this.
>>2) Compatability with the garbage collection system. Some garbage collection
>>systems require particular stack layouts and particular use of registers.
>>3) Maintanence of other invariants that are needed for the runtime system.
>>(e.g. exception handling). I know of at least one system where they manage
>>to maintain these invaraints using C, but only when all compiler
>>optimazations (and I mean ALL) are turned off.
>>4) Handling of optional parameters, keyword parameters, and other types of
>>parameters that C doesn't have.
> 
> This can all be implemented portably in C; I've done this. C can be
> used as an assembler.

You have my unlimited adoration :-)

However, having to live with C's restrictions imposes design constraints 
on an already (usually) over-constrained system. Having too many goals 
usually ends up with achieving none in a satisfactory fashion.

>>Some stuff I don't know about, but I guess are tricky in C. Full
>>closures, though I guess with enough pointers you can get around
>>this. Coroutines (longjump? How do you maintain the multiple stacks?
>>Does PORTABLE C support this?)
> 
> Managing our own stack solves many problems at once: finding pointers
> for GC, exception handling, threads, stack reallocation on overflow.
> It includes a constant cost (e.g. the stack pointer is in a global
> variable instead of a physical register), but it's worth the effort
> if we want a language which does things C cannot do well directly,
> like the above.

Yup. Not relying on C's stack seems to solve most problems. At the 
expense of some additional overhead.

However, what I had in mind were other things, most notably C's overflow 
behavior. There's no way to efficiently check for integer overflow in C, 
and it's indispensable if you want reliability of any kind.

Of course, instead of compiling to machine code, it may be easier to 
simply require an assembly-language integer package that's linked to the 
C code.
.... oops, I should write while thinking. I'm not sure whether C 
compilers can inline assembly modules. Probably they can't, in which 
case the function call overhead is rather prohibitive. (OTOH one could 
do everything with GMP and ignore the overhead. We're not after speed 
when compiling to C...)

Regards,
Jo
0
jo427 (1164)
6/8/2005 8:16:18 PM
Joachim Durchholz <jo@durchholz.org> writes:

> However, what I had in mind were other things, most notably C's
> overflow behavior. There's no way to efficiently check for integer
> overflow in C, and it's indispensable if you want reliability of any
> kind.

This doesn't generate optimal code but I don't know any better
portable way (it assumes two's complement arithmetic and should better
be compiled with -fwrapv on new gcc):

   small = x + y;
   return (~(x ^ y) & (small ^ x)) >= 0) ? small : add_to_bignum(x, y);

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/8/2005 8:53:58 PM
Andreas Rossberg <rossberg@ps.uni-sb.de> writes:
>Zoltan Somogyi wrote:
>> 	direct access to all hardware features (not usually very important)

>Such access can be important e.g. for implementing overflow checks 
>efficiently etc., or in the same vein, optimised representations for 
>infinite precision integers, as we have been discussing.

Which is why I wrote "not usually very important" instead of "not important".

>Moreover, the GCC label trick requires coding 
>up your own parameter passing, stack management and register allocation, 
>effectively giving up the most important advantages of using an 
>intermediate compiler.

It gives up some of the advantages. I have found the remaining advantages
to be sufficient to still choose to generate C.

> It is also likely to be less efficient (and 
>tuning it will again be highly platform-specific).

I conceded up front that assembler is likely to be somewhat faster in raw
speed. However, the time you save not having to write a pipeline scheduler
can be used to implement higher level optimizations.

Only a small fraction of all the optimizations in the Mercury compiler
do stuff that the C compiler would also do. Short circuiting jumps and
peephole optimization are the main ones, and they mostly work at a higher
level than C could. There is only one optimization that is at all platform
specific: it generates code that runs faster on machines with delayed jumps,
such as SPARC. The module that implements it is a whopping 81 lines in length,
including comments.

It has been a long time since I have looked at the assembly code generated
by the C compiler for code that was originally Mercury. The reason for that
is that when I did, I didn't see any room for speeding it up by more than
about 10%-15% in the general case, and that only by essentially implementing
the back end of a conventional compiler. (There was one big exception to this:
code that handles floating point. However, that has never been very important
to us.) Now that we use mostly x86s, which are register starved, the possible
gains would be significantly higher, but unfortunately so would the costs :-(

>And how good does it 
>scale to separate compilation?

In the case of Mercury, perfectly. The Mercury compiler has about 300 modules,
so it better :-)

>But of course, there is C--, which addresses all these deficiencies.

It didn't exist for many years after we started working on Mercury.

Zoltan Somogyi <zs@cs.mu.OZ.AU> http://www.cs.mu.oz.au/~zs/
Department of Computer Science and Software Engineering, Univ. of Melbourne
0
zs22 (13)
6/9/2005 5:22:25 AM
"Rene de Visser" <Rene_de_Visser@hotmail.de> writes:
>> The advantages of generating assembler:
>>
>> speed
>> possibly size
>> direct access to all hardware features (not usually very important)
>> control over low level details; e.g. can generate map from function
>> names to locations for a specialized debugger

>You forgot a few

>1) Proper tail recursion, and some langauges require this.

Not an advantage of assembler, since you can also provide the same guarantees
if you generate C. You may have to work a bit harder.

>2) Compatability with the garbage collection system. Some garbage collection
>systems require particular stack layouts and particular use of registers.
>3) Maintanence of other invariants that are needed for the runtime system.
>(e.g. exception handling). I know of at least one system where they manage
>to maintain these invaraints using C, but only when all compiler
>optimazations (and I mean ALL) are turned off.

These are the kinds of things I meant by "control over low level detail".

>4) Handling of optional parameters, keyword parameters, and other types of
>parameters that C doesn't have.

If you don't map calls in the source language to calls in C this is not
a problem. Remember, you don't have to generate idiomatic C; you can generate
assembler in C syntax.

Zoltan Somogyi <zs@cs.mu.OZ.AU> http://www.cs.mu.oz.au/~zs/
Department of Computer Science and Software Engineering, Univ. of Melbourne
0
zs22 (13)
6/9/2005 5:25:41 AM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:
>> The lack of tail call optimization in C need not be a problem.
>> It is easy to compile tail recursion into while loops, only slightly
>> harder to compiler mutual tail recursion into while loops, and one
>> can avoid mapping calls in the source language into calls in C by
>> using GNU C extensions (taking the addresses of labels).

>I wouldn't know how to do separate compilation and indirect jumps
>using addresses of labels.

We have been doing it for ten years. You generate assembler code in labeled
blocks, and don't worry too much about which labels go in which function.
(It doesn't matter, except for C compilation speed, since you also generate
code that never accesses any variables local to the C function it is in.)
Next to every local label, you add a piece of assembly code that takes the
label name, creates a global variant of the name (we do it by sticking
something like "_entry_mercury" at the front) and provides a .globl
pseudo-op for that label. This allows code in other modules to refer
to the label as long as they follow the same algorithm for computing
its global name.

There is a significant amount of trickery that you have to have with this,
whose main aim is to make sure that the C compiler doesn't believe it can
optimize away any of the functions that are never called or any of the code
inside functions that don't have local gotos jumping to them.

If you can't generate .globl pseudo-ops, you can associate a global variable
with each label, and have an initialization pass that invokes a function in
each module, which assigns the addresses of the labels in that module to the
corresponding variables.

There is a layer of macros in the Mercury runtime that hides the choice
between three techniques for implementing gotos: these two, and the
"return to a driver function" model you mention below. Its implementation
takes maybe 500 lines. The rest of the system doesn't need to know which
method is being used; it works only at or above the level of the macros.
(The one exception I recall is the foreign language interface.)

For more information, see "Compiling logic programs to C using GNU C as a
portable assembler", available from the URL

	www.cs.mu.oz.au/research/mercury/information/papers.html

Its first author, Fergus Henderson, implemented most of this ten years ago.
It has been very stable. The only time I remember touching these macros
in the last five years was when gcc 3.4 came out. It was a bit more agressive
about deleting apparently unreachable functions than 3.3, so I had to make
their actual reachability apparent to gcc. It took only a couple of hours.

>Here is what my compiler is doing (the design is based on GHC):

>The portable version uses the well known trampoline trick, where each
>function returns a function pointer which it wishes to jump to, and a
>central interpreter loop repeatedly calls a function, then its result
>etc. until exited by longjmp.

Mercury can do that too, on machines that don't have compilers that
support gcc extensions to C. This technique (without the edited assembler
trick) loses a factor of 2 in speed compared to the faster method described
above.

>Then on selected platforms (x86 and x86_64) a Perl script translates
>the assembler output of the C compiler, and converts returning a
>function pointer into a direct jump (this is not always trivial,
>e.g. jumps into a common epilogue are replaced with duplicated code).
>Such jumps are marked by a comment in inline asm so the Perl script
>can distinguish them from other function returns.

This technique predates Haskell. The NU-Prolog system used it in 1986,
and I bet it wasn't new then.

Zoltan.
0
zs22 (13)
6/9/2005 5:55:43 AM
Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:
>It includes a constant cost (e.g. the stack pointer is in a global
>variable instead of a physical register),

With GNU C extensions, a few global variables can BE in physical registers.
Even on the x86, on which the Mercury implementation stores only two abstract
machine registers in real machine registers (to leave the rest to the C
compiler), the stack pointer is one of them.

Zoltan.
0
zs22 (13)
6/9/2005 5:59:08 AM
Zoltan Somogyi <zs@students.cs.mu.OZ.AU> writes:

>>I wouldn't know how to do separate compilation and indirect jumps
>>using addresses of labels.
>
> We have been doing it for ten years. You generate assembler code in labeled
> blocks, and don't worry too much about which labels go in which function.

What if different functions need different stack frame sizes? What if
some of them save callee-saved registers on the stack and others don't?

> With GNU C extensions, a few global variables can BE in physical registers.

I tried that, but:

- there are too many interesting virtual registers and too few
  physical registers on x86 (I pass up to 5 arguments in virtual
  registers, the return address is another)

- different libraries which use this approach can't be used together

- if many physical registers are taken out, gcc sometimes is unable to
  compile code

- performance savings were quite small (about 10% if I remember)

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
0
qrczak (1266)
6/9/2005 12:02:38 PM
I wrote:
>> We have been doing it for ten years. You generate assembler code in labeled
>> blocks, and don't worry too much about which labels go in which function.

Marcin 'Qrczak' Kowalczyk <qrczak@knm.org.pl> writes:
>What if different functions need different stack frame sizes? What if
>some of them save callee-saved registers on the stack and others don't?

The stack that the code inside these functions store their information on
is not the C stack; it is a stack under our control, which is a C array
pointed to by a global variable. None of the functions ever store anything
on the C stack, except in two circumstances. First, the C compiler may
decide that some local expression is so complex it needs to spill some
registers. Second, in a few cases the generated C code refers to local
variables declared in small scopes. These are intended to be variables
for the C compiler to map to registers, but some of these may also be
spilled. (Their lifetime never goes beyond the next nonlocal goto.)

Accommodating these spills imposes a few requirements on the C function
that starts the Mercury abstract machine, and whose stack frame is
therefore shared by all these pieces of code. It does not expect any
of its local variables to survive having its frame being shared, and
the local variables include an array that forces the size of the stack frame
to be quite big (1 Kb if I remember). Since the size of the expression
that needs N bytes of spill is exponential in N, any invocation of the C
compiler that finds an expression that requires 1 Kb of spilled registers
will probably take days to execute and/or run out of swap space. Just
to be sure, we have a sanity check that tests whether an integer beyond
this array has been clobbered; I don't remember it ever having been
triggered after the initial debugging of this part of the Mercury
runtime system.

>> With GNU C extensions, a few global variables can BE in physical registers.

>I tried that, but:

>- there are too many interesting virtual registers and too few
>  physical registers on x86 (I pass up to 5 arguments in virtual
>  registers, the return address is another)

We started this work on SPARC and MIPS CPUs, on which we could use about
eight real machine registers. The payoff was of course higher. However,
when we instrumented every reference to an abstract machine register with a
counter, we found that the two most frequently used abstract machine
registers, the stack pointer and the return address register, account for
44% of all abstract machine register references. So we get close to half
the available benefit even with two real machine registers. Your mileage
of course will vary.

>- different libraries which use this approach can't be used together

Different libraries generated by the same language implementation can
of course be used together. If you are talking about two different language
implementations both claiming the same real register, it can still
be handled with appropriate code at the interface between them. Save the
registers to one language's backing store (some global variables), restore
the registers from the backing store of the other. Do the reverse when
returning.

>- if many physical registers are taken out, gcc sometimes is unable to
>  compile code

Gcc has indeed had some bugs along these lines. Sometimes it wants to use
hand-written (by the gcc folks) assembler code for some primitive operations
such as strcpy, sometimes these primitives want to use registers we have
reserved for global variables, and sometimes gcc doesn't notice the conflict
until too late. We have reported some such bugs; they have either been fixed
or we developed workarounds.

>- performance savings were quite small (about 10% if I remember)

The benchmark results on the SPARC and MIPS machines we did about
a decade ago showed that using 8 or so machines registers to store
abstract machine registers gave a speed improvement of about a factor of 2.
Adding nonlocal gotos as well raised this to a factor of 3.
Definitely worthwhile.

Zoltan Somogyi <zs@cs.mu.OZ.AU> http://www.cs.mu.oz.au/~zs/
Department of Computer Science and Software Engineering, Univ. of Melbourne
0
zs22 (13)
6/10/2005 7:52:53 AM
Reply: