Jump to page: 1 2
Thread overview
Ideas, thoughts, and criticisms, part one
Aug 26, 2002
Antti Sykäri
Aug 27, 2002
Pavel Minayev
Aug 27, 2002
Antti Sykäri
Sep 04, 2002
Walter
Aug 27, 2002
Sean L. Palmer
Aug 27, 2002
Pavel Minayev
Sep 04, 2002
Walter
Sep 03, 2002
Matthew Wilson
Sep 04, 2002
Walter
Aug 27, 2002
Richard Krehbiel
Aug 27, 2002
Sean L. Palmer
Metaprogramming (Was Re: Ideas, thoughts, and criticisms, part one)
Aug 28, 2002
Antti Sykäri
Sep 04, 2002
Walter
Sep 03, 2002
Matthew Wilson
Sep 05, 2002
Dario
August 26, 2002
(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

August 27, 2002
On Mon, 26 Aug 2002 23:57:37 +0000 (UTC) Antti Syk_ri <jsykari@cc.hut.fi> wrote:

> modern system. So, what are the calling conventions used in D? They are on their way to being standardized, right?

The compiler decides calling convention itself for each function. It can decide
to pass some arguments in registers, or put everything on stack, in any
order - so optimizer can achieve maximum efficiency of function calls.

> 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)

You can avoid using GC, but then you will have to forget about dynamic arrays
and
90% of stdlib.

> 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);

Yes.

> 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?

Yes, you are right.

> 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?

I think they made it because it was simplier to implement.

> 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?)

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
		}
	}
August 27, 2002
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.



August 27, 2002
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...

August 27, 2002
"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)



August 27, 2002
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
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)



August 27, 2002
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.

August 28, 2002
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

September 03, 2002
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
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.
>
>
>


September 03, 2002
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
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)
>
>
>


« First   ‹ Prev
1 2