Re: is LISP the ultimate prgram language?
On Oct 22, 6:13 pm, Keith H Duggar <dug...@alum.mit.edu> wrote:
On Oct 21, 11:47 am, James Kanze <james.ka...@gmail.com> wrote:
On Oct 21, 3:51 pm, Keith H Duggar <dug...@alum.mit.edu> wrote:
On Oct 21, 4:22 am, James Kanze <james.ka...@gmail.com> wrote:
On Oct 20, 8:19 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
If you have, for example, a vector of ints, where each int
is a full-fledged object (in other words, some of the ints
could actually be objects derived from an int), then I
don't think the compiler has any way of optimizing dynamic
binding checks away. It cannot prove that none of the ints
in the array are objects derived from int.
It can, and some do. Obviously, it's harder for the
compiler than optimizing around std::vector, but then,
optimizing around std::vector is harder for the compiler
than optimizing around Fortran style arrays. (C-style
arrays are a problem for the compiler, because they end up
being pointers.)
And what would you replace this C-style array "problem" with?
Make arrays first class types, behaving as any other type.
As in make them std::vector? Why isn't that better done at the
library level as has already been done (in multiple different
ways to meet different needs)?
That's what was decided, but there are still repercusions.
There's no way you can create an std::vector with static
initialization, for example, and the initialization syntax isn't
the same. (The committee is working on the latter.)
In other words, how would you implement iterators for C-style
array sequences?
The same way you implement them for any other container. For
that matter, you usually inhibit the convertion of array to
pointer (by using pass by reference) when you want "iterators"
for C style arrays, using something like:
template< typename T, size_t n >
T*
end( T (&array)[ n ] )
{
return array + n ;
// or return &array[0] + n, if there was no conversion,
// or just something like
// return array.end(), if the language were defined
// thusly.
}
Basically, you block the conversion because it involves loss
of important information concerning the type, mainly how
many elements the array contains.
So your chief complaint is that information about the size of
the array is lost?
Not only, with regards to C style vectors. My chief complaint
is that they follow completely different rules than other types
of objects. The decision to use pass by reference, rather than
the usual pass by value, should be made by the programmer. (And
yes, in both cases, length information should be preserved.)
Ok then I'm a bit confused because you also mentioned Fortran
as an example of a language that does not have C's "problem"
however Fortran also discards size information and it must be
passed in as additional parameters (or otherwise known).
Agreed, and now that I think of it, I'm not sure that Fortran is
a good example; Fortran's arrays don't convert to pointers,
which can then be abused, but you can't (or at least, you
couldn't when I used Fortran) assign an array to another array.
(It's hard to compare Fortran, of course, because it never uses
pass by value.)
The point is that objects in C++ have a specific behavior: this
holds for the basic types, for pointers, for structs, and in
fact, for every object type except arrays. (By default, anyway.
In C++, you can replace that behavior, at least in part, by
overloading operators and defining a copy and a default
constructor.) That default behavior includes things like copy
and assignment.
Do you have a link to a proposal for C++ or examples of
languages that "do it right" and support Stepanov iterator
concepts as C++ does?
The STL has been implemented in Ada. The problems doing so
had nothing to do with arrays; the problems had to do with
the fact that Ada's generics work somewhat differently than
those in C++.
Ok so you would happy if built-in arrays were instead
std::vector? Ie a class with some interface to the size in
this case .size(), .begin(), etc just like the standard
interface that Ada offers to array types (First, Last, etc)?
That would be one solution. There are many. All I really
insist on is that arrays work like any other type---a struct
doesn't implicitly convert to a pointer to its first element in
just about any context; nor should an array. And of course, as
a side effect, indexation would be indexation, and not pointer
arithmetic.
Doing this does allow carrying the size around, so you could
then add all of the advantages that allows (like efficient
bounds checking). But that's really a second point---important,
but not as primordial as the first.
So then what would the type of "new T[]" and the return type
of malloc(sizeof(T)*N) be? std::vector<T>?
The return type of new T should be T*, for *all* T. Not just
for the cases where T is not an array. That's really part of
what I'm complaining about: it's totally abherant that the
return type of new int and new int[n] be the same. And that you
have to use a different form of delete on them, because the
original type has been lost.
requiring a separate object to contain all of the necessary
information, when you could put all the information in a
single object, resulting in a more powerful and simpler to
use abstraction.
That really is a separate and large topic.
Agreed. But anyone who's worked with complex iterators to any
extend (filtering iterators, etc.) realizes what a pain it is
not being able to know the end from within the iterator. And
anyone who makes use of extensive functional decomposition with
e.g. one function determing the range, and another function
iterating over it, has suffered from the fact that you need two
separate objects to define the range.
You would certainly have trouble justifying in absolute the
"all information", "more powerful", and "simpler to use"
claims.
Not in the least.
You could look to the recent debates stirred up by Andrei's
"iterators must go" range advocacy to see many cogent
arguments against your view above.
I don't think there is any sense in opening that debate here;
but, I would like to know do you advocate "range" concepts a
la Andrei (for generalizing sequences I mean) or something
else?
Not having seen what Andrei is advocating, I don't know. But it
should only take one object in order to iterate, since a
function can only return a single object to be used as a single
argument to another function.
--
James Kanze