October 04, 2002
Ok, you've all convinced me. I'll change the semantics so a super() is inserted automatically if none is already present. -Walter


October 05, 2002
Walter wrote:
> Ok, you've all convinced me. I'll change the semantics so a super() is
> inserted automatically if none is already present. -Walter

I won't put implicit code generation of something so important in my port.  An error, okay - I disagree, but it's acceptable.  Putting in code behind the programmer's back is not.

October 05, 2002
In article <anng7t$1m75$1@digitaldaemon.com>, Burton Radons says...
>
>Walter wrote:
>> Ok, you've all convinced me. I'll change the semantics so a super() is inserted automatically if none is already present. -Walter
>
>I won't put implicit code generation of something so important in my port.  An error, okay - I disagree, but it's acceptable.  Putting in code behind the programmer's back is not.
>
I agree.


October 07, 2002
"Walter" <walter@digitalmars.com> wrote in message news:anjhap$2t9h$1@digitaldaemon.com...
>
> "Mac Reiter" <Mac_member@pathlink.com> wrote in message news:anf1ji$15s4$1@digitaldaemon.com...
> > I also agree with someone else's comment that the base invariant should
be
> > called at the end of the base constructor, even when invoked through
> super().  I
> > also think it should be called _again_ at the end of the derived
> constructor,
> > since it is a valid invariant for the derived class.
>
> That should be the way it works now, I miswrote it.
>
> Some issues with the compiler flagging not calling super:
>
>     class A
>     {   this() { .. do general construction .. }
>         this(int x) { this(); .. do more construction ..}
>     }
>
> Calling super in each constructor means it gets called twice. Secondly, there is:
>
>     this()
>     {
>             if (...)
>                 super();
>     }
>
> So super() isn't always run. It's impossible for the compiler to verify
that
> super() is called exactly once in the general case.


To choose from super constructors at runtime is a good idea.
I see, that this makes (near) impossible to detect all cases where a
constructor avoids calling the super.
But the compiler could still try to detect where it is easy. If there is no
mention of same-level or super constructors in a constructor, then it is
clearly an error. This would help to avoid a typical error of forgetting the
super call.



October 07, 2002
In article <anng7t$1m75$1@digitaldaemon.com>, Burton Radons says...
>
>Walter wrote:
>> Ok, you've all convinced me. I'll change the semantics so a super() is inserted automatically if none is already present. -Walter
>
>I won't put implicit code generation of something so important in my port.  An error, okay - I disagree, but it's acceptable.  Putting in code behind the programmer's back is not.
>

What?  We've got a garbage collector, and we now have RAII destruction/finalization.  Where does "putting in code behind the programmer's back is not (acceptable)" but "An error ... is acceptable" come from?  We're already putting in code "behind the programmer's back" to make programming more reliable (GC, RAII finalization).  Plus, anybody coming from any OOP language with inheritance is going to expect that the base constructor was called before the derived constructor anyway...

Having said that, my personal preference is to require either a call to super() or a keyword that signals that super() is deliberately not called.  Then, throw a compilation error if neither "call" is present in the constructor.  Forces explicitness, avoids "oops, I forgot" errors, and also doesn't insert code behind anybody's back...

I guess my larger grump is with the divergence I already see between the Win32 DMD language and the DLI language.  There are already programs that will compile and run under DLI that use features not even present in DMD.  I would understand if it was a "completeness of implementation" issue, but it isn't -- DLI has specifically added things to its language that are not part of D/Phobos.  It does not appear that these additional features went through the degree of discussion and agreement that the DMD changes seem to be exposed to.  I'm not sure if all of those changes would fit under an "extended library" behavior or not.  But if a split occurs on something like "what to do with super() in a derived constructor", it will essentially be impossible to call both languages D.  Once a "port" decides not to implement a language feature, then it isn't a "port" any more.

I guess the even bigger grump is the perceived attitude.  "I won't put <feature X> in my port."  Fine, but then it isn't a port.

Sorry, gotta go to yet another meeting...
Mac



October 07, 2002
Mac wrote:
>I guess the even bigger grump is the perceived attitude.  "I won't put <feature X> in my port."  Fine, but then it isn't a port.
>

I agree.  If it's called D, then it should be D.

Still in these early days it might be wise to try two or three different development forks to see what people like; but only with the expectation that all such forks will eventually merge into D proper.

Mark


October 08, 2002
>What?  We've got a garbage collector, and we now have RAII destruction/finalization.
While I agree with your larger sentiment about not fragmenting ports, I don't think these two examples really make your claim.  The garbage collector just reclaims memory that is safe to reclaim, and indeed does not even need to be run when the system has enough ram.  Second RAII inserts code when the programmer specifies that RAII is desired.  Not the inverse, which is: insert code because I (the compiler) think the programmer is a dummy and I know better.


October 08, 2002
I think these issues are related, what is required is a unamigious statement of mission.

I agree in concept with the idea that the compiler should not add code
because it considers me a fool
but at the same time, we all make fools of ourselfs whilst programming.
and to quote murphys laws of technology "make a system fool proof and only a
fool would want to use it"

I was under them impression part of the design of D was to reduce the
pitfalls and allow a programmer to realise the foolishness of an action
before they try to run flawed code.
the issuse of base constructors, I would consider it potentially dangerous
to NOT call super before accessing an inherited public or protected member
or invoking a member function that does that.
if you want to do this then you should tell the compiler you intention.
in exactly the same way that garbage collection allows a programmer to let
the compiler/program chose when to cleanup/deallocate any created items, but
RAII and static arrays allow you to decide the life time of an item.

you have not mentioned dynamic arrays and hashtables as builtin types, these also perform many tasks that are not explicitly requested by the programmer such as allocations.

I am finding D quite a confusing language to use,
on one hand it seems to offer Java/C# style simplicity with all the "fool
proof" features like type safetly, default virtual and GC etc.
it also has script language like features such as builting dynamic array and
hashtables rather than templated
collections, so generic parameters seem a logical inclusion too.

but then allows me to make a bigger fool of myself with simple typo's by
allowing a class to never call a super constuctor, stack allocation of
arrays that can be referenced in heap objects and very strange dynamic array
behaviour when passed as 'in'.
I understand the Interface semantics are becuase of COM. Delphi/C# also
follows this and although Java does not, partly because an interface is not
a separate vtbl, and Java is much more dynamic and very tuned to the JavaVM,
neither is a good reason for any given semantics.
having mark a class as implementing an interface if it changes the
implementation does make sense, there should also be a mechanism to inherit
interface methods that do not require reimplementing.

I am finding it odd that features have been added (templates, RAII) while there are still basic issues like array handling, constructor semantics and passing stack allocated items that need to be addressed.

I would like to see a simple, design doc with mission statement and design ideology, containing enought information that these issues can be discussed in terms of this document. it should answer the question, who D is aimed at, what you should need to know to understand a piece of D code (i.e. what are the basics of the basic types and how to they interoperate).

number one on the list should be IMHO:

a D program or section of program should be written to perform a task, the programmer should write a description of the task they wish to apply to a set of items, and the limits within which this occurs, without having to be aware of the full implications of their actions, but with the assurance that their task will be carried out safely and in the most efficient manner. the full implications of a program should be determinable, and should not contain any unwanted side effects that effect the context from which the program or section was called.

::off to read more about ML and F#::

Mike.


"Joe Battelle" <Joe_member@pathlink.com> wrote in message news:antf5v$mtr$1@digitaldaemon.com...
> >What?  We've got a garbage collector, and we now have RAII destruction/finalization.
> While I agree with your larger sentiment about not fragmenting ports, I
don't
> think these two examples really make your claim.  The garbage collector
just
> reclaims memory that is safe to reclaim, and indeed does not even need to
be run
> when the system has enough ram.  Second RAII inserts code when the
programmer
> specifies that RAII is desired.  Not the inverse, which is: insert code
because
> I (the compiler) think the programmer is a dummy and I know better.
>
>


October 09, 2002
"Mike Wynn" <mike.wynn@l8night.co.uk> wrote in message news:anuh63$1sc6$1@digitaldaemon.com...
> but then allows me to make a bigger fool of myself with simple typo's by allowing a class to never call a super constuctor,

That is fixed.

> stack allocation of
> arrays that can be referenced in heap objects and very strange dynamic
array
> behaviour when passed as 'in'.

??

> I understand the Interface semantics are becuase of COM. Delphi/C# also follows this and although Java does not, partly because an interface is
not
> a separate vtbl, and Java is much more dynamic and very tuned to the
JavaVM,
> neither is a good reason for any given semantics.
> having mark a class as implementing an interface if it changes the
> implementation does make sense, there should also be a mechanism to
inherit
> interface methods that do not require reimplementing.

The interface semantics were changed to allow overriding of individual methods. The issue is not one of a separate vtbl[] vs Java's runtime lookup system - the semantics are the same. The separate vtbl[] is there because:

1) it is a lot faster
2) working with COM requires it



October 09, 2002
>
> The interface semantics were changed to allow overriding of individual methods. The issue is not one of a separate vtbl[] vs Java's runtime
lookup
> system - the semantics are the same. The separate vtbl[] is there because:

but what about the statment ...
A reimplemented interface must implement all the interface functions, it
does not inherit them from a super class

I do not understand you should implements all of an reinplemented interface, if you what to modify part of it, but not all them you can not comment your code to say 'I implement X'

There are differences between the Java signaure based interface and the
multipul vtbl approach,
the Java Style CAN be implemented as separate vtbls BUT multipul vtbl CAN
NOT be implemented with the method signature alone as it allows two
interfaces to have the same signature but different implementations within a
single class.

> 1) it is a lot faster
> 2) working with COM requires it
I know, when I worked on a JavaVM I suggested it was used to speed up interface calls but it was rejected on the grounds of extra memory usage (and with a JavaVM you'd still have to search for the right vtbl).

the docs do not say what will happen with

interface D
{
    int foo();
}

interface E
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A, E
{
    int foo() { return 2; }
}

which is valid within COM interfaces

or worse

interface D
{
    int foo();
}

interface E
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A, E
{
    int foo() { return 2; }
}

class C : B
{
    int foo() { return 2; }  // which foo is this foo; D or E ?
}