May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #60 from Andrei Alexandrescu <andrei@metalanguage.com> 2012-05-06 19:48:55 PDT ---
This has been some significant pwning of Walter and myself, and I think there is a larger lesson here we should learn.

We essentially operated from vague memories instead of actually going back and revisit the sources. This must be how some dogma is born - an imprecise and incorrect recollection of some assumption that becomes petrified.

What I think we should do going forward is to make sure we state and document our assumptions instead of relying on rote recollection. The DbC-related documentation and language specification should contain chapter and page of Meyer's work. There's a good reason why all academic work makes sure cites all of its sources, and even that is liable to mistakes of the kind we've done.

Thanks to all who have pursued this matter.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #61 from Stewart Gordon <smjg@iname.com> 2012-05-07 03:58:47 PDT ---
(In reply to comment #58)
> It's not that simple. Several considerations have to be met:
> 
> 1.  Because of struct construction/destruction, you really only want to construct the parameter list *once*, but you're calling two functions with the same parameter list.

Can't this be solved by simply making all struct parameters to the in/out functions ref?

(I've never been sure about this struct construction/destruction business anyway.  Struct constructors are nice, but I must've thought at a time that part of the design of D is that structs can always safely be just bit-copied.)

> 2. Variadic functions mean that one function cannot forward to another one using standard functions.  (Perhaps a dirty magic thunk can work.)
> 
> 3. The presence or absence of contracts must not change the ABI of the function.
> 
> 4. The virtual table must be unchanged.

I assume these were part of the reason for using nested functions to implement contract inheritance.  2 is indeed something that needs to be considered.  But is forwarding the arguments any more difficult than putting the arguments onto the stack in the first place?

As for 3 and 4, the in/out functions don't need to be virtual as far as I can see, so this shouldn't cause much difficulty.

> 5.  It's not so practical to jump into the middle of another function - things just aren't designed that way.
> 
> 6.  The caller now has to be aware of contracts in the called function, this was never necessary before.

I think this is a good thing, since it enables the user of a library to switch on/off in contract checking without having to rebuild the library.

(In reply to comment #56)
> class A {
>  static void foo_in(A x) {  assert(n>0); }
>  virtual int foo(int n) { foo_in(this, n);  return foo_body(n); }
>  virtual int foo_body(int n) { return n; }
> }

foo needs to be non-virtual - otherwise you're implementing dynamic binding, which we already have, not static binding.

Indeed, it should be something like this

class A {
    void foo_in(int n) {  assert(n>0); }
    int foo_dbc(int n) { foo_in(this, n); return foo(n); }
    virtual int foo(int n) { return n; }
}

then a call to foo would translate to a call to foo_dbc when compiling in non-release mode.  This also has the advantage of not changing the vtable layout.

The difficulty is that the library might have been built in release mode, with foo_in and foo_dbc absent.  Can we get around this by treating them as nullary templates, so they are compiled/linked in according to usage?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #62 from deadalnix <deadalnix@gmail.com> 2012-05-07 04:43:25 PDT ---
(In reply to comment #60)
> This has been some significant pwning of Walter and myself, and I think there is a larger lesson here we should learn.
> 

Quoting yourself « Mistakes happen to the best of us. ». Don't worry, I think your reaction is very safe, and I'm happy to see D evolving that way.

Changing how the language work must be done only if strong arguments are made. Providing documentation on language design decision is surely a way to improve the current state of things.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #63 from Walter Bright <bugzilla@digitalmars.com> 2012-05-07 08:29:21 PDT ---
(In reply to comment #61)
> (In reply to comment #58)
> > It's not that simple. Several considerations have to be met:
> > 
> > 1.  Because of struct construction/destruction, you really only want to construct the parameter list *once*, but you're calling two functions with the same parameter list.
> 
> Can't this be solved by simply making all struct parameters to the in/out functions ref?

Losing all C ABI compatiblity in the process.

> I assume these were part of the reason for using nested functions to implement contract inheritance.  2 is indeed something that needs to be considered.  But is forwarding the arguments any more difficult than putting the arguments onto the stack in the first place?

How do you forward a variadic function? You don't know what's on the stack to forward.

> class A {
>     void foo_in(int n) {  assert(n>0); }
>     int foo_dbc(int n) { foo_in(this, n); return foo(n); }
>     virtual int foo(int n) { return n; }
> }
> 
> then a call to foo would translate to a call to foo_dbc when compiling in non-release mode.  This also has the advantage of not changing the vtable layout.

Again, you're pushing the parameters on the stack twice - and this won't work for variadic functions.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #64 from deadalnix <deadalnix@gmail.com> 2012-05-07 09:00:05 PDT ---
(In reply to comment #63)

> Again, you're pushing the parameters on the stack twice - and this won't work for variadic functions.

Why not jump in the function directly after the prolog and not push arguments twice on the stack ?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #65 from Walter Bright <bugzilla@digitalmars.com> 2012-05-07 09:36:56 PDT ---
(In reply to comment #64)
> Why not jump in the function directly after the prolog and not push arguments twice on the stack ?

Not so easy given how back ends are designed.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #66 from Stewart Gordon <smjg@iname.com> 2012-05-07 10:32:33 PDT ---
(In reply to comment #63)
> > Can't this be solved by simply making all struct parameters to the in/out functions ref?
> 
> Losing all C ABI compatiblity in the process.

Contracts don't exist in C - so what's there to lose?

> How do you forward a variadic function? You don't know what's on the stack to forward.

How do you implement a variadic function at all without knowing this?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #67 from Stewart Gordon <smjg@iname.com> 2012-05-07 10:48:26 PDT ---
(In reply to comment #62)
> Changing how the language work must be done only if strong arguments are made.

Unless I've missed something, the language leaves this unspecified.  So a compiler is free to do it either way.  Though it would be better if it were specified.

> Providing documentation on language design decision is surely a way to improve the current state of things.

Indeed, if all rationales scattered about the D docs were collected in one place, and a few more that we ought to have were added, I wonder how big this section would be.

FTR, look at the PNG rationale page.... http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #68 from Walter Bright <bugzilla@digitalmars.com> 2012-05-07 12:17:19 PDT ---
(In reply to comment #66)
> (In reply to comment #63)
> > > Can't this be solved by simply making all struct parameters to the in/out functions ref?
> > 
> > Losing all C ABI compatiblity in the process.
> 
> Contracts don't exist in C - so what's there to lose?

1. pass by ref is semantically very different from pass by value. It is necessary to support both.

2. D supports using C calling conventions, including having contracts on functions callable from C.

> > How do you forward a variadic function? You don't know what's on the stack to forward.
> 
> How do you implement a variadic function at all without knowing this?

See printf, an example of where such knowledge is known by the programmer, not the language semantics.

Just for fun, I suggest you try to implement a "myprintf" function which forwards all its arguments to printf.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 07, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=6857



--- Comment #69 from Stewart Gordon <smjg@iname.com> 2012-05-07 12:26:47 PDT ---
(In reply to comment #68)
> 1. pass by ref is semantically very different from pass by value. It is necessary to support both.

The function that implements a contract is an internal thing.  If you can implement said function to receive the struct by value, you can equally implement it to receive the struct by reference.

> 2. D supports using C calling conventions, including having contracts on functions callable from C.

But the contract itself doesn't need to be callable from C.  Only the overall function does.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------