Thread overview
Language design... and implementation
Jan 19, 2002
Pavel Minayev
Jan 19, 2002
Pavel Minayev
Jan 19, 2002
Pavel Minayev
Jan 19, 2002
Walter
January 18, 2002
   I guess I should start by apologizing to Walter for starting in this
forum in "harsh critic mode". I guess he probably gets that a lot. Probably
a "fair" punishment for going ahead and do what most of us would like to do
but don't, namely, designing (and implementing, for Chrissakes!) his own
language and compiler.

   So from here, I'd like to commend his work. It's awesome to say the
least.

   Nevetheless, there's always opinions and opinions, so I'll keep pusing
for mine. If you want me to stop, Walter, then tell me.

   Ok... So... From the online documentation...

> Functions: "There is no inline keyword. The compiler makes the decision
whether to inline a function or not"

   Hmmm... My inclination is exactly the opposite. What I'd want is a
"macro" keyword that enforces the inlining of a function. I want to be able
to tell the compiler to inline it, and fail with an error if for any reason
it can't.

> Classes, Constructors: "The vptr initialization is performed before the
constructor is ever called (by the new operator)"

   I suppose that you're aware that this by itself makes constructors behave
very differently from the C++ standard. I actually like it this way no less
than what the C++ does. It brings me back to my times with Turbo Pascal :)
Still, it should be a BIG emphatical point in the "Programming in D for C++
Programmers" section.

> Asserts:

   Asserts are a very powerful thing. I believe that the decission of making
them a primitive is a very good one. Still, it would be even better to
formalize compile-time asserts. Those are asserts where the asserted
expression is constant. It would be a good thing to force compilers to
evaluate such asserts at compile-time

> Contracts: "If a function in a derived class overrides a function in its
super class, then only one of the in contracts of the base functions must be satisified"

   I'm not sure this is advisable. The "in" contract of a derived method
should be forced to be implied by the contract for the parent method. For
example:

---
class A {
  int[10] nums;
  int Convert(int k)
  in {
    assert(k >= 0 && k < 10);
  }
  body {
    return nums[k];
  }
}

class B: A {
  int Convert(int k)
  in {
    assert(k >= 0 && k < 12);
  }
  body {
    printf("Converting %d\n", k);
    return super.Convert(k);
  }
}
---

   This allows you to do:

---
B b = new b;
b.Convert(11);
---

   Which would blow. The derived class has broken the contract of its
parent. I agree that it shouldn't happen, but then the compiler should help
with enforcing it.

   Instead, a somewhat acceptable alternative would be to use only the
derived's contract when calling, and have the parent's contract be used only
if/when the parent implementation is called.

Salutaciones,
                         JCAB



January 19, 2002
"Juan Carlos Arevalo Baeza" <jcab@roningames.com> wrote in message news:a2acct$bi$1@digitaldaemon.com...

> > Functions: "There is no inline keyword. The compiler makes the decision
> whether to inline a function or not"
>
>    Hmmm... My inclination is exactly the opposite. What I'd want is a
> "macro" keyword that enforces the inlining of a function. I want to be
able
> to tell the compiler to inline it, and fail with an error if for any
reason
> it can't.

Why exactly do you need it? From your POV there is no difference other than perfomance, and you can be sure that compiler does his best to optimize it... inline functions aren't C macro, anyhow...

> > Classes, Constructors: "The vptr initialization is performed before the
> constructor is ever called (by the new operator)"
>
>    I suppose that you're aware that this by itself makes constructors
behave
> very differently from the C++ standard. I actually like it this way no
less
> than what the C++ does. It brings me back to my times with Turbo Pascal :) Still, it should be a BIG emphatical point in the "Programming in D for
C++
> Programmers" section.

What is great in it is that constructor in base classes can call virtual methods of child classes. This was impossible to do in C++.

Also, constructors can call each other this way - so no need to make a separate initialization function, a common thing in C++.

>    Asserts are a very powerful thing. I believe that the decission of
making
> them a primitive is a very good one. Still, it would be even better to formalize compile-time asserts. Those are asserts where the asserted expression is constant. It would be a good thing to force compilers to evaluate such asserts at compile-time

I woudln't be surprised if there's already something like that in D.

>    I'm not sure this is advisable. The "in" contract of a derived method
> should be forced to be implied by the contract for the parent method. For

In-contracts are what _function_ expects. Since function in derived class might be different of that in base class, providing its own implementation, it _can_ cover an extended range of values (remember, deriving from a class means _extending_ this class!). This can be demonstrated with this example:

    class A
    {
        void func(int x)
            in { assert(x > 0 && x < 10); }
            { ... }
    }

    class B: A
    {
        override void func(int x)
            in { assert(x > 0 && x < 20); }
            { ... }
    }

    A obj = new B;

    obj.func(5);    // since B is child of A, it must be able
                    // to do at least what A can...

    obj.func(15);   // ...but might do even more!

Programmer is responsible for calling super() with appropriate arguments.
If his function doesn't, it breaks the contract with super() - but
not the user who called that function!




January 19, 2002
"Pavel Minayev" <evilone@omen.ru> wrote in message news:a2afi4$2hh$1@digitaldaemon.com...
> "Juan Carlos Arevalo Baeza" <jcab@roningames.com> wrote in message news:a2acct$bi$1@digitaldaemon.com...
>
> >    Hmmm... My inclination is exactly the opposite. What I'd want is a
> > "macro" keyword that enforces the inlining of a function. I want to be
> able
> > to tell the compiler to inline it, and fail with an error if for any
> reason
> > it can't.
>
> Why exactly do you need it? From your POV there is no difference other than perfomance, and you can be sure that compiler does his best to optimize it... inline functions aren't C macro, anyhow...

   "and you can be sure that compiler does his best". Hmmm... No.

   I want to do things like put in functions for accessible properties,
(which D does, for example), and still be 100% assured that there's no
performance penalty. Even in debug mode. I don't want to give the compiler
the choice.

> > > Classes, Constructors: "The vptr initialization is performed before
the
> > constructor is ever called (by the new operator)"
>
> What is great in it is that constructor in base classes can call virtual methods of child classes. This was impossible to do in C++.

   :) Yes.

> Also, constructors can call each other this way - so no need to make a separate initialization function, a common thing in C++.

   Exactly. The downside is that it loses the strictness of  C++ as far as
the "life" of objects is concerned, which is a good thing, even if it gets
in the way sometimes.

> >    Asserts are a very powerful thing. I believe that the decission of
> making
> > them a primitive is a very good one. Still, it would be even better to formalize compile-time asserts. Those are asserts where the asserted expression is constant. It would be a good thing to force compilers to evaluate such asserts at compile-time
>
> I woudln't be surprised if there's already something like that in D.

   :) It wouldn't see its potential until some form of parametric
polymorphism (templates) made it into the language. But it'd shine then.
Imagine being able to add an error message to the assert. I'd buy into the
language, despite my differences of opinion with Walter, just to get that.

> >    I'm not sure this is advisable. The "in" contract of a derived method
> > should be forced to be implied by the contract for the parent method.
For
>
> In-contracts are what _function_ expects. Since function in derived class might be different of that in base class, providing its own implementation, it _can_ cover an extended range of values (remember, deriving from a class means _extending_ this class!). This can be demonstrated with this example:
>
> [...]
>
>     obj.func(5);    // since B is child of A, it must be able
>                     // to do at least what A can...
>
>     obj.func(15);   // ...but might do even more!

   But it still could do less and get away with it! Until it crashes! What
I'm talking is about the compiler (or the runtime, in this case) _enforcing_
that.

Salutaciones,
                         JCAB



January 19, 2002
"Juan Carlos Arevalo Baeza" <jcab@roningames.com> wrote in message news:a2aguf$3hf$1@digitaldaemon.com...

>    I want to do things like put in functions for accessible properties,
> (which D does, for example), and still be 100% assured that there's no
> performance penalty. Even in debug mode. I don't want to give the compiler
> the choice.

I guess D is a wrong tool for this.
BTW why do you want "no perfomance penalty" in debug mode? It was
never supposed to run fast! Just remember about DBC, invariants etc...

>    Exactly. The downside is that it loses the strictness of  C++ as far as
> the "life" of objects is concerned, which is a good thing, even if it gets
> in the way sometimes.

I don't see any good way to combine this power with strictness of C++. If I have to choose, I choose the D way.

>    But it still could do less and get away with it! Until it crashes! What
> I'm talking is about the compiler (or the runtime, in this case)
_enforcing_
> that.

How can this be implemented? Remember, in-blocks don't only contain
simple asserts - they can have loops (see string.toStringz() for an
example of such), and are in general just another sort of subroutines.
You can run one then another (as it's done with out-blocks), but how
do you check if it provides _at least_ (and not _at most_) the same
"range" as its superclass?


January 19, 2002
"Pavel Minayev" <evilone@omen.ru> wrote in message news:a2aifk$4ja$1@digitaldaemon.com...
> "Juan Carlos Arevalo Baeza" <jcab@roningames.com> wrote in message news:a2aguf$3hf$1@digitaldaemon.com...
>
> >    I want to do things like put in functions for accessible properties,
> > (which D does, for example), and still be 100% assured that there's no
> > performance penalty. Even in debug mode. I don't want to give the
compiler
> > the choice.
>
> I guess D is a wrong tool for this.
> BTW why do you want "no perfomance penalty" in debug mode? It was
> never supposed to run fast! Just remember about DBC, invariants etc...

   I develop games. I often run in debug mode because it's easier to debug
(duh! ;). The problem is that I also want to use high-level abstractions
that don't change the semantics of my program. Macros are perfect for that.
And, AFAIKS, there's absolutely no technical reason why the debugger (MSVC's
for example) couldn't single-step inlined functions (macros) on their
original source. It's one of those things that make me miserable sometimes.

   Remember: debug doesn't necessarily have to mean "as slow as possible".
Just "slow enough to be easily debuggeable" would be enough.

> >    Exactly. The downside is that it loses the strictness of  C++ as far
as
> > the "life" of objects is concerned, which is a good thing, even if it
gets
> > in the way sometimes.
>
> I don't see any good way to combine this power with strictness of C++. If I have to choose, I choose the D way.

   :) That's fair enough. Personally, I'd have to play with it a while
before I'll buy into that.

> >    But it still could do less and get away with it! Until it crashes!
What
> > I'm talking is about the compiler (or the runtime, in this case)
> _enforcing_
> > that.
>
> How can this be implemented? Remember, in-blocks don't only contain simple asserts - they can have loops (see string.toStringz() for an example of such), and are in general just another sort of subroutines.

   Yes. That baffles me. :) Still...

> You can run one then another (as it's done with out-blocks), but how
> do you check if it provides _at least_ (and not _at most_) the same
> "range" as its superclass?

   You can't, you're right. The other option is what I said before: that
only the actually called method's contract is the valid one, and that
calling through "super" invokes super's contract instead. That is definitely
doable by the compiler, and it swould be safe.

Salutaciones,
                         JCAB



January 19, 2002
"Juan Carlos Arevalo Baeza" <jcab@roningames.com> wrote in message news:a2ak4n$5mq$1@digitaldaemon.com...

>    Remember: debug doesn't necessarily have to mean "as slow as possible".
> Just "slow enough to be easily debuggeable" would be enough.

...which gives an opportunity for D to make functions inline even in debug build, if it can then handle them properly.

>    You can't, you're right. The other option is what I said before: that
> only the actually called method's contract is the valid one, and that
> calling through "super" invokes super's contract instead. That is
definitely
> doable by the compiler, and it swould be safe.

Invoking parent contract with super() - I like the idea!




January 19, 2002
"Pavel Minayev" <evilone@omen.ru> wrote in message news:a2alq1$6ik$1@digitaldaemon.com...
> "Juan Carlos Arevalo Baeza" <jcab@roningames.com> wrote in message news:a2ak4n$5mq$1@digitaldaemon.com...
>
> >    Remember: debug doesn't necessarily have to mean "as slow as
possible".
> > Just "slow enough to be easily debuggeable" would be enough.
>
> ...which gives an opportunity for D to make functions inline even in debug build, if it can then handle them properly.

   I admit it... I'm a "control freak" of sorts. :)

   Still... if I intend for something to have no impact on performance, I'm
the one who knows it, not the compiler, so I _should_ be able to express it.
I'd like the compiler to tell me if it has a problem with that. On MSVC, we
have the "__forceinline" extension, but MSVC will use only if it feels like
it, as it stands. Intel's compiler will respect it very well, but it's a
generally poorer compiler in my experience.

   Also, sometimes, it's hard for the compiler to inline a chain of 10
function calls, even if the result would be a single simple assembler
instruction. If they haven't been able to get it right, I doubt the D
compiler will. Sincerely. It'd make me warmer at night just to know I can
get a compiler error when things are not done the way I intended them. This
happens a lot when making functions that just redirect the call elsewhere
(to "super", or to another aggregated class, for example).

   This brings me to another interesting point: function redirections.
Having to make a whole new function with body just have it call a similar
function in an aggregated object seems like a good place to improve the
user-friendliness of the language.

Salutaciones,
                         JCAB



January 19, 2002
"Pavel Minayev" <evilone@omen.ru> wrote in message news:a2afi4$2hh$1@digitaldaemon.com...
> Also, constructors can call each other this way - so no need to make a separate initialization function, a common thing in C++.

Yes! One thing in C++ that caused me incessant bugs was a class with multiple constructors. I'd add a new member as a routine improvement, and forget to put the initializer for it into one of the constructors.

With D, you can have the more complex constructors call a "default" constructor, which sets all the members. Alternatively, the default for a member can be set in the member declaration itself. Worst case, the member is automatically initialized by a default set by the type.