www.digitalmars.com         C & C++   DMDScript  

D - Ideas, thoughts, and criticisms, part one

reply Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari cc.hut.fi> writes:
(Contents: praise, general issues, questions, "switch" statement and
nested comments raised from the dead, a terminology note and an idea of
explanative annotations in the "D" web reference. At least.)

Hello,

I've dreamt about designing a language like "D" lately - a language
which would

- fix the shortcomings of C without sacrificing its efficiency
- have good OO support, as well as support for useful object-oriented
  facilities such as contracts and assertions, and finally,
- have support for extensive metaprogramming facilities. ("Better
  macros" if you will.)

Now, I only needed the name for the language -- maybe "D" could be it?
I decided to check if there already was a language called D. Darn
indeed, there was. And it already had some of the things that I had
mind. Now that's convenient :-)

Ok, I read through the specification and I can say that I'm fairly
impressed - the language seems quite well thought out.

Things that were especially heart-warming were:

- properties like .size sounds like a lot cleaner version of sizeof,
  without cluttering the global namespace with keywords. Very good.

- contracts - oh yes! :)

- delegates - for someone trying to do this (an object which has a
  function reference and an object reference, and can be called) with
  C++, this is just brilliant.

- using .cmp() to implement comparison operators which in C++ are tedious
  or require template hackery. Cool.

More detailed feedback on all kinds of things, including but not limited
to (hopefully constructive!) critique, general ideas, feature
suggestions and detailed, annoying nitpickery, in no particular order,
follows.  There are quite a few references of the form "author:title",
which I have included at the end of the message.  The html files I
mention are taken relative to http://www.digitalmars.com/d/.


First of all, it is stated in overview.html:
	Modern compiler technology has progressed to the point where
	language features for the purpose of compensating for primitive
	compiler technology can be omitted.
Keeping this in mind, what would the function calling conventions be?

The C calling convention is to pass everything in the stack. Microsoft
uses a similar convention for Win32 functions with little changes
(msdn:calling_conventions) and they also have a __fastcall calling
convention, which passes values in the registers. Certainly passing
values in registers sounds fast and something you would like to do on a
modern system. So, what are the calling conventions used in D? They
are on their way to being standardized, right?


overview.html:
Who D is Not For:
	* Real time programming where latency must be guaranteed.
[and regarding other low-level tasks]

Do, for instance, operating system writers belong into the "Not For"
category?  Could D be used *without* garbage collection for real-time
and low-level tasks? Or just because someone doesn't like it? I don't
see why anyone should be _prevented_ for doing memory management
manually if he so desires, as smart pointers might be quite viable
alternative for that (see boost:smart)

I could see that D would be a nice replacement for C when doing
down-to-the-metal programming. But not if it enforces things like
garbage collection.

(Incidentally, garbage collection might not be *completely* out
regarding operating system kernels - check out russo:garbage)


lex.html:
	Comment:
	/* Characters */
	// Characters EndOfLine
	/+ Characters +/

	D has three kinds of comments: 

	1. Block comments can span multiple lines, but do not nest. 
	2. Line comments terminate at the end of the line. 
	3. Nesting comments can span multiple lines and can nest.

The document doesn't actually state which is which (I assume that /* */
are the non-nesting and /+ +/ are the nesting comments). Why not make it
simpler and just include the normal /* */ and // comments, but so that
/* */ would be nesting? I think this has been done already by some
language. Non-nesting comments are, IMHO, an artifact of the seventies
and should be gotten rid of for good.

Now, the typical argument is that one wants D to be C/C++ compatible -
but this isn't really the case.  I'd say that if there is an opportunity
to fix it, why not fix it?

Is there any C/C++ programmer out there whose code would break if /* and
*/ suddenly started to nest? Would you even notice?  Hands up!  Anyone?


declaration.html:

The idea of breaking free of the C declaration syntax when it comes to
pointers is best thing that happened to imperative programming languages
since the invention of... umm... C. I congratulate thee for that. :-)

However, function pointer declarations are still a bit unclear for my
small mind.  Could you clarify be a bit... how are the function pointers
typedef'd/aliased?

// like in C?
typedef int (*FunctionPointer)(int);
// or like this?
typedef int (*)() FunctionPointer;

By the way, I think that having *both* C and D style definitions (both
"int[3] x" and "int x[3]" work) might be confusing. I'd prefer that
there be exactly one way to do a thing, so nobody would have to think
about which way to do it. Besides, it might make parsing more difficult
(or it might not - I'm not a context-free language expert).

(It's the same case for C++. You can say const int x; or int const x;
and whatever you do, you always confuse someone. That's not nice. Makes
a language seem clumsy and committee-designed.)


A terminology note - "bool" data type in expressions.html:

I take it that bit replaces bool as a data type (since it is not listed
in types.html), and therefore the use of "bool" in file expression.html
(such as "The result type of an AndAnd expression is bool") should be
replaced by "bit". Am I not right?

(Although I'm not sure if you'd want to replace "boolean values" with
"bitean values" ... :-)


Then a little rant about the infamous "switch" behavior:

About C compatibility and especially the switch fall-through behavior:
faq.html:
	Why fall through on switch statements?

	Many people have asked for a requirement that there be a break between
	cases in a switch statement, that C's behavior of silently falling
	through is the cause of many bugs. 

	The reason D doesn't change this is for the same reason that integral
	promotion rules and operator precedence rules were kept the same - to
	make code that looks the same as in C operate the same. If it had subtly
	different semantics, it will cause frustratingly subtle bugs. 

I think one needs to take a new perspective here.

I strongly believe that C compatibility is just not something worth
striving for. Why? There are a couple of reasons. 

The first and foremost reason is:
0. Falling through is a special case you almost never see.  There is
just no point in doing that the default. C designers simply made a
mistake.  Isn't the point of making a new language to fix it?

Besides, good-mannered C programmer will anyway document the
fall-through case with a comment like "/* FALL THROUGH */". Why not make
the documentation part of the language and introduce a keyword
"fallthrough" to document the uncommon case? (or maybe just use
"continue") You have already provided the means to document the code
with assert() and pre- and postconditions - then why not fallthrough, if
it so badly needs documentation?

Because the previous reason is so obvious that everybody has become
blind to it, I'll present some more reasons:

1. Who needs the compatibility? The seasoned C hackers, you say. Not
everybody changes from C or C++ to D. In time, if D turns out to be a
success, we will see people learning D as their first language. And, if
we have the "fall through by default" semantics, they will _certainly_
encounter the mysterious "missing break" bugs C programmers have two
decades' experience of. And, I don't mean just newbies, since:

2. I believe that even seasoned C hackers make "missing break" mistakes.
Frequently. Everyone forgets the "break" from there sometimes. If it
were the other way round, it wouldn't happen. And that, if something,
causes frustratingly subtle bugs, and that will continue to be the case
forever if it doesn't get fixed now.

Question: Why make falling through a special case?

Answer: Because it _can_ _be_. And we can do that without introducing
subtle bugs:

3. The chance of introducing subtle bugs could be minimized by issuing
an error (or possibly a loud warning) for every "break;" encountered
inside the switch statement. (What would the break do there, anyway?)
Now the so-called "subtle" bugs would be introduced only if there were
no "break" statements inside the switch statement, which would
correspond to a rare case like this:

// Assume that the user has copy&pasted this from existing C/C++ code,
// and that we have "don't fall through by default" semantics:
f(int i) {
	switch (i)
	{
	case 1:
		doIfOne();
		// FALL THROUGH (at least the programmer assumed so)
	case 2:
		doIfOneOrTwo();
		// FALL THROUGH (at least the programmer assumed so)
	case 3:
		doIfOneOrTwoOrThree();
		// FALL THROUGH (at least the programmer assumed so)
	default:
		doAlways(); // this could as well be outside the switch
		// statement so there really shouldn't even be a 'default:'
	}
}

Now, this isn't a case you would see every day, and I will even argue
that the bugs caused by this wouldn't be anything, and I mean _anything_
like subtle if the programmer had bothered to test his code even a
_bit_.  There should be a testcase which tests at least f(1), f(3) and
f(98728234).

But on the other hand, if he copy & pasted the snippet from C++ code and
then didn't bother to learn the new rules before starting to program,
and *still* failed to write the decent test cases, he deserves to be
screwed. And we can be happy since bad behavior got rightfully punished.
:-)

Now, the only argument you have on behalf on "fall through by default"
semantics is that Duff's Device (duff:device) relies on it, and you can
fix even that by adding fallthrough/continue keywords in every line of
it. I rest my case.

Finally, a meta-comment about the D reference at
http://www.digitalmars.com/d/:
The reference is in places a bit terse, stating mostly "what" instead of
"why".  For example when it comes to the nesting comments mentioned
earlier. Sometimes there are explanations, but mostly not.

I note that so far I've probably reasked the same questions that have
been asked several times and perhaps already thoroughly discussed in
this newsgroup. I'm sorry if I have done so, but I really haven't had
the time - at least yet :-) - to read all the articles.  I searched the
subjects for the most important keywords I have commented upon, though.

Anyway.

Maybe there is a need for an annotated reference (ā la
stroustrup,ellis:arm, which IMHO is a spendid book), which could include
a brief discussion on _why_ a certain feature is as it is, perhaps
equipped with references and maybe even links to messages in this
newsgroup. Nothing fancy, just the line of thought which has lead to a
certain decision. Of course, I understand that this takes time and
effort and might not be feasible.

Phew. That's enough for now. More will probably follow, in proper time.
I have still things to say at least about functions, data types, and
perhaps something about generics.

I'd be pleased to know what you think about these ideas.  If you feel
some of my suggestions annoying, impossible to implement, or downright
absurd, feel free to express so. Also, being aggressive should be
interpreted as being enthusiastic (you see, I'm young, innocent, and
still learning :-)

Antti.

References:

(boost:smart) http://www.boost.org/libs/smart_ptr/smart_ptr.htm
(russo:garbage) http://citeseer.nj.nec.com/russo91garbage.html)
(duff:device) http://www.lysator.liu.se/c/duffs-device.html
(msdn:calling_conventions)
http://msdn.microsoft.com/library/en-us/vccore98/HTML/_core_argument_passing_and_naming_conventions.asp
(stroustrup,ellis:arm) http://www.research.att.com/~bs/arm.html
Aug 26 2002
next sibling parent reply Pavel Minayev <evilone omen.ru> writes:
On Mon=2C 26 Aug 2002 23=3A57=3A37 +0000 =28UTC=29 Antti Syk=5Fri
=3Cjsykari=40cc=2Ehut=2Efi=3E wrote=3A

=3E modern system=2E So=2C what are the calling conventions used in D=3F They
=3E are on their way to being standardized=2C right=3F
 
The compiler decides calling convention itself for each function=2E It can
decide
to pass some arguments in registers=2C or put everything on stack=2C in any
order - so optimizer can achieve maximum efficiency of function calls=2E

=3E Do=2C for instance=2C operating system writers belong into the =22Not For=22
=3E category=3F  Could D be used *without* garbage collection for real-time
=3E and low-level tasks=3F Or just because someone doesn't like it=3F I don't
=3E see why anyone should be =5Fprevented=5F for doing memory management
=3E manually if he so desires=2C as smart pointers might be quite viable
=3E alternative for that =28see boost=3Asmart=29

You can avoid using GC=2C but then you will have to forget about dynamic arrays 
and
90% of stdlib=2E
 
=3E However=2C function pointer declarations are still a bit unclear for my
=3E small mind=2E  Could you clarify be a bit=2E=2E=2E how are the function
pointers
=3E typedef'd=2Faliased=3F
=3E 
=3E =2F=2F like in C=3F
=3E typedef int =28*FunctionPointer=29=28int=29=3B

Yes=2E

=3E I take it that bit replaces bool as a data type =28since it is not listed
=3E in types=2Ehtml=29=2C and therefore the use of =22bool=22 in file
expression=2Ehtml
=3E =28such as =22The result type of an AndAnd expression is bool=22=29 should
be
=3E replaced by =22bit=22=2E Am I not right=3F

Yes=2C you are right=2E
 
=3E 0=2E Falling through is a special case you almost never see=2E  There is
=3E just no point in doing that the default=2E C designers simply made a
=3E mistake=2E  Isn't the point of making a new language to fix it=3F

I think they made it because it was simplier to implement=2E
 
=3E 3=2E The chance of introducing subtle bugs could be minimized by issuing
=3E an error =28or possibly a loud warning=29 for every =22break=3B=22
encountered
=3E inside the switch statement=2E =28What would the break do there=2C
anyway=3F=29

Break out of the loop=3A

=09=2F=2F auto-breaking on
=09white =28cond=29
=09{
=09=09switch =28x=29
=09=09{
=09=09case 0=3A foo=28=29=3B
=09=09case 1=3A bar=28=29=3B
=09=09case 2=3A break=3B=09=2F=2F break out of while-loop
=09=09}
=09}
Aug 27 2002
parent reply Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari cc.hut.fi> writes:
In article <CFN374955051835069 news.digitalmars.com>, Pavel Minayev wrote:
 The compiler decides calling convention itself for each function=2E It
 can decide to pass some arguments in registers=2C or put everything on
 stack=2C in any order - so optimizer can achieve maximum efficiency of
 function calls=2E

I see, I missed that part in pretod.html. That can be a very clever idea indeed. How about passing the arguments between modules that are compiled separately? Is the calling convention documented in the object file, perhaps? Or maybe it is derivable from the function's signature?
 Break out of the loop?
 
// auto-breaking on
white (cond)
{
    switch (x)
    {
    case 0: foo();
    case 1: bar();
    case 2: break;    // break out of while-loop
    }
}

Of course. Having too much C exposure I didn't assume anyone in their right mind would use break the "wrong" way anymore. Antti.
Aug 27 2002
parent "Walter" <walter digitalmars.com> writes:
"Antti Sykäri" <jsykari cc.hut.fi> wrote in message
news:akh33p$iff$1 digitaldaemon.com...
 How about passing the arguments between modules that are compiled
 separately? Is the calling convention documented in the object file,
 perhaps? Or maybe it is derivable from the function's signature?

It's really up to the compiler system. A D implementation doesn't even require .obj files, it can generate an executable directly. The current implementation, however, adheres to the boring, traditional .obj file method - but it doesn't have to be that way.
Sep 03 2002
prev sibling next sibling parent reply "Sean L. Palmer" <seanpalmer earthlink.net> writes:
I'm all for dropping C compatibility.  If people want to port C code to
Java, they have to make changes.  It's the same with D.  I for one would be
glad to rid myself of the nasty habit of adding break's to cases.  I'm sure
you can already write plenty of D code that looks just like C but works
differently, and you can do the same for Java.  One more won't hurt.

I agree that D has a golden window of opportunity to start the slate off
clean and fresh, and fix C's failings.  There are a whole lot of C
programmers out there that use C, know C, and hate C's failings.  They use
it because there's nothing better.  Not because it's got the really nice
case fallthrough wierdness.

D should be entirely better than C.  In all respects.  Everyone seems to
agree that C's way of doing things is a bug-generating machine.

Besides, once break isn't required by cases, it can be used to break out of
an enclosing loop like it was originally intended (this is how it works in
languages such as Delphi IIRC).

Sean

"Antti Sykäri" <jsykari cc.hut.fi> wrote in message
news:akef9g$gvt$1 digitaldaemon.com...
 Then a little rant about the infamous "switch" behavior:

 About C compatibility and especially the switch fall-through behavior:
 faq.html:
 Why fall through on switch statements?

 Many people have asked for a requirement that there be a break between
 cases in a switch statement, that C's behavior of silently falling
 through is the cause of many bugs.

 The reason D doesn't change this is for the same reason that integral
 promotion rules and operator precedence rules were kept the same - to
 make code that looks the same as in C operate the same. If it had subtly
 different semantics, it will cause frustratingly subtle bugs.

 I think one needs to take a new perspective here.

 I strongly believe that C compatibility is just not something worth
 striving for. Why? There are a couple of reasons.

 The first and foremost reason is:
 0. Falling through is a special case you almost never see.  There is
 just no point in doing that the default. C designers simply made a
 mistake.  Isn't the point of making a new language to fix it?

 Besides, good-mannered C programmer will anyway document the
 fall-through case with a comment like "/* FALL THROUGH */". Why not make
 the documentation part of the language and introduce a keyword
 "fallthrough" to document the uncommon case? (or maybe just use
 "continue") You have already provided the means to document the code
 with assert() and pre- and postconditions - then why not fallthrough, if
 it so badly needs documentation?

 Because the previous reason is so obvious that everybody has become
 blind to it, I'll present some more reasons:

 1. Who needs the compatibility? The seasoned C hackers, you say. Not
 everybody changes from C or C++ to D. In time, if D turns out to be a
 success, we will see people learning D as their first language. And, if
 we have the "fall through by default" semantics, they will _certainly_
 encounter the mysterious "missing break" bugs C programmers have two
 decades' experience of. And, I don't mean just newbies, since:

 2. I believe that even seasoned C hackers make "missing break" mistakes.
 Frequently. Everyone forgets the "break" from there sometimes. If it
 were the other way round, it wouldn't happen. And that, if something,
 causes frustratingly subtle bugs, and that will continue to be the case
 forever if it doesn't get fixed now.

 Question: Why make falling through a special case?

 Answer: Because it _can_ _be_. And we can do that without introducing
 subtle bugs:

 3. The chance of introducing subtle bugs could be minimized by issuing
 an error (or possibly a loud warning) for every "break;" encountered
 inside the switch statement. (What would the break do there, anyway?)
 Now the so-called "subtle" bugs would be introduced only if there were
 no "break" statements inside the switch statement, which would
 correspond to a rare case like this:

 // Assume that the user has copy&pasted this from existing C/C++ code,
 // and that we have "don't fall through by default" semantics:
 f(int i) {
 switch (i)
 {
 case 1:
 doIfOne();
 // FALL THROUGH (at least the programmer assumed so)
 case 2:
 doIfOneOrTwo();
 // FALL THROUGH (at least the programmer assumed so)
 case 3:
 doIfOneOrTwoOrThree();
 // FALL THROUGH (at least the programmer assumed so)
 default:
 doAlways(); // this could as well be outside the switch
 // statement so there really shouldn't even be a 'default:'
 }
 }

 Now, this isn't a case you would see every day, and I will even argue
 that the bugs caused by this wouldn't be anything, and I mean _anything_
 like subtle if the programmer had bothered to test his code even a
 _bit_.  There should be a testcase which tests at least f(1), f(3) and
 f(98728234).

 But on the other hand, if he copy & pasted the snippet from C++ code and
 then didn't bother to learn the new rules before starting to program,
 and *still* failed to write the decent test cases, he deserves to be
 screwed. And we can be happy since bad behavior got rightfully punished.
 :-)

 Now, the only argument you have on behalf on "fall through by default"
 semantics is that Duff's Device (duff:device) relies on it, and you can
 fix even that by adding fallthrough/continue keywords in every line of
 it. I rest my case.

Aug 27 2002
next sibling parent reply Pavel Minayev <evilone omen.ru> writes:
On Tue, 27 Aug 2002 02:04:46 -0700 "Sean L. Palmer" <seanpalmer earthlink.net> 
wrote:

 I'm all for dropping C compatibility.  If people want to port C code to
 Java, they have to make changes.  It's the same with D.  I for one would be
 glad to rid myself of the nasty habit of adding break's to cases.  I'm sure
 you can already write plenty of D code that looks just like C but works
 differently, and you can do the same for Java.  One more won't hurt.

I second that.
 Besides, once break isn't required by cases, it can be used to break out of
 an enclosing loop like it was originally intended (this is how it works in
 languages such as Delphi IIRC).

Yes, exactly. Lots of times I want to break out of the loop conditionally, using switch-statement - but arrgh! goto only...
Aug 27 2002
parent "Walter" <walter digitalmars.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:CFN37495671212963 news.digitalmars.com...
 Yes, exactly. Lots of times I want to break out of the loop conditionally,
 using switch-statement - but arrgh! goto only...

There is the break label; syntax, useful for breaking out of arbitrarilly nested loops.
Sep 03 2002
prev sibling parent reply "Matthew Wilson" <matthew thedjournal.com> writes:
Agree wholeheartedly.

In some ways, making one language appear like another syntactically has the
pitfall of making one think it is alike semantically.

I can remember the first time I realised (in a happiling compiling program)
that Java does not have out-parameters. To say I was disgusted would be
putting it mildly ...


"Sean L. Palmer" <seanpalmer earthlink.net> wrote in message
news:akfeqj$1m32$1 digitaldaemon.com...
 I'm all for dropping C compatibility.  If people want to port C code to
 Java, they have to make changes.  It's the same with D.  I for one would

 glad to rid myself of the nasty habit of adding break's to cases.  I'm

 you can already write plenty of D code that looks just like C but works
 differently, and you can do the same for Java.  One more won't hurt.

 I agree that D has a golden window of opportunity to start the slate off
 clean and fresh, and fix C's failings.  There are a whole lot of C
 programmers out there that use C, know C, and hate C's failings.  They use
 it because there's nothing better.  Not because it's got the really nice
 case fallthrough wierdness.

 D should be entirely better than C.  In all respects.  Everyone seems to
 agree that C's way of doing things is a bug-generating machine.

 Besides, once break isn't required by cases, it can be used to break out

 an enclosing loop like it was originally intended (this is how it works in
 languages such as Delphi IIRC).

 Sean

 "Antti Sykäri" <jsykari cc.hut.fi> wrote in message
 news:akef9g$gvt$1 digitaldaemon.com...
 Then a little rant about the infamous "switch" behavior:

 About C compatibility and especially the switch fall-through behavior:
 faq.html:
 Why fall through on switch statements?

 Many people have asked for a requirement that there be a break between
 cases in a switch statement, that C's behavior of silently falling
 through is the cause of many bugs.

 The reason D doesn't change this is for the same reason that integral
 promotion rules and operator precedence rules were kept the same - to
 make code that looks the same as in C operate the same. If it had subtly
 different semantics, it will cause frustratingly subtle bugs.

 I think one needs to take a new perspective here.

 I strongly believe that C compatibility is just not something worth
 striving for. Why? There are a couple of reasons.

 The first and foremost reason is:
 0. Falling through is a special case you almost never see.  There is
 just no point in doing that the default. C designers simply made a
 mistake.  Isn't the point of making a new language to fix it?

 Besides, good-mannered C programmer will anyway document the
 fall-through case with a comment like "/* FALL THROUGH */". Why not make
 the documentation part of the language and introduce a keyword
 "fallthrough" to document the uncommon case? (or maybe just use
 "continue") You have already provided the means to document the code
 with assert() and pre- and postconditions - then why not fallthrough, if
 it so badly needs documentation?

 Because the previous reason is so obvious that everybody has become
 blind to it, I'll present some more reasons:

 1. Who needs the compatibility? The seasoned C hackers, you say. Not
 everybody changes from C or C++ to D. In time, if D turns out to be a
 success, we will see people learning D as their first language. And, if
 we have the "fall through by default" semantics, they will _certainly_
 encounter the mysterious "missing break" bugs C programmers have two
 decades' experience of. And, I don't mean just newbies, since:

 2. I believe that even seasoned C hackers make "missing break" mistakes.
 Frequently. Everyone forgets the "break" from there sometimes. If it
 were the other way round, it wouldn't happen. And that, if something,
 causes frustratingly subtle bugs, and that will continue to be the case
 forever if it doesn't get fixed now.

 Question: Why make falling through a special case?

 Answer: Because it _can_ _be_. And we can do that without introducing
 subtle bugs:

 3. The chance of introducing subtle bugs could be minimized by issuing
 an error (or possibly a loud warning) for every "break;" encountered
 inside the switch statement. (What would the break do there, anyway?)
 Now the so-called "subtle" bugs would be introduced only if there were
 no "break" statements inside the switch statement, which would
 correspond to a rare case like this:

 // Assume that the user has copy&pasted this from existing C/C++ code,
 // and that we have "don't fall through by default" semantics:
 f(int i) {
 switch (i)
 {
 case 1:
 doIfOne();
 // FALL THROUGH (at least the programmer assumed so)
 case 2:
 doIfOneOrTwo();
 // FALL THROUGH (at least the programmer assumed so)
 case 3:
 doIfOneOrTwoOrThree();
 // FALL THROUGH (at least the programmer assumed so)
 default:
 doAlways(); // this could as well be outside the switch
 // statement so there really shouldn't even be a 'default:'
 }
 }

 Now, this isn't a case you would see every day, and I will even argue
 that the bugs caused by this wouldn't be anything, and I mean _anything_
 like subtle if the programmer had bothered to test his code even a
 _bit_.  There should be a testcase which tests at least f(1), f(3) and
 f(98728234).

 But on the other hand, if he copy & pasted the snippet from C++ code and
 then didn't bother to learn the new rules before starting to program,
 and *still* failed to write the decent test cases, he deserves to be
 screwed. And we can be happy since bad behavior got rightfully punished.
 :-)

 Now, the only argument you have on behalf on "fall through by default"
 semantics is that Duff's Device (duff:device) relies on it, and you can
 fix even that by adding fallthrough/continue keywords in every line of
 it. I rest my case.


Sep 02 2002
parent "Walter" <walter digitalmars.com> writes:
"Matthew Wilson" <matthew thedjournal.com> wrote in message
news:al1end$2d9f$1 digitaldaemon.com...
 I can remember the first time I realised (in a happiling compiling

 that Java does not have out-parameters. To say I was disgusted would be
 putting it mildly ...

The workaround for lack of out parameters in Java is awful. To my mind it's the most serious shortcoming of the language.
Sep 03 2002
prev sibling next sibling parent reply "Richard Krehbiel" <rich kastle.com> writes:
"Antti Sykäri" <jsykari cc.hut.fi> wrote in message
news:akef9g$gvt$1 digitaldaemon.com...

 - have support for extensive metaprogramming facilities. ("Better
   macros" if you will.)

Unless I misread something, your lenghty post didn't expand upon this idea. Now, Walter's currently attacking the concept of "generics" but I think it won't go far enough. I want real, programmable functions, run in compile-time context, with access to the compiler's input, output, and symbol tables. But nobody else does. :-( -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 comcast.net (personal)
Aug 27 2002
next sibling parent "Sean L. Palmer" <seanpalmer earthlink.net> writes:
Other people do.  But who's going to make it possible?  ;)

Sean

"Richard Krehbiel" <rich kastle.com> wrote in message
news:akg8t5$2jm8$1 digitaldaemon.com...
 "Antti Sykäri" <jsykari cc.hut.fi> wrote in message
 news:akef9g$gvt$1 digitaldaemon.com...

 - have support for extensive metaprogramming facilities. ("Better
   macros" if you will.)

Unless I misread something, your lenghty post didn't expand upon this

 Now, Walter's currently attacking the concept of "generics" but I think it
 won't go far enough.  I want real, programmable functions, run in
 compile-time context, with access to the compiler's input, output, and
 symbol tables.  But nobody else does.  :-(

 --
 Richard Krehbiel, Arlington, VA, USA
 rich kastle.com (work) or krehbiel3 comcast.net  (personal)

Aug 27 2002
prev sibling next sibling parent reply Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari cc.hut.fi> writes:
In article <akg8t5$2jm8$1 digitaldaemon.com>, Richard Krehbiel wrote:
 "Antti Sykäri" <jsykari cc.hut.fi> wrote in message
 news:akef9g$gvt$1 digitaldaemon.com...
 - have support for extensive metaprogramming facilities. ("Better
   macros" if you will.)

Unless I misread something, your lenghty post didn't expand upon this idea.

No, because I saved something for later. And decided to go to sleep.
 Now, Walter's currently attacking the concept of "generics" but I
 think it
 won't go far enough.  I want real, programmable functions, run in
 compile-time context, with access to the compiler's input, output, and
 symbol tables.  But nobody else does.  :-(

Looks like that you want the compiler to include an interpreted language which has access to the compile-time information. Not a bad idea indeed, considering the power you would have at your fingertips. Now you have basically two choices: 1. make it an imperative language (such as python, or whatever - or even D, with possibly certain restrictions and with access to compile-time information) This would allow you to do things like: define metafunction blah(type X) { // define generic functions f, g and h here instantiate generic functions f, g and h with parameters X.argumentType and X.anotherArgumentType, or a tuple X.arguments, or whatever, into type X. return type X; } then you could do something like: alias blah(X) Type_with_f_and_g_and_h; and Type_with_f_and_g_and_h would be the same type as X, but with functions f, g and h. Something like private inheritance, but carefully designed not to look like it. This would probably need more abstraction etcetera, but you get the point. Or you could do something completely different: metafunction WithDebugPrints(Type X) { for each f in (X.functions) { X.remove(f); f.insertStatementAtBeginning( // here's a primitive form of lambda function: [ print("entering function", functionname); ]); f.insertStatementAtEnd( [ print("exiting function", functionname); ]); X.insert(f); } } and WithDebugPrints(SomeClass) is a type which has the same functions and other stuff as SomeClass, except that every function prints out "entering function <functionname>". You can probably invent a place where the function can dig up the "functionname" part. (No. __FILE__, __LINE__ and __function__ are right out. They're preprocessor macro hackery.) Then, the another alternative. 2. make it a pure functional language (such as C++ templates, in a way, are) This is the route I'm going to follow here. Pure functional language here means that you cannot change the parameters (types) at any phase. That would quite about match the usage of C++ templates. They could be probably designed to be much better by someone proficient in both template metaprogramming and functional languages and data structures. I'll provide pointers later on about what this kind of of metaprogramming would make possible. They're already a tremendously powerful tool in C++, but they're a bit slow and because the poor language wasn't designed for them, the support for such techniques seems to be inexistent. At least for now. Now, there would be another, more exotic alternative, if you want to pursue a bit more non-conventional route: 3. make your metalanguage a logic programming language (like prolog). This would be an interesting adventure indeed, and I don't know if many people have walked that path and seen what kind of dangers and exciting problems lie ahead. And I don't certainly know if there is a rainbow at the end of the road. Maybe some time... I thought about implementing regression tests for the compiler in a kind of metalanguage: // this is a function the compilation of which we want to test. int main() { print("Hello world\n"); } int reference_main() { asm { // you should insert the text of "main", as it will be // after the compilation. } } // and this is meta D which asserts that the compilation of main() went // as it should. main.text is assumed to contain the compiled code as // a byte array. meta_assert(main.text == reference_main.text); Of course, this kind of metacode could be run only after the compilation itself is done. It could test the code between different optimization passes, etc... of course, when the optimization engine is added (and the compiler optimizes better) this kind of test would break and defeat its purpose. But I could imagine that something like this could exist. Boost provides a meta-assertion facility in boost:static-assert and they use it like this: BOOST_STATIC_ASSERT(sizeof(int) * CHAR_BIT >= 32); Unlike normal assertion, this one can be placed in the file scope, and only handles constant expressions. One meta-idea I do have: make the "if" construct to be evaluable at compile-time, if possible. Then the if construct would be able to appear anywhere or almost anywhere. This would, however, require the functional style "if" I preached about yesterday, on "part two". For example: interface ThingyInterface { void garble(int x, int y); } class Thingy : ThingyInterface { if (target_arch == arch_i386) void garble(int x, int y) { // this is the i386 optimized version of garble() asm { if ( target_arch.subarch == athlon || target_arch.subarch == athlon_xp) // insert athlon-specific assembler code here else // insert general-purpose x86 assembler code here } } else if (target_arch == arch_alpha) void garble(int x, int y) { // now here we have the alpha optimized version } else void garble(int x, int y) { // native D version } // other functions here } I note that the previous was just an example; probably a better idea would be to introduce "alias Thingy_x86 Thingy;" inside an if (or version, which seems to be designed for that). Make a better example if you can! If the infamous switch were "automatically breaking instead of falling through", we could use even that without serious semantic flaws: module operator.addition; // target_arch is a special variable defined by the compiler switch (compile_time.target_arch) { case arch_i386: // introduce i386 specific functions, for example: uint operator.mul(uint lhs, uint rhs) { /* some serious MUL here! */ } case target_alpha: // alpha functions here... uint operator.mul(uint lhs, uint rsh) { /* do the alpha thingy! */ } default: // we don't have a MUL operation in hardware. but don't panic, we // probably have addition: uint result operator.mul(uint lhs, uint rhs) { while (lhs--) result += rhs; } } I can imagine that it would also work with the "automatic fall through" semantics for switch, but it would be kind of silly, wouldn't it, since there wouldn't be anything to "break" from. The type declarations just "are". (A declarative programming language, you see. Reminds me of prolog... mmm...) (And besides, no one really wants different semantics for compile time and run time switch. That if you will do, I will shoot y00.) I assume that inlining if's and switches already happens at compile time if the argument is a constant one - and it is often used for "commenting out code by if (0)". This is just a small step of generalization about that. Needless to say, this would be rather the same as the "version" mechanism, except a bit more consistent with the rest of language, I think. (Not 100% sure) I still haven't thoroughly studied the possibilities of D's template facilities, but IMHO templates should be designed to be able to do much of what C++'s templates should. However, this is not enough. With C++ you can do a _lot_, but since the C++ templates were not designed with metaprogramming in mind, they are 1) not powerful enough for everything (for instance, C++ would need a portable "typeof" operator. It's coming but I surely hope that the rats will have left the sinking boat by then. At least I hope I have. *g*) 2) not too portable, because depending on what kind of tricks you do, the infamous Internal Compiler Error appears on different compilers. We all know this "MSVC version X has a partial template function specialization instantiation bug" merry-go-round. And we don't want to make D as complicated as C++ is. (I just wonder if it will be possible...) 3) not efficient enough, partly because the compilers weren't designed with metaprogramming in mind, and partly because to circumvent reasons (1) and (2), horrible kludges have to be invented. About the efficiency part - I have always desired a possibility to preinstantiate templates for certain types, and to distribute these with the source code, so that the poor user wouldn't have to use the precious processor time to instantiate the templates (which might be very complicated if sophisticated modern metaprogramming product-line architecture, and whatnot, techniques be used!) again and again. I know what from C++ experience. The slowness doesn't come from just reading in a big bunch of include files. It's also the tremendous amount if symbolic processing you have to do in order to generate a type out of a template filled with kludges designed to make C++ template code more portable and efficient - run-time efficient, I mean. For those of you not thoroughly exposed to metaprogramming, that is something you should enlighten yourself with as soon as possible. You could start by reading the following: For a quick glance at metaprogramming, or "What every (C++) programmer/compiler implementor/language designer needs to know about metaprogramming", see boost:mpl. Then there's Andrei Alexandrescu's delighful book, which sets a new course for modern programming techniques using templates alexandrescu:modern-c++-design. There's also a sample chapter on smart pointers available as a pdf. I believe that this is a book which will have a tremendous impact on the raising generation of C++ programmers, and you don't really want to make D just a disappointing Java clone in their eyes. Finally, eisenecker:generative-programming is said to be a useful book, a classic even, although I haven't read it myself. They talk a lot about product-line architectures, which seem a boring concept. But very smart people seem to dig the book. I have it on my list... (Incidentally, they're selling it at amazon (see amazon:generative) together with Modern C++ Design) Now there's enough rant about metaprogramming... Antti. References: (boost:static-assert) http://www.boost.org/libs/static_assert/static_assert.htm (boost:mpl) http://www.mywikinet.com/mpl/paper/html/index.html (alexandrescu:modern-c++-design) http://www.aw.com/catalog/academic/product/1,4096,0201704315,00.html (eisenecker:generative-programmign) http://143.93.17.150/~gporg/ (amazon:generative) http://www.amazon.com/exec/obidos/tg/detail/-/0201309777/qid=1030497660/sr=8-1/ref=sr_8_1/002-5800298-9167210?v=glance&s=books&n=507846
Aug 27 2002
parent "Walter" <walter digitalmars.com> writes:
At one time, I intended to use the 'if' for conditional compilation. It
turned out to be too confusing - the version statement/declaration works
much better.

So far, I've got the D templates about 1/3 working. Syntax analysis,
argument deduction, and partial specialization are implemented. Next comes
instantiation, followed by object code generation.
Sep 03 2002
prev sibling parent "Matthew Wilson" <matthew thedjournal.com> writes:
I do!

"Richard Krehbiel" <rich kastle.com> wrote in message
news:akg8t5$2jm8$1 digitaldaemon.com...
 "Antti Sykäri" <jsykari cc.hut.fi> wrote in message
 news:akef9g$gvt$1 digitaldaemon.com...

 - have support for extensive metaprogramming facilities. ("Better
   macros" if you will.)

Unless I misread something, your lenghty post didn't expand upon this

 Now, Walter's currently attacking the concept of "generics" but I think it
 won't go far enough.  I want real, programmable functions, run in
 compile-time context, with access to the compiler's input, output, and
 symbol tables.  But nobody else does.  :-(

 --
 Richard Krehbiel, Arlington, VA, USA
 rich kastle.com (work) or krehbiel3 comcast.net  (personal)

Sep 02 2002
prev sibling parent "Dario" <supdar yahoo.com> writes:
If we drop the fall-through feature we should change the entire sintax of
the switch statement.
For example:

int blah = rand();

switch(blah)
case(1)
    return;
case(2)
{
    goto case(3);
}
case(3) case(4)
    goto default;
default
{/*do nothing*/}

This way the compiler will fail if trying to compile old C code,
and the programmer will known that something should be modified.

If we don't change the sintax the following code won't work as expected:

switch(1)
{
    case 1: case 2:
    printf("GOOD");
    default:
    printf("BAD");
}

Just some thoughts. Anyway I agree that the language should prevent errors
from happening.
Sep 05 2002