www.digitalmars.com         C & C++   DMDScript  

D - initial reaction to D

reply "D. Hugh Redelmeier" <hugh mimosa.com> writes:
A friend asked me what I thought of D.  Here is my initial reaction.  It 
is *not* based on a careful reading of all available material -- I've 
only read the introduction and FAQ.

Many nice refinements to c/c++.  I'll concentrate on what I don't
like or have concerns about.

- in switch, cases fall through.  Very inhumane (my term for bad human
   engineering).

- printf exists -- a good type system would not allow it

- requiring heap allocation of objects is over-specified -- ought to
   be an implementation decision.  Besides, it is useful to support
   boxed and unboxed objects.  Clearly unboxed objects might have
   additional restrictions.

- C declaration syntax is "inside out" and unnatural -- it should
   have been ditched

- Pascal subranges are powerful and should be supported.  Specifying
   size of integer types any other way is crude.

- Some C source files provide more than one interface.  This ability
   is probably lost in D.

- There is no single optimal string abstraction.  But D must have
   chosen one.  I don't know which one was chosen, but there is a
   great chance that I'd not like it.

- more expressive declarations about parameters would be good.  For
   example, it would be nice to know whether a parameter ever has its
   address preserved beyond the call.  Perhaps this can be derived --
   after all, the declaration of the function is automatically computed
   from the definition.

- With no separate .h files, make is likely to do too much recompiling
   For example consider a file a.d that uses things provided by b.d.
   The make dependency would be expressed in a way that requires a.d to
   be recompiled whenever b.d is changed, even if b.d's interface isn't
   changed.  In c, this is handled by separating the .h and .c.  If
   make were smarter, an interface description could be automatically
   generated for b.d, and only if it differed from the previous one
   would recompilation of a.d be triggered.  I see this as a weakness
   of make, but d is claimed to be suitable for make.

- how do circular dependencies between files get sorted out?  If a.d
   needs b.d and b.d needs a.d, there appears to be a chicken-and-egg
   problem.  In C, this must be sorted out by the programmer when
   crafting .h and #includes.

- How does separate compilation work?  In C, .h files are an important
   part of this.

- The concept of "uniform referents" is not reflected in the language
   design.  There is no good reason for function call to use different
   notation from subscripting and there are good reasons for them to be
   the same.  C followed B where they had to be different because the
   language was typeless.

- the intro seems to imply that for (;;) is gone.  Why?

- there are a couple of features of Dijkstra's notation from "A
   discipline of programming" that would be nice

   + a static way of avoiding/detecting uninitialized variables

   + (related, interestingly enough) a more general and convenient
     set of array operations.  They only become possible because
     arrays are now first class types (with bounds).  Perhaps
     these arrays become pleasant for holding strings.

     In C, arrays are more of a memory allocation technique than
     a data structure.
Aug 28 2001
next sibling parent reply Erik Rounds <erikr aatrix.com> writes:
Well, you really should read more of the language documentation as some of
your assumptions about the language are unfounded.  On the other hand you do
have a few good points too.


 - in switch, cases fall through.  Very inhumane (my term for bad human
    engineering).
The reason switches fall through is because that is the behaviour that switches have in C. The author is concerned that if switch is included in the language with only small changes, it would be difficult to detect bugs from old software related to those changes. Personally, I agree though - not falling through should be the default condition.
 - printf exists -- a good type system would not allow it
I wonder if a typesafe printf is feasible??? Like have compile-time checking of types printf("%d - %d",1,3.0) // Runtime detected error - parameter 2 needs casting and perhapse it could be passed objects (instances of classes) whch implement some Printable interface ( have a ToString method). Like: PrintableClass MyObject = new MyObject(); printf("ToString() = %o\n",MyObject); Just some ideas.
 - Pascal subranges are powerful and should be supported.  Specifying
    size of integer types any other way is crude.
I sort of agree, but doesn't that incur some sort of performance hit?
 - There is no single optimal string abstraction.  But D must have
    chosen one.  I don't know which one was chosen, but there is a
    great chance that I'd not like it.
The string in D is a character array, just like C. The difference is that static arrays in D have an operator that returns the size of the array.
 - With no separate .h files, make is likely to do too much recompiling
    For example consider a file a.d that uses things provided by b.d.
    The make dependency would be expressed in a way that requires a.d to
    be recompiled whenever b.d is changed, even if b.d's interface isn't
    changed.  In c, this is handled by separating the .h and .c.  If
    make were smarter, an interface description could be automatically
    generated for b.d, and only if it differed from the previous one
    would recompilation of a.d be triggered.  I see this as a weakness
    of make, but d is claimed to be suitable for make.
 - how do circular dependencies between files get sorted out?  If a.d
    needs b.d and b.d needs a.d, there appears to be a chicken-and-egg
    problem.  In C, this must be sorted out by the programmer when
    crafting .h and #includes.

 - How does separate compilation work?  In C, .h files are an important
    part of this.
Although they don't actually come out and say it in the FAQ or documentation, header files are being supported, although they are not required. The include statement and text-based inclusion are not being used in D. In fact, the preprocessor will not be used at all. To use a file, import it with the import directive. When a D file is first compiled, a symbol table is formed and that is what gets imported rather than having the text from the header file be inserted into the source verbatum. Anyway, that's what I have been able to piece together from the documentation and some conversations here in the newsgroup. Thanks for your opinions though!
Aug 28 2001
parent reply Russ Lewis <russ deming-os.org> writes:
Erik Rounds wrote:

 I wonder if a typesafe printf is feasible???
We've been discussing that in the thread "typesafe printf". There are at least two reasonable alternatives out there that don't require runtime type identification of the arguments or using wrappers on fundamental types.
 - There is no single optimal string abstraction.  But D must have
    chosen one.  I don't know which one was chosen, but there is a
    great chance that I'd not like it.
The string in D is a character array, just like C. The difference is that static arrays in D have an operator that returns the size of the array.
Also remember that they are not null terminated (don't need to be, since they have a size parameter).
 - With no separate .h files, make is likely to do too much recompiling
    For example consider a file a.d that uses things provided by b.d.
    The make dependency would be expressed in a way that requires a.d to
    be recompiled whenever b.d is changed, even if b.d's interface isn't
    changed.  In c, this is handled by separating the .h and .c.  If
    make were smarter, an interface description could be automatically
    generated for b.d, and only if it differed from the previous one
    would recompilation of a.d be triggered.  I see this as a weakness
    of make, but d is claimed to be suitable for make.
AS I UNDERSTAND IT: Several D modules (.d files) are processed at once to create a single .o file or executable. If you want to declare an interface to import but you don't want to give the implementation in that object file, create an interface module that only declares the functions, not defines them. foo.d // contains all code for foo library.int.d // contains interface to library library.d // contains code for library. foo.d imports library.int.d; together they are built into foo.o library.d builds into library.o foo.o and library.o are linked together to produce the foo executable.
 - how do circular dependencies between files get sorted out?  If a.d
    needs b.d and b.d needs a.d, there appears to be a chicken-and-egg
    problem.  In C, this must be sorted out by the programmer when
    crafting .h and #includes.
Like in Java, D processes all currently available modules in one pass. Order of declaration is not important, so forward declarations are never used. struct Foo { Bar *bar; // legal...D looks ahead (or into the other module) and sees that Bar will be declared later }; struct Bar { Foo *foo; }; Thus, there are no C-style header dependencies.
Aug 28 2001
parent "Walter" <walter digitalmars.com> writes:
Russ Lewis wrote in message <3B8BD2E1.CA1850D9 deming-os.org>...
Also remember that they are not null terminated (don't need to be, since
they
have a size parameter).
I was initially reluctant to drop the null termination, but I since discovered that so many things just get nicer without the null.
Several D modules (.d files) are processed at once to create a single .o
file or
executable.  If you want to declare an interface to import but you don't
want to
give the implementation in that object file, create an interface module
that
only declares the functions, not defines them.

foo.d    // contains all code for foo
library.int.d  // contains interface to library
library.d // contains code for library.

foo.d imports library.int.d; together they are built into foo.o
library.d builds into library.o
foo.o and library.o are linked together to produce the foo executable.
I haven't yet decided if interface files should have a different extension.
Like in Java, D processes all currently available modules in one pass.
Order of
declaration is not important, so forward declarations are never used.
Yes.
Thus, there are no C-style header dependencies.
Yes.
Aug 28 2001
prev sibling parent "Anthony Steele" <asteele nospam.iafrica.com> writes:
 - Pascal subranges are powerful and should be supported.  Specifying
    size of integer types any other way is crude.
I have done a lot of pascal (Delphi) and I can't say that I use them at all. Enums (ans sets of enuyms) are nice though.
 - There is no single optimal string abstraction.  But D must have
    chosen one.  I don't know which one was chosen, but there is a
    great chance that I'd not like it.
Or go the C/C++ route, don't provide any standard one, and frustrate everyone with incompatibilites?
 - how do circular dependencies between files get sorted out?  If a.d
    needs b.d and b.d needs a.d, there appears to be a chicken-and-egg
    problem.  In C, this must be sorted out by the programmer when
    crafting .h and #includes.
The java compiler handles this with no fuss at all. But then Java allows forward refs as long as they are resolved eventually. Anthony
Aug 30 2001