www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - new DIP47: Outlining member functions of aggregates

reply Walter Bright <newshound2 digitalmars.com> writes:
Outlining of member functions is the practice of placing the declaration of a 
member function in the struct/class/union, and placing the definition of it at 
global scope in the module or even in another module.

http://wiki.dlang.org/DIP47
Sep 07 2013
next sibling parent reply Jos van Uden <usenet fwend.com> writes:
On 7-9-2013 19:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration of a
member function in the struct/class/union, and placing the definition of it at
global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

The problem is that it is optional, so when you're reading other people's code you'll still have to deal with inline definitions, and you'll need a decent editor (doesn't have to be an IDE, even basic editors like notepad++ and editpad pro support code folding and function lists) to easily read it.
Sep 07 2013
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 7 September 2013 at 17:28:42 UTC, Jos van Uden wrote:
 and you'll need a decent editor

Or just run dmd -H over it.
Sep 07 2013
prev sibling next sibling parent reply "Paolo Invernizzi" <paolo.invernizzi gmail.com> writes:
On Saturday, 7 September 2013 at 17:28:42 UTC, Jos van Uden wrote:
 On 7-9-2013 19:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, 
 and placing the definition of it at global scope in the module 
 or even in another module.

 http://wiki.dlang.org/DIP47

The problem is that it is optional, so when you're reading other people's code you'll still have to deal with inline definitions, and you'll need a decent editor (doesn't have to be an IDE, even basic editors like notepad++ and editpad pro support code folding and function lists) to easily read it.

No pun intended, but having it as _mandatory_ would be a little to much for people like me that don't like this proposal at all. - Paolo Invernizzi
Sep 07 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 11:39 AM, Paolo Invernizzi wrote:
 No pun intended, but having it as  _mandatory_ would be a little to much for
 people like me that don't like this proposal at all.

There's no way it would be mandatory.
Sep 07 2013
prev sibling parent Jos van Uden <usenet fwend.com> writes:
On 7-9-2013 20:39, Paolo Invernizzi wrote:
 On Saturday, 7 September 2013 at 17:28:42 UTC, Jos van Uden wrote:
 On 7-9-2013 19:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration of a
member function in the struct/class/union, and placing the definition of it at
global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

The problem is that it is optional, so when you're reading other people's code you'll still have to deal with inline definitions, and you'll need a decent editor (doesn't have to be an IDE, even basic editors like notepad++ and editpad pro support code folding and function lists) to easily read it.

No pun intended, but having it as _mandatory_ would be a little to much for people like me that don't like this proposal at all. - Paolo Invernizzi

Exactly, so we're adding a lot of code noise, while you still have to use an editor for codes that don't outline, so you might as well just use an smart editor in the first place.
Sep 07 2013
prev sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Saturday, 7 September 2013 at 17:28:42 UTC, Jos van Uden wrote:
 On 7-9-2013 19:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, 
 and placing the definition of it at global scope in the module 
 or even in another module.

 http://wiki.dlang.org/DIP47

The problem is that it is optional, so when you're reading other people's code you'll still have to deal with inline definitions, and you'll need a decent editor (doesn't have to be an IDE, even basic editors like notepad++ and editpad pro support code folding and function lists) to easily read it.

So the problem is that you need a *basic* editor to make other people's code look like the way you like ? I'd say this is awesome, and most of the time, you won't achieve that. Don't try to impose your religion to the world.
Sep 07 2013
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
07-Sep-2013 21:00, Walter Bright пишет:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

7. Outlined member function return types, parameter types, and function bodies have private access to the module where the aggregate is declared. I understand why you may want this hack but it starts to smells real bad. Not only we haven't fixed bugs in our module system yet we introduce another kludge into it to support the C++ header + unknown set of files with implementations. Another twist in visibility/accessiblity lookup rules. I expect another wave of bugs regarding safe/pure/etc. silently accepted for outlined functions and so on. Now you can't know if a module implements all of stuff it declares or not. Or where it is implemented at all. I would rather restrict this feature w.r.t. where outlined methods can be defined - e.g. same module or in the same sub-package. Accessibility rules should stay the same as they are now. In that setting if one wants to split methods across multiple file - fine, just declare them 'package' and put implementations deeper down the package tree. TL;DR: DROP point 7, and describe how to use 'package' to split implementation across multiple files. -- Dmitry Olshansky
Sep 07 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
07-Sep-2013 22:01, Dmitry Olshansky пишет:
 07-Sep-2013 21:00, Walter Bright пишет:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47


Not to mention poor motivation. A huge paragraph that basically states that some folks prefer IDEs to automatically fixup *this* kind of stuff and not *that* kind of stuff. I could understand this feature can be very convenient in e.g. DDMD that is being converted from C++. Then this and other examples should be provided. -- Dmitry Olshansky
Sep 07 2013
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
On 7 September 2013 18:28, Jos van Uden <usenet fwend.com> wrote:
 On 7-9-2013 19:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the definition
 of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

The problem is that it is optional, so when you're reading other people's code you'll still have to deal with inline definitions, and you'll need a decent editor (doesn't have to be an IDE, even basic editors like notepad++ and editpad pro support code folding and function lists) to easily read it.

There's no problem here then! Only two points I'd add to that list are that outlined member functions declared in external modules: - Will error if the aggregate or member declaration is not found (eg: member doesn't exist in aggregate or external module is not imported). - Are mangled as if from the module where the aggregate member is declared. Just clarifies some implementation detail. -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
Sep 07 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/07/2013 07:00 PM, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

 Rationale:

I don't think that the official rationale should include 'readability', giving clear preference to one declaration style over the other.
 Semantics:

First of all, the DIP should address the following additional points: - CTFE (under which circumstances is an outlined member function CTFE-able?) - UDA's - DDOC - Auto return functions
 1. Only member functions of aggregates at module scope can be outlined.

Why module scope? Why just member functions?
 2. Types, parameter types, and pure/const/immutable/shared/nothrow attributes
must match. This is necessary as they affect overloading and so are needed for
correct selection of which declaration is being outlined.

Why would nothrow/pure affect overloading but safe/static not?
 3. Parameter names need not match.

OK. (But maybe it is better to require them to match if given in both places.)
 4. If there is a default parameter value, it may only appear in the member
function declaration.

Probably this is not too bad, but can't you just require the AST to match?
 5.  safe/ trusted/ system, private/package/public/export access, linkage and
storage classes are as set in the declaration, overriding any in effect for the
definition.

Isn't the overriding just confusing for no reason?
 6. Template member functions may not be outlined.

(This is included in point 1.)
 7. Outlined member function return types, parameter types, and function bodies
have private access to the module where the aggregate is declared.

The function names themselves are missing, and maybe you want the type-declaring module to have access to its private function bodies as well if it imports the implementing module. In any case, this is rather ugly. Why not use 'package' for this purpose and keep visibility rather simple? [1] ([1] Well, IMO 'protected' is quite hard to implement in a non-restrictive way in presence of compile-time reflection.)
Sep 07 2013
prev sibling next sibling parent "Jonas Drewsen" <nospam4321 hotmail.com > writes:
 3. Parameter names need not match.

I think we should be conservative and require that parameter names match. This will ensure that code will not break in the future if named parameter functionality is added to the language at some point.
Sep 07 2013
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 http://wiki.dlang.org/DIP47

Am I correct to say that such member definitions will have the same overload rules as before? Currently using UFCS has issues where function hijacking prevention will cause errors at compile time, for example: ----- module a; import b; struct A { } void test(A a) { } // hides B.test! void main() { B b; // error: function a.test (A a) is not // callable using argument types (B) b.test(); } ----- ----- module b; struct B { } void test(B b) { } ----- I just want to ensure that the following does not issue a compiler error: ----- module a; import b; struct A { void test() { } } void A.test() { } // outlined void main() { B b; b.test(); // should be ok, A.test should not hide B.test! } ----- ----- module b; struct B { void test() { } } void B.test() { } // outlined -----
Sep 07 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 12:05 PM, Andrej Mitrovic wrote:
 Am I correct to say that such member definitions will have the same
 overload rules as before?

Yes. This proposal does not add the outlined function name to any other scope than where it is declared, hence it cannot hide anything.
Sep 07 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Sep 07, 2013 at 07:28:39PM +0200, Jos van Uden wrote:
 On 7-9-2013 19:00, Walter Bright wrote:
Outlining of member functions is the practice of placing the
declaration of a member function in the struct/class/union, and
placing the definition of it at global scope in the module or even in
another module.

http://wiki.dlang.org/DIP47

The problem is that it is optional, so when you're reading other people's code you'll still have to deal with inline definitions, and you'll need a decent editor (doesn't have to be an IDE, even basic editors like notepad++ and editpad pro support code folding and function lists) to easily read it.

This in itself is a pretty strong argument against this DIP. It introduces additional cognitive overload (now we have to learn a second syntax for defining class members), and *still* doesn't help the people who want this feature in the first place when they have to read others' code. Not to mention, this will add additional complexity to the parser, and probably introduce more bugs related to function attributes -- for example: - Should function attributes be repeated verbatim across the in-class declaration and the out-of-class definition? If not, where can they be omitted? - What about attribute inference? What if the definition has attributes that conflict with the in-class declaration? - How will this interact with the current DI generation code? - How will it affect forward references (which are currently already rather wonky in certain areas)? - What about nested classes? Will they be allowed to have outlining member functions too? Where should their member definitions be, and what should their syntax be? How will attribute inference work for them? I vote against this DIP. I feel like it's adding a lot of complexity to the language (and probably many more bugs to the compiler) for only a small gain. We already have enough wrinkles yet to be ironed out (scope, shared, auto ref, AA's, inout ambiguities, postblit, tail-const, emplace, the combinatorial explosion of all the different interactions between the foregoing, just to name a few), why are we introducing yet another level of complexity into the mix? T -- Tech-savvy: euphemism for nerdy.
Sep 07 2013
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
On 7 September 2013 20:04, Jonas Drewsen <nospam4321 hotmail.com> wrote:
 3. Parameter names need not match.

I think we should be conservative and require that parameter names match. This will ensure that code will not break in the future if named parameter functionality is added to the language at some point.

What about the absence of parameter names in the declaration? struct Foo { int bar (string, int, int); } int Foo.bar (string str, int start, int end) { /* ... */ } -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
Sep 07 2013
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 3. Parameter names need not match.

I disagree with this, because it will practically guarantee that declarations and definitions go out of sync, which will be *harmful* for readability (which is partly what this DIP is all about).
 4. If there is a default parameter value, it may only appear in the member
function declaration.

Also disagreed, because again you can't tell how a function can be called just by looking at its definition, now you have to go back and forth between the declaration and the definition to fully understand how the function works and how it can be used. On the other hand, allowing both the declaration and the definition to have the default values (which must match of course) might have issues with readability as well: module a; enum val = 1; struct S { void test(int x = val); } module a_impl; enum val = 2; void S.test(int x = val); // a.val or a_impl.val? If 'val' will always refer to a.val in the declaration module, then there's no conflict, however it does create a bit of a readability issue. Still, I think default values should appear at both sides. It's very easy to forget you've defaulted a parameter when you start implementing the function, you could even implement it wrongly.
  safe/ trusted/ system, private/package/public/export access, linkage and
storage classes are as set in the declaration, overriding any in effect for the
definition.

They should both match or there should be an error. Don't allow sloppy code to be written like that, people *will* read both the declarations and the definitions (the team or contributors in an open-source project), and any mismatch will only cause confusion.
Sep 07 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 12:30 PM, Andrej Mitrovic wrote:
 On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 3. Parameter names need not match.

I disagree with this, because it will practically guarantee that declarations and definitions go out of sync, which will be *harmful* for readability (which is partly what this DIP is all about).

Good point.
 4. If there is a default parameter value, it may only appear in the member
function declaration.

Also disagreed, because again you can't tell how a function can be called just by looking at its definition, now you have to go back and forth between the declaration and the definition to fully understand how the function works and how it can be used.

How a function is to be *used* should be all there in the *declaration*. Not the definition. I didn't mention it in the DIP, and should, that the reason for the default value to be in the declaration is 1. it should only depend on the declaration's scope and 2. because all uses of it should rely only on the declaration and 3. because making an exact duplicate of it in the definition is pointless.
 On the other hand, allowing both the declaration and the definition to
 have the default values (which must match of course) might have issues
 with readability as well:

 module a;

 enum val = 1;
 struct S { void test(int x = val); }

 module a_impl;

 enum val = 2;
 void S.test(int x = val);  // a.val or a_impl.val?

 If 'val' will always refer to a.val in the declaration module, then
 there's no conflict, however it does create a bit of a readability
 issue.

 Still, I think default values should appear at both sides. It's very
 easy to forget you've defaulted a parameter when you start
 implementing the function, you could even implement it wrongly.

No, see above.
  safe/ trusted/ system, private/package/public/export access, linkage and
storage classes are as set in the declaration, overriding any in effect for the
definition.

They should both match or there should be an error. Don't allow sloppy code to be written like that, people *will* read both the declarations and the definitions (the team or contributors in an open-source project), and any mismatch will only cause confusion.

I have mixed feelings about this. I think there needs to be just enough in the definition to match it to the declaration, and nothing else.
Sep 07 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 If 'val' will always refer to a.val in the declaration module

I meant if 'val' in the parameter list in the outlined function always refers to 'a.val'.
Sep 07 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 http://wiki.dlang.org/DIP47

 1. Only member functions of aggregates at module scope can be outlined.

This is an unnecessary restriction. You haven't provided any reason in the DIP why #1 is necessary.
Sep 07 2013
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 http://wiki.dlang.org/DIP47

Your example code: ----- struct S { static int mfunc(int a, int b = 5) pure; // member function declaration } int S.mfunc(int a, int b) pure { // member function definition ... } ----- Two things: 1. Why are you demonstrating static functions and not regular member functions (or better yet why not both)? 2. Why has 'static' been removed at the outlined implementation function? It should also be there: static int S.mfunc(int a, int b) pure { // member function definition } To reiterate, let's not introduce a feature where we can be totally lax about what we do at the declaration and implementation site. My strong opinion is that the declaration and implementation must perfectly match, otherwise you can throw the readability argument out the window.
Sep 07 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 12:43 PM, Andrej Mitrovic wrote:
 On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 http://wiki.dlang.org/DIP47

Your example code: ----- struct S { static int mfunc(int a, int b = 5) pure; // member function declaration } int S.mfunc(int a, int b) pure { // member function definition ... } ----- Two things: 1. Why are you demonstrating static functions and not regular member functions (or better yet why not both)?

Because I wanted to point out that you didn't need to put the 'static' in front of the definition.
 2. Why has 'static' been removed at the outlined implementation
 function? It should also be there:

 static int S.mfunc(int a, int b) pure {	// member function definition
 }

Why?
 To reiterate, let's not introduce a feature where we can be totally
 lax about what we do at the declaration and implementation site. My
 strong opinion is that the declaration and implementation must
 perfectly match, otherwise you can throw the readability argument out
 the window.

On the other hand, DRY, and I don't recall anyone ever complaining about this in C++ outlined members.
Sep 07 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

Many details were ommited. Just some of them, others were raised. 1) If you allow to have definition in external module (by the way, this point is not clear), how can you control name mangling? 2) Does outlining limited only to static functions? 3) With UFSC if you have a.foo you cannot know where to found foo(a) - it can be hidden in dozens of imports, and if there are public imports, the situation becomes even more complex.
Sep 07 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 12:56 PM, Maxim Fomin wrote:
 On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration of a
 member function in the struct/class/union, and placing the definition of it at
 global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

Many details were ommited. Just some of them, others were raised. 1) If you allow to have definition in external module (by the way, this point is not clear), how can you control name mangling?

You import the module containing the declaration. Like in C++.
 2) Does outlining limited only to static functions?

No.
 3) With UFSC if you have a.foo you cannot know where to found foo(a) - it can
be
 hidden in dozens of imports, and if there are public imports, the situation
 becomes even more complex.

??? You find the declaration in the module that declares it. Same as for C++.
Sep 07 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

By the way, what is the ratio implemented DIPS/total DIPS? I guess it is <5%. Shouldn't it be a sign of DIP process flaws? I seems that many take care of pushing their ideas in form of DIPs but don't bother to take care of implementing them (last sentence obviously doesn't apply personally to Walter).
Sep 07 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 1:14 PM, Maxim Fomin wrote:
 By the way, what is the ratio implemented DIPS/total DIPS? I guess it is <5%.
 Shouldn't it be a sign of DIP process flaws? I seems that many take care of
 pushing their ideas in form of DIPs but don't bother to take care of
 implementing them (last sentence obviously doesn't apply personally to Walter).

Even if they are unimplemented, the same ideas crop up repeatedly. The DIPs provide an anchor to avoid everyone repeating the same things.
Sep 07 2013
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
Like I said in Manu's thread, we can actually do this already, 
via pragma(mangle) hacks. That's brittle, the compiler doesn't 
tell you if you messed up the signature, but it works and gives 
answers to a lot of the questions in this thread.

class A {
    void foo();
}

pragma(mangle, A.foo.mangleof)
void foo_impl(A _this) {}


That's compile and run today. Things to note:

* The name is figured out by regular importing rules. A is 
whatever A is in schope.

* foo_impl might as well not exist as far as the outside world is 
concerned. It just is A.foo.

* I think the privacy should work this same way too: if it is in 
the same module, it can see private members, if not, it can't.
Sep 07 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
 How a function is to be *used* should be all there in the *declaration*. Not
the definition.

I mean the *header* part of the function's definition (everything up to the closing parens of the parameter list). If someone is currently looking at an implementation file: void S.foo(int x) { ... } They will assume 'x' must be specified. You can argue that people shouldn't be looking at the implementation, but do have in mind two things: 1. This new feature is *optional*, meaning people will still look at the implementation for guidance, and not all new library writers will take advantage of this new feature. This has the consequence that a user looking at a function called "foo", and looking at one called "S.foo" will have to be careful not to assume that "S.foo" documents the parameter list properly (because it can mismatch the declaration if you allow default arguments to be missing). 2. People are already used to looking at implementation files and method implementations in almost all public D projects. Header files have not proven to be popular among D projects.
 I didn't mention it in the DIP, and should, that the reason for the default
value to be in the declaration is
 1. it should only depend on the declaration's scope

The code in the function's body already depends on the declaration's scope. It would be a little strange if the body of the function has access to one scope, but the parameter list has either no scope or a different scope.
Sep 07 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/7/13, Adam D. Ruppe <destructionator gmail.com> wrote:
 pragma(mangle, A.foo.mangleof)
 void foo_impl(A _this) {}

It's cute, but it it doesn't allow you to e.g. implement constructors outside the class. It also doesn't allow you to call a 'super' method without explicitly naming the class. E.g. with the above you can't do: _this.super.foo(); You would have to change it to: _this.ExplicitClassName.foo();
Sep 07 2013
prev sibling next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Walter Bright" <newshound2 digitalmars.com> wrote in message 
news:l0fm2o$2uat$1 digitalmars.com...
 Outlining of member functions is the practice of placing the declaration 
 of a member function in the struct/class/union, and placing the definition 
 of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

I am strongly opposed to this DIP. I think it brings a little slice of C++ hell to D. This change will result in manually-synchronized duplication. The argument that IDEs can deal with this automatically is irrelevant, because they currently can't and are unlikely to do so any time soon. The main motivation for this seems to be that you can't get a clear overview of a class from looking at the raw source code. I propose a much simpler solution to this: ** Introduce compiler-checked (via warnings) class summary documentation. ** This solves the problem - an overview of the class is available in the raw source code, and enabling the warning will prevent them from getting out of sync. Let's solve a documentation issue with documentation improvements.
Sep 07 2013
parent "Joakim" <joakim airpost.net> writes:
On Sunday, 8 September 2013 at 04:32:36 UTC, Daniel Murphy wrote:
 "Walter Bright" <newshound2 digitalmars.com> wrote in message
 news:l0fm2o$2uat$1 digitalmars.com...
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, 
 and placing the definition of it at global scope in the module 
 or even in another module.

 http://wiki.dlang.org/DIP47

I am strongly opposed to this DIP. I think it brings a little slice of C++ hell to D. This change will result in manually-synchronized duplication. The argument that IDEs can deal with this automatically is irrelevant, because they currently can't and are unlikely to do so any time soon. The main motivation for this seems to be that you can't get a clear overview of a class from looking at the raw source code. I propose a much simpler solution to this: ** Introduce compiler-checked (via warnings) class summary documentation. ** This solves the problem - an overview of the class is available in the raw source code, and enabling the warning will prevent them from getting out of sync. Let's solve a documentation issue with documentation improvements.

This generated documentation solution seems like the best approach.
Sep 07 2013
prev sibling next sibling parent "Brian Schott" <briancschott gmail.com> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

It's this post again: Why do all of the DIPs that change the grammar never detail the changes to the grammar?
Sep 07 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 07, 2013 10:00:05 Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration of
 a member function in the struct/class/union, and placing the definition of
 it at global scope in the module or even in another module.
 
 http://wiki.dlang.org/DIP47

I confess that I really don't like this idea. I think that the separation of declarations and definitions is a serious downside of C++ and that it negatively impacts code maintenence. And from the recent discussion on this, it's clear that quite a few people agree with me. However, at the same time, there are some folks (like Manu) who really prefer to separate the declaration and definitions so that they can just see the signatures for an entire class' functions at once without seeing any definitions. Personally, I don't think that that's a big deal and that it's far better to just use generated documentation for that, but clearly there's not a consensus on that. If this DIP is implemented, I do not expect to ever use it, and I hope to never have to deal with code that does (which is ultimately the main reason why I think that it would be a problem if this were implemented - eventually, I'll have to deal with code that uses it even though I think that it harms code maintainibility). But at the same time, I don't know that the fact that quite a few of this really don't like this paradigm is enough a reason to deny it to those who seem to think that it's of value. If I had to vote though, I'd vote against this, because I think that it's a bad paradigm, and I don't want to deal with it. On an implementation note, I don't think that #5 is strong enough. I think that it should be an outright error if there is a difference between the declaration and definition rather than giving one precedence over the other. I'd also be inclined to argue that #3 should be thrown out and that parameters should be required to match, but it's unfortunately not all that uncommon in C++ for folks to not even give parameters names in their declarations, so requiring that the parameters match is probably too much, much as I think that that they should be required to. - Jonathan M Davis
Sep 07 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 9:46 PM, Jonathan M Davis wrote:
 On an implementation note, I don't think that #5 is strong enough. I think
 that it should be an outright error if there is a difference between the
 declaration and definition rather than giving one precedence over the other.

I'll point out that C++ has equivalent behavior, and it has not resulted in any complaints I've ever heard. When you outline a C++ member function, you do not need to add 'static', 'private', 'virtual', and in fact you cannot add the latter two.
Sep 07 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/7/2013 11:08 PM, Peter Williams wrote:
 In summary, you've gotten rid of the need for this type of duplication so why
 would you introduce it?

I believe that is covered in the "Rationale" section of the dip.
Sep 07 2013
prev sibling next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 07.09.2013 19:00, schrieb Walter Bright:
 Outlining of member functions is the practice of placing the declaration of a
 member function in the struct/class/union, and placing the definition of it at
 global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

"Parameter names need not match." please don't do this - that will nearly kill any easy way of finding the implementation, and there is absolutely no reason for differ here - that is too much sort of C/C++ compatible and i think in the end all styleguides around the world will tell you not to change the name on implementation
Sep 07 2013
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 08.09.2013 07:48, schrieb Iain Buclaw:
 On Sep 8, 2013 5:55 AM, "dennis luehring" <dl.soluz gmx.net> wrote:
 Am 07.09.2013 19:00, schrieb Walter Bright:

 Outlining of member functions is the practice of placing the declaration


 member function in the struct/class/union, and placing the definition of


 global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

"Parameter names need not match." please don't do this - that will nearly kill any easy way of finding the

That depends on your coding style and is not necessarily true. Eg: I put function names at the start of the line. int foo_bar () { } So all global functions are easily grep'able ('^foo_bar'). Same thing is also done with C++ outlined members ('^Class::foo_bar') and I could see myself adopting the same for D aggregate methods too. Regards

im talking about "Parameter names need not match." so it will become hard to find the same overload of a method if someone else writes int a, int b in declaration and int pa, int pb in implementation - and the only benefit is beeing compatible with c/c++ - that will introduce another point in all D-coding-style guides around the world not to rename parameter in implementation
Sep 07 2013
parent dennis luehring <dl.soluz gmx.net> writes:
Am 08.09.2013 08:46, schrieb Iain Buclaw:
 im talking about "Parameter names need not match."
 so it will become hard to find the same overload of a method if someone else
 writes int a, int b in declaration and int pa, int pb in implementation -
 and the only benefit is beeing compatible with c/c++ - that will introduce
 another point in all D-coding-style guides around the world not to rename
 parameter in implementation

I was talking about "Parameter names need not match" too... I disagree that mismatched parameter names makes things hard to find, and by way of example, I just search for the function. I never say "right, I need to find this implementation" and grep for the parameter list in the declaration...

i work as a independed refactorig/bug hunter developer on big team (30+ developers) big projects (1Mio LOC+) - i need to do that most of the time - i like D for beeing better refactorable/readable in the long run (years) of projects different people - different needs
Sep 08 2013
prev sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
On 8 September 2013 07:14, dennis luehring <dl.soluz gmx.net> wrote:
 Am 08.09.2013 07:48, schrieb Iain Buclaw:
 On Sep 8, 2013 5:55 AM, "dennis luehring" <dl.soluz gmx.net> wrote:
 Am 07.09.2013 19:00, schrieb Walter Bright:

 Outlining of member functions is the practice of placing the declaration


of a
 member function in the struct/class/union, and placing the definition of


it at
 global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

"Parameter names need not match." please don't do this - that will nearly kill any easy way of finding the

implementation, That depends on your coding style and is not necessarily true. Eg: I put function names at the start of the line. int foo_bar () { } So all global functions are easily grep'able ('^foo_bar'). Same thing is also done with C++ outlined members ('^Class::foo_bar') and I could see myself adopting the same for D aggregate methods too. Regards

im talking about "Parameter names need not match." so it will become hard to find the same overload of a method if someone else writes int a, int b in declaration and int pa, int pb in implementation - and the only benefit is beeing compatible with c/c++ - that will introduce another point in all D-coding-style guides around the world not to rename parameter in implementation

I was talking about "Parameter names need not match" too... I disagree that mismatched parameter names makes things hard to find, and by way of example, I just search for the function. I never say "right, I need to find this implementation" and grep for the parameter list in the declaration... Regards -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
Sep 07 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 07, 2013 21:30:10 Andrej Mitrovic wrote:
 On 9/7/13, Walter Bright <newshound2 digitalmars.com> wrote:
  safe/ trusted/ system, private/package/public/export access, linkage and
 storage classes are as set in the declaration, overriding any in effect
 for the definition.

code to be written like that, people *will* read both the declarations and the definitions (the team or contributors in an open-source project), and any mismatch will only cause confusion.

Agreed. If we're going to do this, let's not allow the possibility of mismatches or it will make the maintenance problems that this DIP introduces even worse (though I'd prefer that we not implement it at all). - Jonathan M Davis
Sep 07 2013
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 07, 2013 10:00:05 Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration of
 a member function in the struct/class/union, and placing the definition of
 it at global scope in the module or even in another module.
 
 http://wiki.dlang.org/DIP47

Actually, for those who really want this sort of thing, why don't they just use .di files? At that point, you're doing basically the same thing that C++ does anyway (which is part of why I hate .di files). What benefit over that do we really get by adding this feature? - Jonathan M Davis
Sep 07 2013
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
08-Sep-2013 09:00, Jonathan M Davis пишет:
 On Saturday, September 07, 2013 10:00:05 Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration of
 a member function in the struct/class/union, and placing the definition of
 it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

Actually, for those who really want this sort of thing, why don't they just use .di files? At that point, you're doing basically the same thing that C++ does anyway (which is part of why I hate .di files). What benefit over that do we really get by adding this feature?

And speaking of IDEs, they easily grow a simple feature - press some short-cut and it would display what dmd -H of the current file looks like. No need to bend the language backwards.
 - Jonathan M Davis

-- Dmitry Olshansky
Sep 08 2013
prev sibling parent Martin Nowak <code dawg.eu> writes:
On 09/08/2013 07:00 AM, Jonathan M Davis wrote:
 Actually, for those who really want this sort of thing, why don't they just
 use .di files?

One important point is being able to verify the definition against the declaration which isn't currently possible.
Sep 09 2013
prev sibling next sibling parent Lionello Lunesu <lionello lunesu.remove.com> writes:
On 9/8/13 1:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

I would restrict it to a single module for the time being. We can always open it up to other modules later, but we wouldn't be able to restrict it back to a single module, since that would be a breaking change. L.
Sep 07 2013
prev sibling next sibling parent "Ramon" <spam thanks.no> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

I'm against that. Reasons: - Do not change a language without very solid or even urgent need. - A concise spec (we are going there that, right?) and reliability is way more important than gadgets or "X has that. We need that, too!". - What for? This approach is anyway not the right one. If this is about readability then ... ... what's the big issue? "I don't like 'class ...{' at the beginning of my source code and a '}' at the end"? Because that's what it comes down to. If this is about readability as in "I want to have a quick and comfortable look at my module or class interface" (which is a reasonable desire and a useful thing) then ... ... the solution is not to change the language but to have a compiler switch to have the compiler generate a client/interface view file. (One might discuss what exactly should should go there) A+ -R
Sep 07 2013
prev sibling next sibling parent Iain Buclaw <ibuclaw ubuntu.com> writes:
--047d7bdc0b3cd799e004e5d8d1da
Content-Type: text/plain; charset=ISO-8859-1

On Sep 8, 2013 5:55 AM, "dennis luehring" <dl.soluz gmx.net> wrote:
 Am 07.09.2013 19:00, schrieb Walter Bright:

 Outlining of member functions is the practice of placing the declaration


 member function in the struct/class/union, and placing the definition of


 global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

"Parameter names need not match." please don't do this - that will nearly kill any easy way of finding the

That depends on your coding style and is not necessarily true. Eg: I put function names at the start of the line. int foo_bar () { } So all global functions are easily grep'able ('^foo_bar'). Same thing is also done with C++ outlined members ('^Class::foo_bar') and I could see myself adopting the same for D aggregate methods too. Regards -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; --047d7bdc0b3cd799e004e5d8d1da Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <p>On Sep 8, 2013 5:55 AM, &quot;dennis luehring&quot; &lt;<a href=3D"mailt= o:dl.soluz gmx.net">dl.soluz gmx.net</a>&gt; wrote:<br> &gt;<br> &gt; Am 07.09.2013 19:00, schrieb Walter Bright:<br> &gt;<br> &gt;&gt; Outlining of member functions is the practice of placing the decla= ration of a<br> &gt;&gt; member function in the struct/class/union, and placing the definit= ion of it at<br> &gt;&gt; global scope in the module or even in another module.<br> &gt;&gt;<br> &gt;&gt; <a href=3D"http://wiki.dlang.org/DIP47">http://wiki.dlang.org/DIP4= 7</a><br> &gt;&gt;<br> &gt;<br> &gt;<br> &gt; &quot;Parameter names need not match.&quot;<br> &gt;<br> &gt; please don&#39;t do this - that will nearly kill any easy way of findi= ng the implementation,</p> <p>That depends on your coding style and is not necessarily true.=A0 Eg: I = put function names at the start of the line.</p> <p>int<br> foo_bar ()<br> {<br> }</p> <p>So all global functions are easily grep&#39;able (&#39;^foo_bar&#39;).</= p> <p>Same thing is also done with C++ outlined members (&#39;^Class::foo_bar&= #39;) and I could see myself adopting the same for D aggregate methods too.= <br></p> <p>Regards<br> -- <br> Iain Buclaw</p> <p>*(p &lt; e ? p++ : p) =3D (c &amp; 0x0f) + &#39;0&#39;;<br> </p> --047d7bdc0b3cd799e004e5d8d1da--
Sep 07 2013
prev sibling next sibling parent "Brian Schott" <briancschott gmail.com> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

"Parameter names need not match." I can't wait to implement a static code analysis rule that yells at people for not having them match. "If there is a default parameter value, it may only appear in the member function declaration." Shouldn't they match? " safe/ trusted/ system, private/package/public/export access, linkage and storage classes are as set in the declaration, overriding any in effect for the definition." Again. Someone will create a static code analysis tool that warns about this. Why allow it in the language?
Sep 07 2013
prev sibling next sibling parent Peter Williams <pwil3058 bigpond.net.au> writes:
On 08/09/13 15:40, Walter Bright wrote:
 On 9/7/2013 9:46 PM, Jonathan M Davis wrote:
 On an implementation note, I don't think that #5 is strong enough. I
 think
 that it should be an outright error if there is a difference between the
 declaration and definition rather than giving one precedence over the
 other.

I'll point out that C++ has equivalent behavior, and it has not resulted in any complaints I've ever heard. When you outline a C++ member function, you do not need to add 'static', 'private', 'virtual', and in fact you cannot add the latter two.

Here's one. It's one of the things that I don't like about C/C++ as it doubles the work required in code maintenance. One of the things that I like about D is that forward references aren't required and this seems to me to be introducing a feature that was only ever in C/C++ to make forward references possible (which is why I tolerated it). In summary, you've gotten rid of the need for this type of duplication so why would you introduce it? Peter
Sep 07 2013
prev sibling next sibling parent "Paolo Invernizzi" <paolo.invernizzi gmail.com> writes:
On Sunday, 8 September 2013 at 06:47:14 UTC, Walter Bright wrote:
 On 9/7/2013 11:08 PM, Peter Williams wrote:
 In summary, you've gotten rid of the need for this type of 
 duplication so why
 would you introduce it?

I believe that is covered in the "Rationale" section of the dip.

IMHO the rationale of the proposal il pretty weak: - You can't have a 1:1 correspondence with translated C++ code, so the translation barrier can be lower. - You can't read _easily_ the code. The first is not a problem, if it is true that D avoidance of duplication is better than C++ way of doing that stuff (and that's a C++ problem, as Peter suggested). I would also add that I don't think at all that this is a concrete translation barrier: usually I start copying and pasting the C++ header in the D code, and then filling the methods translating from the cpp part one after another. The second point is more subtle, as we are talking about an easy _navigation_ in the code in the editor, we are talking about being able to "gain a sense of familiarity" with foreign code? The former is something that should not impact over the language at all (alas, C++ navigation, back and forth between header and implementation is a mess), The latter resolved by D with DDOC, which it is perfectible BUT is _today_ a wonderful tool for strangers: the D library section on DLang site is there to prove it. You have at a glance all the definitions, documented and in sync with the last compilation. What is missing from that? - Paolo Invernizzi
Sep 08 2013
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
I'm against it. More important than such a gimmick are the many 
open bugs, auto ref, AA, scope, etc. And don't forget the 
implementation of the virtual keyword.
Sep 08 2013
prev sibling next sibling parent "Michael" <pr m1xa.com> writes:
On Sunday, 8 September 2013 at 09:15:52 UTC, Namespace wrote:
 I'm against it. More important than such a gimmick are the many 
 open bugs, auto ref, AA, scope, etc. And don't forget the 
 implementation of the virtual keyword.

+1
Sep 08 2013
prev sibling next sibling parent "Tove" <tove fransson.se> writes:
On Sunday, 8 September 2013 at 09:24:52 UTC, Michael wrote:
 On Sunday, 8 September 2013 at 09:15:52 UTC, Namespace wrote:
 I'm against it. More important than such a gimmick are the 
 many open bugs, auto ref, AA, scope, etc. And don't forget the 
 implementation of the virtual keyword.

+1

I strongly dislike DIP47, I found many unintended discrepancies in our C code-base at work... precisely because of "lax rules", even cases with wrong linkage as result! "Parameter names need not match." "If there is a default parameter value, it may only appear in the member function declaration." This forces indexing of source and jump to declaration features in the IDE, the current way is more friendly to simpler text-editors, the problem which DIP47 is trying to solve is anyway solved by IDE:s "Class View" feature etc. i.e. For people using IDE:s(class view, or ddoc) nothing changes with DIP47. For people using plain editors, DIP47 makes it worse. Even if DIP47 is implemented, I hope this feature is strongly discouraged in the standard library.
Sep 08 2013
prev sibling next sibling parent "Tove" <tove fransson.se> writes:
Wouldn't this style be an acceptable compromise instead? with 
both declaration and definition 100% identical.

struct S
{
   // member function declarations
   static int mfunc1(int a, int b = 5) pure;
   static int mfunc2(int a, int b = 5) pure;
   static int mfunc3(int a, int b = 5) pure;

   // member function definitions
   static int mfunc1(int a, int b = 5) pure
   {
   }
   static int mfunc2(int a, int b = 5) pure
   {
   }
   static int mfunc3(int a, int b = 5) pure
   {
   }
}
Sep 08 2013
prev sibling next sibling parent Robert Schadek <realburner gmx.de> writes:
On 09/08/2013 06:46 AM, Jonathan M Davis wrote:
 If I had to vote though, I'd vote against this, because I think that
 it's a bad paradigm, and I don't want to deal with it. 

+1
Sep 08 2013
prev sibling next sibling parent "nazriel" <spam dzfl.pl> writes:
On Sunday, 8 September 2013 at 10:59:34 UTC, Robert Schadek wrote:
 On 09/08/2013 06:46 AM, Jonathan M Davis wrote:
 If I had to vote though, I'd vote against this, because I 
 think that
 it's a bad paradigm, and I don't want to deal with it.

+1

+1 Also issues mentioned by Manu are easily solvable: DI files and/or DDOC + remove one level of indentation after class: --- class Foo { void foo() { writeln("hello world"); } } --- ;)
Sep 08 2013
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-09-07 17:00:05 +0000, Walter Bright <newshound2 digitalmars.com> said:

 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and placing 
 the definition of it at global scope in the module or even in another 
 module.
 
 http://wiki.dlang.org/DIP47

About placing the definition in another module, you say that the definition when outlined in another module would have private access to the private members of the module of declaration. Does that mean that the definition has access to the private members of two modules at the same time, the one it is declared in and the one it is defined in? That seems strange to me. I find it strange that pure/const/immutable/shared/nothrow need to match, yet static does not. Beside this being the way it works in C++ (presumably because static at global scope has another meaning inherited from C), I see no reason for this. In C++ I often find myself wondering whether a function has access to the member variables and I have to find the definition in the header file, which is inconvenient. Static being part of the definition seems to only make sense. About parameter names, I think it'd be better if they were forced to match. Mismatches are a code smell to me: if you reverse the meaning of two parameters with the same type while refactoring, you must be sure the public interface and the implementation still agree. I guess you could allow the declaration to omit the parameter names in which case the definition could add a name, but don't allow *different* names, it's pointless and it can easily hide a bug. I think it's fine that default values for parameters don't have to be repeated, but it'd be nice if they *could* because it enables copy-pasting of the declarations. The compiler would of course have to check that both expressions are identical. I'd like to make a suggestion. If one goal is effectively to allow the implementation of a function to live in a separate file from its declaration, then we already have a mechanism for that: .di files. So I'd like to suggest this: allow a .d file to "import" its corresponding .di file. Then the .d file should only contain the missing definitions for what's declared in the hand-crafted .di file. That'd remove the dubious semantics of making the definition part of another module and would also allow outlining of global functions. And it also matches better the C++ model of header/implementation files. Also, I'd allow outlining only for this specific case where a .di file is imported by a .d file. This way you know for sure when you see a declaration without the definition in a .di file that this declaration is in the corresponding .d file and not anywhere else, making it easier to hunt it down. Example: // test.di module test; class A { void foo(int a, int b); } // test.d import module test; // import declarations from the .di file void A.foo(int a, int b) { // member function definition } -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Sep 08 2013
next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
08-Sep-2013 16:02, Michel Fortin пишет:
 On 2013-09-07 17:00:05 +0000, Walter Bright <newshound2 digitalmars.com>
 said:

 Outlining of member functions is the practice of placing the
 declaration of a member function in the struct/class/union, and
 placing the definition of it at global scope in the module or even in
 another module.

 http://wiki.dlang.org/DIP47

About placing the definition in another module, you say that the definition when outlined in another module would have private access to the private members of the module of declaration. Does that mean that the definition has access to the private members of two modules at the same time, the one it is declared in and the one it is defined in? That seems strange to me.

Same here. This was the ugliest point. [snip]
 I'd like to make a suggestion. If one goal is effectively to allow the
 implementation of a function to live in a separate file from its
 declaration, then we already have a mechanism for that: .di files. So
 I'd like to suggest this: allow a .d file to "import" its corresponding
 .di file. Then the .d file should only contain the missing definitions
 for what's declared in the hand-crafted .di file. That'd remove the
 dubious semantics of making the definition part of another module and
 would also allow outlining of global functions. And it also matches
 better the C++ model of header/implementation files.

 Also, I'd allow outlining only for this specific case where a .di file
 is imported by a .d file. This way you know for sure when you see a
 declaration without the definition in a .di file that this declaration
 is in the corresponding .d file and not anywhere else, making it easier
 to hunt it down.

 Example:

      // test.di
      module test;

      class A {
          void foo(int a, int b);
      }

      // test.d
      import module test; // import declarations from the .di file

      void A.foo(int a, int b) {
          // member function definition
      }

With this suggestion it finally becomes sane. -- Dmitry Olshansky
Sep 08 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Sunday, 8 September 2013 at 12:34:06 UTC, Andrej Mitrovic 
wrote:
 On 9/8/13, Michel Fortin <michel.fortin michelf.ca> wrote:
 So I'd like to suggest this: allow a .d file to "import" its 
 corresponding
 .di file.

This is actually what Andrei proposed as well.

+42
Sep 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 8 September 2013 at 15:14:51 UTC, deadalnix wrote:
 On Sunday, 8 September 2013 at 12:34:06 UTC, Andrej Mitrovic 
 wrote:
 On 9/8/13, Michel Fortin <michel.fortin michelf.ca> wrote:
 So I'd like to suggest this: allow a .d file to "import" its 
 corresponding
 .di file.

This is actually what Andrei proposed as well.

+42

That is why I had a feeling I have already seen it somewhere :)
Sep 08 2013
prev sibling next sibling parent "Ettienne Gilbert" <ettienne.gilbert gmail.com> writes:
On Sunday, 8 September 2013 at 13:00:11 UTC, Dmitry Olshansky 
wrote:
 08-Sep-2013 16:02, Michel Fortin пишет:

 Example:

     // test.di
     module test;

     class A {
         void foo(int a, int b);
     }

     // test.d
     import module test; // import declarations from the .di 
 file

     void A.foo(int a, int b) {
         // member function definition
     }

With this suggestion it finally becomes sane.

+1
Sep 08 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/8/13 5:33 AM, Andrej Mitrovic wrote:
 On 9/8/13, Michel Fortin <michel.fortin michelf.ca> wrote:
 So I'd like to suggest this: allow a .d file to "import" its corresponding
 .di file.

This is actually what Andrei proposed as well.

I have to say I was a lot more in favor of the proposal before this thread. The problem as I see it has two facets: 1. Code duplication 2. Modularity and logistics Regarding (1), we currently force duplication of the entire class layout. My understanding is that this is the way it's done: // file acme.di class A { int x; double y; void fun(); } // file acme.d // cannot import acme.di class A { int x; double y; void fun() { ... } } The fact that acme.d cannot import acme.di is an unforced error of embarrassing proportions and consequence. That should be fixed yesterday no matter how we proceed otherwise. The problem with acme.d not having access to acme.di is that any error in duplicating the layout of A (e.g. swapping x and y or adding some other members etc) will have undefined behavior, and there is no reasonable way for the compiler to check against that. Assuming that bug is fixed, the problem of duplication remains - all state of the class must be duplicated. (I also suspect constructors might need to be white-boxed (i.e. available in the .di) for raw/cooked typechecking, but I'm not sure.) If we go with DIP47, the duplication of state goes away. However we have a distinct problem - modularity, which segues into (2). Allowing out-of-module implementations of individual methods poses additional modularity problems. Consider: // file acme.di class A { int x; double y; void fun(); } private int a; private void gun(); // file acme.d // assume we solve the import problem import acme; void A.fun() { gun(); a = 42; } If A.fun() were defined inside acme.di, it would have access to gun() and a. Defining it outside asks the question - do we allow such access, or not? Intuitively the body of a method should not be all too sensitive to where it's placed, so that argues in favor of visibility. D's module system has always favored a file-granular approach, e.g. private stuff is module-private. This notion of spilling private access outside the file into methods defined in various other files works against that nice tenet. So it looks there's no obvious and obviously good solution. Probably the first one is more sensible. Andrei
Sep 08 2013
next sibling parent Paulo Pinto <pjmlp progtools.org> writes:
Am 09.09.2013 02:03, schrieb Andrei Alexandrescu:
 On 9/8/13 5:33 AM, Andrej Mitrovic wrote:
 On 9/8/13, Michel Fortin <michel.fortin michelf.ca> wrote:
 So I'd like to suggest this: allow a .d file to "import" its
 corresponding
 .di file.

This is actually what Andrei proposed as well.

I have to say I was a lot more in favor of the proposal before this thread. The problem as I see it has two facets: 1. Code duplication 2. Modularity and logistics Regarding (1), we currently force duplication of the entire class layout. My understanding is that this is the way it's done: // file acme.di class A { int x; double y; void fun(); } // file acme.d // cannot import acme.di class A { int x; double y; void fun() { ... } } The fact that acme.d cannot import acme.di is an unforced error of embarrassing proportions and consequence. That should be fixed yesterday no matter how we proceed otherwise. The problem with acme.d not having access to acme.di is that any error in duplicating the layout of A (e.g. swapping x and y or adding some other members etc) will have undefined behavior, and there is no reasonable way for the compiler to check against that. Assuming that bug is fixed, the problem of duplication remains - all state of the class must be duplicated. (I also suspect constructors might need to be white-boxed (i.e. available in the .di) for raw/cooked typechecking, but I'm not sure.) If we go with DIP47, the duplication of state goes away. However we have a distinct problem - modularity, which segues into (2). Allowing out-of-module implementations of individual methods poses additional modularity problems. Consider: // file acme.di class A { int x; double y; void fun(); } private int a; private void gun(); // file acme.d // assume we solve the import problem import acme; void A.fun() { gun(); a = 42; } If A.fun() were defined inside acme.di, it would have access to gun() and a. Defining it outside asks the question - do we allow such access, or not? Intuitively the body of a method should not be all too sensitive to where it's placed, so that argues in favor of visibility. D's module system has always favored a file-granular approach, e.g. private stuff is module-private. This notion of spilling private access outside the file into methods defined in various other files works against that nice tenet. So it looks there's no obvious and obviously good solution. Probably the first one is more sensible. Andrei

The approach should be like in Modula-2 family, only public stuff is allowed in .di files. -- Paulo
Sep 09 2013
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/8/2013 5:03 PM, Andrei Alexandrescu wrote:
 D's module system has always favored a file-granular approach, e.g. private
 stuff is module-private. This notion of spilling private access outside the
file
 into methods defined in various other files works against that nice tenet.

 So it looks there's no obvious and obviously good solution. Probably the first
 one is more sensible.

One solution that has been proposed here (by Manu and perhaps others) is that the outlined functions can only appear inside the same module that the declaration is in. This would resolve the private access problem and the modularity problem.
Sep 09 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/9/13 5:12 PM, Walter Bright wrote:
 On 9/8/2013 5:03 PM, Andrei Alexandrescu wrote:
 D's module system has always favored a file-granular approach, e.g.
 private
 stuff is module-private. This notion of spilling private access
 outside the file
 into methods defined in various other files works against that nice
 tenet.

 So it looks there's no obvious and obviously good solution. Probably
 the first
 one is more sensible.

One solution that has been proposed here (by Manu and perhaps others) is that the outlined functions can only appear inside the same module that the declaration is in. This would resolve the private access problem and the modularity problem.

It also reduces the motivation for the thing as it becomes a minor convenience. Andrei
Sep 09 2013
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/9/2013 5:39 PM, Andrei Alexandrescu wrote:
 On 9/9/13 5:12 PM, Walter Bright wrote:
 This would resolve the private access problem and the modularity problem.

It also reduces the motivation for the thing as it becomes a minor convenience.

Yup.
Sep 09 2013
prev sibling parent Michel Fortin <michel.fortin michelf.ca> writes:
On 2013-09-09 00:03:11 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 D's module system has always favored a file-granular approach, e.g. 
 private stuff is module-private. This notion of spilling private access 
 outside the file into methods defined in various other files works 
 against that nice tenet.

Is the D module system file-granular or module-granular? I always thought the later. Putting the implementation of functions in the .d file while the declarations are in the corresponding .di does not change things much: it's still one module, but it's one module split over two files. It also helps solve another problem: the problem where you're shipping a library and want to force some things to not be inlined. This is needed if the library is to be swapped for another version without having to recompile all client code. You can do this currently by hand-crafting .di files, but it's a pain to keep it manually in sync with the .d file. -- Michel Fortin michel.fortin michelf.ca http://michelf.ca
Sep 09 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 09, 2013 at 10:09:51PM -0400, Michel Fortin wrote:
 On 2013-09-09 00:03:11 +0000, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:
 
D's module system has always favored a file-granular approach,
e.g. private stuff is module-private. This notion of spilling
private access outside the file into methods defined in various
other files works against that nice tenet.

Is the D module system file-granular or module-granular? I always thought the later. Putting the implementation of functions in the .d file while the declarations are in the corresponding .di does not change things much: it's still one module, but it's one module split over two files. It also helps solve another problem: the problem where you're shipping a library and want to force some things to not be inlined. This is needed if the library is to be swapped for another version without having to recompile all client code. You can do this currently by hand-crafting .di files, but it's a pain to keep it manually in sync with the .d file.

It would be nice if UDAs can somehow be used to mark functions as don't-inline, so that dmd -H produces the correct .di file without requiring manual maintenance. T -- Mediocrity has been pushed to extremes.
Sep 09 2013
prev sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 10/09/13 04:09, Michel Fortin wrote:
 Is the D module system file-granular or module-granular? I always thought the
 later. Putting the implementation of functions in the .d file while the
 declarations are in the corresponding .di does not change things much: it's
 still one module, but it's one module split over two files.

 It also helps solve another problem: the problem where you're shipping a
library
 and want to force some things to not be inlined. This is needed if the library
 is to be swapped for another version without having to recompile all client
 code. You can do this currently by hand-crafting .di files, but it's a pain to
 keep it manually in sync with the .d file.

Is it possible to manually craft some parts of the .di file, while being able to rely on the compiler to automatically add any module contents that aren't manually declared? If so it might be the best solution to everyone's concerns.
Sep 10 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/8/13, Michel Fortin <michel.fortin michelf.ca> wrote:
 So I'd like to suggest this: allow a .d file to "import" its corresponding
 .di file.

This is actually what Andrei proposed as well.
Sep 08 2013
prev sibling next sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

I'm absolutely against this DIP. This proposal is just going back to the hell of header files again. Why on earth would you emulate C/C++ when D was supposed to be designed taking into account lessons learned from them. This is unnecessary complexity added for the sake of a few programmers who can't get out of C++ mode. I think you need to have a good hard think about *why* header files were introduced into those early languages and then consider if that reason is still valid. Personally i don't think it is. Java and C# do just fine without this. Seriously, this goes against everything you learn as a programmer, nothing should ever be typed twice and then to say that the declaration and implementation could be different just boggles my mind?!?! Great more work! If implemented, i will never used this feature and i will never deal with code that uses it either. I choose D *purely* because it didn't have this header file nonsense. If i find in future i start seeing more and more of this style of D code i would just move on to use something else that doesn't have all this extra baggage and work associated with it. Just because Manu brings it up randomly you decide to create a DIP? In reality this is a documentation issue. Which has already been addressed by DDOC or *.di files. If data exists in one form, and it is needed in another, that's work a computer should do. Not a human! IDE's also give you numerous tools to get class overviews and such. If you are suggesting that you also need these class overviews in code to be viewed on github etc, just use comments. They are as arbitrary and simpler to implement. Honestly this DIP is going backwards, i was under the impression D was going forwards! I am so disappointed.
Sep 08 2013
next sibling parent Paulo Pinto <pjmlp progtools.org> writes:
Am 08.09.2013 15:11, schrieb Gary Willoughby:
 On Sunday, 8 September 2013 at 12:53:11 UTC, Dicebot wrote:
 Seriously, this goes against everything you learn as a programmer,
 nothing should ever be typed twice and then to say that the
 declaration and implementation could be different just boggles my
 mind?!?! Great more work!

It is no different from overriding `interface` methods in class. From the code structure point of view, declaration is interface. Implementation is implementation. Keeping those separate may sometimes/often be useful. That said, I am strongly against permissive rules proposed in this DIP. It should be similar to overriding rules - any smallest difference between to signatures and program stops compiling. Otherwise it is maintenance hell.

Well you've just argued against your first paragraph there. The issue is (as you recognise) the extra complexity introduced with having a declaration and an implementation both of which could be different and/or not clear how they relate. But it goes further than that. If this DIP is implemented and you are working with code written like this you now have to change the code in two places when you want to update a method. Also you now have to find the implementation or declaration which is a total pain when not using an IDE. You now have more files. Longer compilation times. All for what? Not using -D on the command line? Come on! This is entirely different to how overloading works because in that scenario you are explicitly saying in your code this method overrides the parent (or interface) with this one that matches that signature exactly. There is no duplication, it's explicit overriding which is different. Also could you give me any examples of where keeping the declaration separate to the implementation is "sometimes/often useful". Because IMHO it only adds work and Java and C# do just fine. I don't think Walter realises how much of a plus point it is for D to not have this 'feature'. I mean if this was implemented and code started appearing written in this style (as it will) why would people choose D over C++ to get stuff done when they both offer the same headaches now?

Not only Java and C#, but any other language with module support, even the ones that have native compilers by default. The ones that offer interface definitions, like Delphi, Modula-{2,3}, ML family among many others, have a model that D already offers via the .di files. So I also agree this is a step backwards. -- Paulo
Sep 08 2013
prev sibling parent Paulo Pinto <pjmlp progtools.org> writes:
Am 09.09.2013 16:36, schrieb H. S. Teoh:
 On Mon, Sep 09, 2013 at 03:26:23PM +0200, PauloPinto wrote:
 On Monday, 9 September 2013 at 12:28:54 UTC, Dicebot wrote:
 On Monday, 9 September 2013 at 00:43:39 UTC, H. S. Teoh wrote:
 Therefore, the *real* solution to this problem is to fix the
 compiler's .di output to give a proper overview of the class
 *automatically*, and nicely pretty-printed.

Yes, that should be superior approach in general though exact usability is very detail-specific - currently relation between .di and .d and not really well-defined and pulling this off will requires its own DIP at the very least. For example, it is not entirely clear to me, what should happen if there are both .di and .d files in the file system at the same time and they have minor difference (remember, it is perfectly legal to tweak .di manually).


I'd propose to make it such that you *don't* have to tweak the .di manually. Maybe the use of UDAs could help get rid of the need to edit .di by hand, by instructing the compiler what kind of output is desired. Anything that requires hand-tweaking is unreliable and prone to errors and careless bugs. The best way is to have .di completely automated.
 It is likely, that improving .di
 tool chain will require similar signature matching verification
 anyway. Also I am wondering how to differ purely auto-generated .di
 files (should be updated completely upon build) and ones with
 manual changes (should be only verified).

 It is all about small details.

In languages like Modula-2, it is a compile error if there are differences. So I would say D compilers should follow the same behavior, unless it is requested to generate .di files automatically, which will then overwrite the corresponding .di files.

I think it is a bug for the .di and .d to have mismatches. For example, I don't see how the following code could be correct: ---module.di--- int func(int x) pure; ---module.d--- int global; int func(int x) { return global; } Any such mismatch should be considered a bug. In fact, the current lax enforcement of matching makes it possible for something to be declared pure safe nothrow in .di, but impure system throwing in .d. I think there has been a few bugs like this in druntime that got fixed. T

I should have read your earlier post better. The better approach would then be like the compilers of the Oberon language family do, by generating the interface file when compiling the packages. -- Paulo
Sep 09 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 8 September 2013 at 12:46:49 UTC, Gary Willoughby 
wrote:
 This proposal is just going back to the hell of header files 
 again.

It has nothing to do with header files. Or real header file problems.
 Seriously, this goes against everything you learn as a 
 programmer, nothing should ever be typed twice and then to say 
 that the declaration and implementation could be different just 
 boggles my mind?!?! Great more work!

It is no different from overriding `interface` methods in class. From the code structure point of view, declaration is interface. Implementation is implementation. Keeping those separate may sometimes/often be useful. That said, I am strongly against permissive rules proposed in this DIP. It should be similar to overriding rules - any smallest difference between to signatures and program stops compiling. Otherwise it is maintenance hell.
Sep 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
P.S. In general I'd love to have feature feature proposed in 
DIP47  but its importance is very, _very_ low, right now it is 
probably the least important DIP in the whole list.
Sep 08 2013
prev sibling next sibling parent "Gary Willoughby" <dev nomad.so> writes:
On Sunday, 8 September 2013 at 12:53:11 UTC, Dicebot wrote:
 Seriously, this goes against everything you learn as a 
 programmer, nothing should ever be typed twice and then to say 
 that the declaration and implementation could be different 
 just boggles my mind?!?! Great more work!

It is no different from overriding `interface` methods in class. From the code structure point of view, declaration is interface. Implementation is implementation. Keeping those separate may sometimes/often be useful. That said, I am strongly against permissive rules proposed in this DIP. It should be similar to overriding rules - any smallest difference between to signatures and program stops compiling. Otherwise it is maintenance hell.

Well you've just argued against your first paragraph there. The issue is (as you recognise) the extra complexity introduced with having a declaration and an implementation both of which could be different and/or not clear how they relate. But it goes further than that. If this DIP is implemented and you are working with code written like this you now have to change the code in two places when you want to update a method. Also you now have to find the implementation or declaration which is a total pain when not using an IDE. You now have more files. Longer compilation times. All for what? Not using -D on the command line? Come on! This is entirely different to how overloading works because in that scenario you are explicitly saying in your code this method overrides the parent (or interface) with this one that matches that signature exactly. There is no duplication, it's explicit overriding which is different. Also could you give me any examples of where keeping the declaration separate to the implementation is "sometimes/often useful". Because IMHO it only adds work and Java and C# do just fine. I don't think Walter realises how much of a plus point it is for D to not have this 'feature'. I mean if this was implemented and code started appearing written in this style (as it will) why would people choose D over C++ to get stuff done when they both offer the same headaches now?
Sep 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 8 September 2013 at 13:11:01 UTC, Gary Willoughby 
wrote:
 That said, I am strongly against permissive rules proposed in 
 this DIP. It should be similar to overriding rules - any 
 smallest difference between to signatures and program stops 
 compiling. Otherwise it is maintenance hell.

Well you've just argued against your first paragraph there. The issue is (as you recognise) the extra complexity introduced with having a declaration and an implementation both of which could be different and/or not clear how they relate.

Not really. Issue is cognitive load of matching definition and declaration if they are allowed to be out of sync.
 But it goes further than that. If this DIP is implemented and 
 you are working with code written like this you now have to 
 change the code in two places when you want to update a method. 
 Also you now have to find the implementation or declaration 
 which is a total pain when not using an IDE.

I consider it a minor inconvenience for a certain structural gain.
 This is entirely different to how overloading works because in 
 that scenario you are explicitly saying in your code this 
 method overrides the parent (or interface) with this one that 
 matches that signature exactly. There is no duplication, it's 
 explicit overriding which is different.

overloading != overriding. I am speaking about overriding. From the maintenance point of view this two snippets are identical: --- interface A { void foo(); } class A_prim : A { void foo() { } } --- class A { void foo(); } void A.foo() { } --- Same amount of duplication, same amount of information available for compiler verification.
 Also could you give me any examples of where keeping the 
 declaration separate to the implementation is "sometimes/often 
 useful". Because IMHO it only adds work and Java and C# do just 
 fine.

I have never worked on any reasonably large Java/C# code base. But it C++ once amount of entities grows large enough clear interface overview in header files is basically only way to get familiar quickly with sources. As I have already said it is good for same reasons interfaces are good - easier to abstract away information you shouldn't be aware of when working in large teams.
 I don't think Walter realises how much of a plus point it is 
 for D to not have this 'feature'. I mean if this was 
 implemented and code started appearing written in this style 
 (as it will) why would people choose D over C++ to get stuff 
 done when they both offer the same headaches now?

I don't think it will matter at all. As it was mentioned, usage of such feature tends to be private business of certain project - it won't propagate to yours if you don't use it. And you really underestimate issues of C++ that force programmers to seek other languages. Separation of definition and declaration won't probably be even in top 50.
Sep 08 2013
prev sibling next sibling parent "QAston" <qaston gmail.com> writes:
On Sunday, 8 September 2013 at 12:46:49 UTC, Gary Willoughby 
wrote:
 I'm absolutely against this DIP.

 This proposal is just going back to the hell of header files 
 again. Why on earth would you emulate C/C++ when D was supposed 
 to be designed taking into account lessons learned from them. 
 This is unnecessary complexity added for the sake of a few 
 programmers who can't get out of C++ mode. I think you need to 
 have a good hard think about *why* header files were introduced 
 into those early languages and then consider if that reason is 
 still valid. Personally i don't think it is. Java and C# do 
 just fine without this.

 Seriously, this goes against everything you learn as a 
 programmer, nothing should ever be typed twice and then to say 
 that the declaration and implementation could be different just 
 boggles my mind?!?! Great more work!

 If implemented, i will never used this feature and i will never 
 deal with code that uses it either. I choose D *purely* because 
 it didn't have this header file nonsense. If i find in future i 
 start seeing more and more of this style of D code i would just 
 move on to use something else that doesn't have all this extra 
 baggage and work associated with it. Just because Manu brings 
 it up randomly you decide to create a DIP?

 In reality this is a documentation issue. Which has already 
 been addressed by DDOC or *.di files. If data exists in one 
 form, and it is needed in another, that's work a computer 
 should do. Not a human! IDE's also give you numerous tools to 
 get class overviews and such. If you are suggesting that you 
 also need these class overviews in code to be viewed on github 
 etc, just use comments. They are as arbitrary and simpler to 
 implement.

 Honestly this DIP is going backwards, i was under the 
 impression D was going forwards! I am so disappointed.

I totally agree (stating this just in case number of votes matters).
Sep 08 2013
prev sibling next sibling parent "Gary Willoughby" <dev nomad.so> writes:
 I have never worked on any reasonably large Java/C# code base. 
 But it C++ once amount of entities grows large enough clear 
 interface overview in header files is basically only way to get 
 familiar quickly with sources.

This is a job for the *documentation* and if documentation is automatically generated (which it is, see '-D') then this argument is moot.
 I don't think it will matter at all. As it was mentioned, usage 
 of such feature tends to be private business of certain project 
 - it won't propagate to yours  if you don't use it.

Except when dealing with books, tutorials, third party libraries, pull requests, etc... I dismay.
Sep 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 8 September 2013 at 15:09:31 UTC, Gary Willoughby 
wrote:
 This is a job for the *documentation* and if documentation is 
 automatically generated (which it is, see '-D') then this 
 argument is moot.

Documentation is tool to help with cross-project learning. I have never seen one used internally inside the same project. It simply does not work that way, not even close in convenience to matching source organization. Takes more time, uses different information representation other than plain code, is not applicable in some contexts (i.e. git log). Built-in IDE tools are generally better for that but, as I have already said, I am not aware of a single one that does it conveniently enough.
 Except when dealing with books, tutorials, third party 
 libraries, pull requests, etc...

That applies to any other possible feature that may or may not exist in D. What I do mean though is that you shouldn't care how third-party library is organized - for you it remains same import statement and documentation investigation that requires to change nothing in your code flow even if third-party library uses this feature and you do not.
Sep 08 2013
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-09-08, 12:46, Tove wrote:

 Wouldn't this style be an acceptable compromise instead? with both  
 declaration and definition 100% identical.

 struct S
 {
    // member function declarations
    static int mfunc1(int a, int b = 5) pure;
    static int mfunc2(int a, int b = 5) pure;
    static int mfunc3(int a, int b = 5) pure;

    // member function definitions
    static int mfunc1(int a, int b = 5) pure
    {
    }
    static int mfunc2(int a, int b = 5) pure
    {
    }
    static int mfunc3(int a, int b = 5) pure
    {
    }
 }

The problem here is the compiler does not enforce that all definitions are present in the declaration list. Apart from that, I feel this is the correct solution to the problem. -- Simen
Sep 08 2013
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-09-07, 19:00, Walter Bright wrote:

 Outlining of member functions is the practice of placing the declaration  
 of a member function in the struct/class/union, and placing the  
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

I like the idea, but I feel the DIP is missing some info: - What happens to UDAs? Do I need to declare them both places? - Why no nested classes/structs? - How do outlined ctors/dtors look? - How does it look in practice? Is this how it works: // foo.d: module foo; class Foo { int bar(); } //foo_impl.d: module foo; import foo; int Foo.bar() { return 3; } - Do the module names have to be the same? - Do I have to import the 'header' module in the implementation modules? - If the module names don't have to be the same: Can I implement the functions in any package? Sub-package? Only the same package? Also, I disagree with these points: - Parameter names should match. I can accept nameless parameters in the declaration, but otherwise they should match. Anything else is an invitation for things to go out of sync. - Default parameter values - either disallow them or enforce that they are the same in both places. - Implementation in a module different from the declaration. .di files provide all the good stuff here, without sending you on a wild goose chase through all your files for that one function your resident junior programmer hid away inside the implementation of a completely different class. Lastly, I want more examples - is this the same for structs and classes? Interfaces? Can I spread the function definitions over several modules? All in all, I would currently vote against. As an aside, I do like the idea of having a nice list of member functions that is statically compared to those actually implemented. This could however be done in different ways. My favorite would be something along these lines: class Foo { interface { float bar(int n) const; Foo clone(); static int qux(); // Compile-time error on this line: declared // function with no implementation. } float bar(int n) const { return 0.0; } Foo clone() { return this; } static int baz() { // Compile-time error on this line: undeclared // function with implementation. return 2; } } For the sake of fueling discussion, I have created a DIP with this suggestion: http://wiki.dlang.org/DIP48 -- Simen
Sep 08 2013
prev sibling next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

I am against this proposal. The rationale does not convince me we would be getting enough value out of solving this problem. 1. Converting C++ to D This is the strongest argument. Maybe the issue identified here is solved with partial classes (see C#). 2. Having an outline of the code DDOC already provides this! And any such limitations should be fixed. This point has several supporting points. a. An IDE is not always available to fold code I never do this, I hate code folding. b. People read their code just as much in github commits, merge/diff windows, emails/chat, etc. And? I could see some value having a summary for signature changes/additions when reviewing commits. For merges this proposal just adds one more line of conflict to deal with. Brining up emails would suggest that you want someone to write down their class signature; instead of having them go to that much work I'd rather ask them to generate the docs and email them to me. Chat, well I think that is a lost cause (I haven't had any code sent to me over chat that I had been glad to have received over chat) I believe requiring the programmer to keep function prototypes in sync is a mistake. I also don't think having this be optional is addressing the issue of those that are for it. When C/C++ programmers talk of the problems header files, they talk of the problems cause by textual replacements and compiled header files. When everyone who doesn't program in C/C++ talk of the problems of header files, they talk about the troubles of writing prototypes twice. By providing this feature as an optional statement, you'll be left with Manu and his team using it, an no one else touching it (Sorry Manu, you're the only one I've seen with a strong conviction for it, I know others will use it too). I realize that we want to make it as painless as possible for Remedy to switch from C++ to D (along with the rest of the game developers). I'm also really glad about the changes which have come from their use/insistence. However I think this is mostly a superficial change which will result in a divide in the community much like property.
Sep 08 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/8/13, Jesse Phillips <Jesse.K.Phillips+D gmail.com> wrote:
 I realize that we want to make it as painless as possible for
 Remedy to switch from C++ to D (along with the rest of the game
 developers).

FWIW I don't think this has anything to do with Remedy (afaik Manu doesn't work there anymore).
Sep 08 2013
prev sibling next sibling parent "w0rp" <devw0rp gmail.com> writes:
I'm opposed to this DIP. It's aimed solely at aiding readability,
but having two ways to do something usually detracts from
readability. I don't see the point.
Sep 08 2013
prev sibling next sibling parent Peter Williams <pwil3058 bigpond.net.au> writes:
On 08/09/13 22:46, Gary Willoughby wrote:
 On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright wrote:
 Outlining of member functions is the practice of placing the
 declaration of a member function in the struct/class/union, and
 placing the definition of it at global scope in the module or even in
 another module.

 http://wiki.dlang.org/DIP47

I'm absolutely against this DIP. This proposal is just going back to the hell of header files again. Why on earth would you emulate C/C++ when D was supposed to be designed taking into account lessons learned from them. This is unnecessary complexity added for the sake of a few programmers who can't get out of C++ mode. I think you need to have a good hard think about *why* header files were introduced into those early languages and then consider if that reason is still valid. Personally i don't think it is. Java and C# do just fine without this. Seriously, this goes against everything you learn as a programmer, nothing should ever be typed twice and then to say that the declaration and implementation could be different just boggles my mind?!?! Great more work! If implemented, i will never used this feature and i will never deal with code that uses it either. I choose D *purely* because it didn't have this header file nonsense. If i find in future i start seeing more and more of this style of D code i would just move on to use something else that doesn't have all this extra baggage and work associated with it. Just because Manu brings it up randomly you decide to create a DIP? In reality this is a documentation issue. Which has already been addressed by DDOC or *.di files. If data exists in one form, and it is needed in another, that's work a computer should do. Not a human! IDE's also give you numerous tools to get class overviews and such. If you are suggesting that you also need these class overviews in code to be viewed on github etc, just use comments. They are as arbitrary and simpler to implement. Honestly this DIP is going backwards, i was under the impression D was going forwards! I am so disappointed.

Well said. Peter
Sep 08 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Sep 08, 2013 at 02:53:10PM +0200, Dicebot wrote:
 On Sunday, 8 September 2013 at 12:46:49 UTC, Gary Willoughby wrote:

Seriously, this goes against everything you learn as a programmer,
nothing should ever be typed twice and then to say that the
declaration and implementation could be different just boggles my
mind?!?! Great more work!

It is no different from overriding `interface` methods in class. From the code structure point of view, declaration is interface. Implementation is implementation. Keeping those separate may sometimes/often be useful.

I agree that declaration is interface, and implementation is implementation, and that it's good to separate them. What I *don't* agree with is that the interface should be *manually* maintained. There is absolutely no reason, in this day and age, that something so trivial as extracting the interface *automatically* and *reliably* by the compiler, can't be done. Therefore, the *real* solution to this problem is to fix the compiler's .di output to give a proper overview of the class *automatically*, and nicely pretty-printed. Manu has already said that the whole motivation behind wanting this sort of interface/implementation separation was to be able to tell what a class does at a glance. Well guess what? If we clean up the current messy .di generation to produce something decent, then all you have to do is to run dmd -H, and you have your at-a-glance version of the class. No unnecessary complication of the language, no maintenance nightmare, no code duplication, very little implementation effort, and 100% reliable because the .di file is generated straight from the implementation, and therefore by definition is correct. *This* is the correct solution to Manu's issue, IMO. DIP47 is approaching it from a completely wrong angle. Please, let's not go back to the C++ way. We've abandoned that a long time ago, and for good reason. That bridge should've been burned already. T -- INTEL = Only half of "intelligence".
Sep 08 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Sunday, 8 September 2013 at 03:37:35 UTC, Walter Bright wrote:
 On the other hand, DRY, and I don't recall anyone ever 
 complaining about this in C++ outlined members.

Let me be the first, then, to formally lodge my complaint. As for the DIP itself, I had enough of this tedium in C++. I would strongly prefer that it not be introduced in D. Working with Java/C#/D/any language with a decent module system, I've realized what a pain this "feature" is.
Sep 08 2013
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
--089e0149ce4ce1987804e5eb3a8f
Content-Type: text/plain; charset=UTF-8

Missed the action...

Well it's clear this is not a popular proposal.
And even to me personally, it's certainly not of critical importance. If
there was a single thing I'd like to see *DONE* in D, it would be
temporary/r-value->ref args, without question (really, really annoying to
work around).

For the record, I tend to agree with the arguments of many in the 'against'
camp *from a purist point of view*, but the problem remains, and the reason
I raised it; this has demonstrated to me and my colleagues on a number of
occasions that it is a consistent productivity hindrance.
I guess a significant reason my experience seems to differ from many(/most)
on this forum, is that they're not in the business of banging out quick
throw-away commercial code.
The practical reality in my experience in the games industry is this:
 - Some (perhaps small) percentage of code is tech/foundation code. It is
carefully authored, but still typically documented only of the class
outline in the header file isn't already self-explanatory (I'm a big fan of
self-documenting code). It is to be re-used.
 - Much (perhaps most) code is rudimentary logic and glue code, or 'game
code' as we call it. This tends to be code that is written by more
inexperienced programmers and written to tight schedules. It is almost
never documented (apart from the occasional inline comments), rarely
conforms to some spec (unless it's implementing from foundational
interface), and usually exists to serve only the life of this one very
specific project, ie, throw-away. It is also almost always logic-intensive
code, riddled with switch/if/else constructs that take an awful lot of
vertical space, which further magnifies the problem of inline function
definitions breaking up the readability of the class outline.

Now further, from an absolutely practical point of view, the time that
someone unfamiliar with this code has to deal with it in the first place is
very likely at 11pm the night before the publisher is demanding a build so
they can show it to a bunch of arseholes in fancy suits who will decide if
they're going to pay us or not.
In C++ there is a very useful tool for unfamiliar programmers to get a good
brief overview of the code before they go hacking at it, that is the class
outline.
We've lost that. And I have demonstrably missed it.

People make claims like "write better code, split it up better, document
your code better, use the IDE folding", blah blah, but it's simply not the
practical reality. The budget and schedule does not typically allow for
careful consideration, design, and documentation of such throw away code
which glues the project together.
The code is what it is, and whether it's written in C++, or D, or lua, it's
probably not going to change the nature of this huge volume of crappy code.
Code folding doesn't work in foreign editors, communication tools, diff
windows; code reviews become more time consuming to approve, and I don't
know many programmers that like/use it regardless, even if it may help in
some occasions.
I think it's bat-shit-crazy to rely on a tool to simply make code readable
and easy to understand for a start. I also personally feel code folding
alienates me from the code I'm writing. As an author, you quickly gain a
feel for the layout of your source file; the flow and shape of the code
across the file is kinda picturesque. For me personally, code folding ruins
that relationship with my code, and I don't like it. It makes it harder for
me to sweep through my file and quickly locate the points of interest that
I'm working through. So if I'm not using it in my own code, but I'm
required to use it to understand someone else's code... there's a bit of a
conflict of interest there.

If I'm one of very few voices in favour of class outlines, I'm going to
suggest letting this argument sleep until other more serious issues are
resolved which people have been waiting on for ages.
I certainly want r-values -> ref args to work much more.

Keep in mind, I raised this debate as a practical account of last weekend,
among a bunch of other issues which were certainly more significant than
this one, but this seemed to capture the most attention.
It's not the first time it's come up and it'll be back again I'm sure :)

I support this DIP, obviously, but I'd suggest perhaps a conservative
restriction that definitions should only be allowed to appear within the
same module as the declaration. This would seem to simplify things like
mangling issues and access rights. In my own use case, I have no reason to
spread definitions across files. I just want to see class outlines clearly
summarised at the top of the file. This saves time, and time is money.


On 8 September 2013 03:00, Walter Bright <newshound2 digitalmars.com> wrote:

 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the definition
 of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

--089e0149ce4ce1987804e5eb3a8f Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">Missed the action...<div><br></div><div>Well it&#39;s clea= r this is not a popular proposal.</div><div>And even to me personally, it&#= 39;s certainly not of critical importance. If there was a single thing I&#3= 9;d like to see *DONE* in D, it would be temporary/r-value-&gt;ref args, wi= thout question (really, really annoying to work around).</div> <div><br></div><div>For the record, I tend to agree with the arguments of m= any in the &#39;against&#39; camp *from a purist point of view*, but the pr= oblem remains, and the reason I raised it; this has demonstrated to me and = my colleagues on a number of occasions that it is a consistent productivity= hindrance.</div> <div>I guess a significant reason my experience seems to differ from many(/= most) on this forum, is that they&#39;re not in the business of banging out= quick throw-away commercial code.<br></div><div>The practical reality in m= y experience in the games industry is this:</div> <div>=C2=A0- Some (perhaps small) percentage of code is tech/foundation cod= e. It is carefully authored, but still typically documented only of the cla= ss outline in the header file isn&#39;t already self-explanatory (I&#39;m a= big fan of self-documenting code). It is to be re-used.</div> <div>=C2=A0- Much (perhaps most) code is rudimentary logic and glue code, o= r &#39;game code&#39; as we call it. This tends to be code that is written = by more inexperienced programmers and written to tight schedules. It is alm= ost never documented (apart from the occasional inline comments), rarely co= nforms to some spec (unless it&#39;s implementing from foundational interfa= ce), and usually exists to serve only the life of this one very specific pr= oject, ie, throw-away. It is also almost always logic-intensive code, riddl= ed with switch/if/else constructs that take an awful lot of vertical space,= which further magnifies the problem of inline function definitions breakin= g up the readability of the class outline.</div> <div><br></div><div>Now further, from an absolutely practical point of view= , the time that someone unfamiliar with this code has to deal with it in th= e first place is very likely at 11pm the night before the publisher is dema= nding a build so they can show it to a bunch of arseholes in fancy suits wh= o will decide if they&#39;re going to pay us or not.<br> </div><div>In C++ there is a very useful tool for unfamiliar programmers to= get a good brief overview of the code before they go hacking at it, that i= s the class outline.</div><div>We&#39;ve lost that. And I have demonstrably= missed it.</div> <div><br></div><div><div>People make claims like &quot;write better code, s= plit it up better, document your code better, use the IDE folding&quot;, bl= ah blah, but it&#39;s simply not the practical reality. The budget and sche= dule does not typically allow for careful consideration, design, and docume= ntation of such throw away code which glues the project together.</div> <div>The code is what it is, and whether it&#39;s written in C++, or D, or = lua, it&#39;s probably not going to change the nature of this huge volume o= f crappy code.</div><div>Code folding doesn&#39;t work in foreign editors, = communication tools, diff windows; code reviews become more time consuming = to approve, and I don&#39;t know many programmers that like/use it regardle= ss, even if it may help in some occasions.</div> <div>I think it&#39;s bat-shit-crazy to rely on a tool to simply make code = readable and easy to understand for a start. I also personally feel code fo= lding alienates me from the code I&#39;m writing. As an author, you quickly= gain a feel for the layout of your source file; the flow and shape of the = code across the file is kinda picturesque. For me personally, code folding = ruins that relationship with my code, and I don&#39;t like it. It makes it = harder for me to sweep through my file and quickly locate the points of int= erest that I&#39;m working through. So if I&#39;m not using it in my own co= de, but I&#39;m required to use it to understand someone else&#39;s code...= there&#39;s a bit of a conflict of interest there.</div> </div><div><br></div><div>If I&#39;m one of very few voices in favour of cl= ass outlines, I&#39;m going to suggest letting this argument sleep until ot= her more serious issues are resolved which people have been waiting on for = ages.</div> <div>I certainly want r-values -&gt; ref args to work much more.</div><div>= <br></div><div>Keep in mind, I raised this debate as a practical account of= last weekend, among a bunch of other issues which were certainly more sign= ificant than this one, but this seemed to capture the most attention.</div> <div>It&#39;s not the first time it&#39;s come up and it&#39;ll be back aga= in I&#39;m sure :)<br></div><div><br></div><div>I support this DIP, obvious= ly, but I&#39;d suggest perhaps a conservative restriction that definitions= should only be allowed to appear within the same module as the declaration= . This would seem to simplify things like mangling issues and access rights= . In my own use case, I have no reason to spread definitions across files. = I just want to see class outlines clearly summarised at the top of the file= . This saves time, and time is money.</div> </div><div class=3D"gmail_extra"><br><br><div class=3D"gmail_quote">On 8 Se= ptember 2013 03:00, Walter Bright <span dir=3D"ltr">&lt;<a href=3D"mailto:n= ewshound2 digitalmars.com" target=3D"_blank">newshound2 digitalmars.com</a>= &gt;</span> wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex">Outlining of member functions is the practic= e of placing the declaration of a member function in the struct/class/union= , and placing the definition of it at global scope in the module or even in= another module.<br> <br> <a href=3D"http://wiki.dlang.org/DIP47" target=3D"_blank">http://wiki.dlang= .org/DIP47</a><br> </blockquote></div><br></div> --089e0149ce4ce1987804e5eb3a8f--
Sep 08 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-09-09 05:46, Manu wrote:
 Missed the action...

 Well it's clear this is not a popular proposal.
 And even to me personally, it's certainly not of critical importance. If
 there was a single thing I'd like to see *DONE* in D, it would be
 temporary/r-value->ref args, without question (really, really annoying
 to work around).

So what's wrong with this approach, that's already working today: class Foo { void foo (); void foo () { } } void main () { auto foo = new Foo; foo.foo(); } BTW, this feature was implemented because you asked for it. -- /Jacob Carlborg
Sep 09 2013
next sibling parent reply "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Jacob Carlborg" <doob me.com> wrote in message 
news:l0jrm7$3199$1 digitalmars.com...
 On 2013-09-09 05:46, Manu wrote:
 Missed the action...

 Well it's clear this is not a popular proposal.
 And even to me personally, it's certainly not of critical importance. If
 there was a single thing I'd like to see *DONE* in D, it would be
 temporary/r-value->ref args, without question (really, really annoying
 to work around).

So what's wrong with this approach, that's already working today: class Foo { void foo (); void foo () { } } void main () { auto foo = new Foo; foo.foo(); } BTW, this feature was implemented because you asked for it. -- /Jacob Carlborg

Whoa, I didn't think of applying that to member functions. This seems like the answer. Put your variables and function prototypes at the top of your class. Done.
Sep 09 2013
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, September 09, 2013 15:51:11 Joseph Rushton Wakeling wrote:
 On 09/09/13 15:12, Daniel Murphy wrote:
 "Jacob Carlborg" <doob me.com> wrote in message
 news:l0jrm7$3199$1 digitalmars.com...
 
 So what's wrong with this approach, that's already working today:
 
 class Foo
 {
 
 void foo ();
 
 void foo ()
 {
 
 }
 
 }
 
 void main ()
 {
 
 auto foo = new Foo;
 foo.foo();
 
 }
 
 BTW, this feature was implemented because you asked for it.
 
 --
 /Jacob Carlborg

Whoa, I didn't think of applying that to member functions. This seems like the answer. Put your variables and function prototypes at the top of your class. Done.

Problem -- what about: class Foo { // Declarations void foo(); int bar(double n); // Definitions void foo() { .... } int bar(double n) { ....} // Whoops! Forgot to include this one in the // declarations list, but it's still accepted // as part of the class void goo() { ... } } A well-defined rule for separating out declarations and definitions would check for that and throw a compile error.

Walter's proposal would be no different on that count. All that the DIP is proposing is a way to define a member function outside of a class. That requires that it already be declared in the class, but it doesn't make it so that you can't define other functions directly in the class. - Jonathan M Davis
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 21:30, Jonathan M Davis wrote:
 Walter's proposal would be no different on that count. All that the DIP is
 proposing is a way to define a member function outside of a class. That
 requires that it already be declared in the class, but it doesn't make it so
 that you can't define other functions directly in the class.

Sure. The thing is that if you can only declare and define within the class, this potential problem is unavoidable -- you can _never_ be certain that your list of declarations is complete. If on the other hand you can define outside the class declaration, then you can make it a design decision to only declare within the class declaration, and to define elsewhere in the module. In that case it should be possible to guarantee a safety check that what's declared is defined and what's defined is declared -- and that the two match precisely.
Sep 09 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-09-09 23:45, Ettienne Gilbert wrote:

 Ahh, ok. I see where you are coming from - you were evaluating the
 implications of what Jacob Carlborg proposed if "mixed" in with Walter's
 DIP47, right? My points though was specifically on the implications of
 Jacob Carlborg's proposal "in isolation" i.e. as an acceptable
 alternative to DIP47. And, AFAICS, Jacob posed the question to Manu this
 way as well (I think - but maybe Jacob can confirm/deny).

Yes, my suggestion would be an alternative to DIP47. -- /Jacob Carlborg
Sep 10 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-09-09 22:01, Andrej Mitrovic wrote:

 You could use compile-time introspection where the API would look like:

 class C
 {
      void foo();
      void foo() { }
      void bar() { }  // missing declaration
      mixin VerifyDeclarations;
 }

 And this would statically assert if there's a missing declaration for
 a definition. I think this might even be doable with the current
 introspection features, although I'm not sure whether we have a way to
 determine if something is a declaration or a definition. Certainly
 such a trait could easily be added to the compiler.

A mixin should not be necessary. RTInfo can be used for that: https://github.com/D-Programming-Language/druntime/blob/master/src/object.di#L575 The compiler will instantiate RTInfo once for each user defined type. The only downside is that you need to modify druntime. -- /Jacob Carlborg
Sep 10 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-09-10 10:49, Joseph Rushton Wakeling wrote:

 Can you explain a bit more about how that works?

The "object" module, part of druntime defines a template with the name "RTInfo". That template will be instantiated with each user defined type. Currently RTInfo doesn't do anything: template RTInfo(T) { enum RTInfo = cast(void*)0x12345678; } https://github.com/D-Programming-Language/druntime/blob/master/src/object.di#L575 If you replace that template with something like: template RTInfo(T) { enum RTInfo = verifyDeclarations!(T); } verifyDeclarations would look something like this, in pseudo code: void* verifyDeclarations (T) () { static if (is(T == class)) { foreach (member ; methods!(T)) { static if (!hasDefinition!(member)) static assert (false, "The member '" fullyQualifiedName!(T) ~ "." ~ member.stringof ~ "' doesn't have a definition"); } } return null; }
 As long as it can provide a guarantee that everything declared has a
 definition, and everything defined has a declaration -- and that they
 match! -- then I think this is probably the solution required.

 What I mean is -- it needs to ensure that the issue identified in a
 couple of my earlier posts will be flagged and prevented:
 http://forum.dlang.org/post/mailman.1104.1378795749.1719.digitalmars-d puremagic.com


 However, I'm suspicious of anything that would require the programmer to
 be "virtuous" and manually ensure that those checks take place, rather
 than the checks simply being a natural part of the compilation process.

The idea is then you build a tool that "compiles" all your files which uses druntime with the above implementation of RTInfo. -- /Jacob Carlborg
Sep 10 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-09-10 08:49, Joseph Rushton Wakeling wrote:
 (My one caveat is that I think solutions based on
 programmer virtue, like remembering to insert a line: "mixin
 VerifyDeclarations;" into a class, are generally less nice than
 solutions where the compiler does your checking for you without you
 having to ask.)

That shouldn't be necessary, see my reply to Andrej: http://forum.dlang.org/thread/l0fm2o$2uat$1 digitalmars.com?page=14#post-l0mjh4:2418bp:241:40digitalmars.com -- /Jacob Carlborg
Sep 10 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-09-09 14:36, Manu wrote:

 Which is what I requested it for, and use it very extensively.

Doesn't this already solve what this DIP47 is trying to solve? -- /Jacob Carlborg
Sep 09 2013
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/9/13 12:35 PM, H. S. Teoh wrote:
 Auto-generation of .di files solves this problem. (Provided we fix the
 mess that is the current implementation of .di generation, of course.)

OK, so what's the trouble with .di generation today? Andrei
Sep 09 2013
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/9/13 4:43 PM, H. S. Teoh wrote:
 On Mon, Sep 09, 2013 at 02:20:34PM -0700, Andrei Alexandrescu wrote:
 On 9/9/13 12:35 PM, H. S. Teoh wrote:
 Auto-generation of .di files solves this problem. (Provided we fix the
 mess that is the current implementation of .di generation, of course.)

OK, so what's the trouble with .di generation today?

1) It could be pretty-printed (it currently tries to, but it's not very pretty).

Please paste all of the above into a bug report! Andrei
Sep 09 2013
prev sibling parent Bruno Medeiros <brunodomedeiros+dng gmail.com> writes:
On 09/09/2013 04:46, Manu wrote:
 Missed the action...

 Well it's clear this is not a popular proposal.
 And even to me personally, it's certainly not of critical importance. If
 there was a single thing I'd like to see *DONE* in D, it would be
 temporary/r-value->ref args, without question (really, really annoying
 to work around).

 For the record, I tend to agree with the arguments of many in the
 'against' camp *from a purist point of view*, but the problem remains,
 and the reason I raised it; this has demonstrated to me and my
 colleagues on a number of occasions that it is a consistent productivity
 hindrance.
 I guess a significant reason my experience seems to differ from
 many(/most) on this forum, is that they're not in the business of
 banging out quick throw-away commercial code.
 The practical reality in my experience in the games industry is this:
   - Some (perhaps small) percentage of code is tech/foundation code. It
 is carefully authored, but still typically documented only of the class
 outline in the header file isn't already self-explanatory (I'm a big fan
 of self-documenting code). It is to be re-used.
   - Much (perhaps most) code is rudimentary logic and glue code, or
 'game code' as we call it. This tends to be code that is written by more
 inexperienced programmers and written to tight schedules. It is almost
 never documented (apart from the occasional inline comments), rarely
 conforms to some spec (unless it's implementing from foundational
 interface), and usually exists to serve only the life of this one very
 specific project, ie, throw-away. It is also almost always
 logic-intensive code, riddled with switch/if/else constructs that take
 an awful lot of vertical space, which further magnifies the problem of
 inline function definitions breaking up the readability of the class
 outline.

 Now further, from an absolutely practical point of view, the time that
 someone unfamiliar with this code has to deal with it in the first place
 is very likely at 11pm the night before the publisher is demanding a
 build so they can show it to a bunch of arseholes in fancy suits who
 will decide if they're going to pay us or not.
 In C++ there is a very useful tool for unfamiliar programmers to get a
 good brief overview of the code before they go hacking at it, that is
 the class outline.
 We've lost that. And I have demonstrably missed it.

 People make claims like "write better code, split it up better, document
 your code better, use the IDE folding", blah blah, but it's simply not
 the practical reality. The budget and schedule does not typically allow
 for careful consideration, design, and documentation of such throw away
 code which glues the project together.
 The code is what it is, and whether it's written in C++, or D, or lua,
 it's probably not going to change the nature of this huge volume of
 crappy code.
 Code folding doesn't work in foreign editors, communication tools, diff
 windows; code reviews become more time consuming to approve, and I don't
 know many programmers that like/use it regardless, even if it may help
 in some occasions.
 I think it's bat-shit-crazy to rely on a tool to simply make code
 readable and easy to understand for a start. I also personally feel code
 folding alienates me from the code I'm writing. As an author, you
 quickly gain a feel for the layout of your source file; the flow and
 shape of the code across the file is kinda picturesque. For me
 personally, code folding ruins that relationship with my code, and I
 don't like it. It makes it harder for me to sweep through my file and
 quickly locate the points of interest that I'm working through. So if
 I'm not using it in my own code, but I'm required to use it to
 understand someone else's code... there's a bit of a conflict of
 interest there.

 If I'm one of very few voices in favour of class outlines, I'm going to
 suggest letting this argument sleep until other more serious issues are
 resolved which people have been waiting on for ages.
 I certainly want r-values -> ref args to work much more.

 Keep in mind, I raised this debate as a practical account of last
 weekend, among a bunch of other issues which were certainly more
 significant than this one, but this seemed to capture the most attention.
 It's not the first time it's come up and it'll be back again I'm sure :)

 I support this DIP, obviously, but I'd suggest perhaps a conservative
 restriction that definitions should only be allowed to appear within the
 same module as the declaration. This would seem to simplify things like
 mangling issues and access rights. In my own use case, I have no reason
 to spread definitions across files. I just want to see class outlines
 clearly summarised at the top of the file. This saves time, and time is
 money.


 On 8 September 2013 03:00, Walter Bright <newshound2 digitalmars.com
 <mailto:newshound2 digitalmars.com>> wrote:

     Outlining of member functions is the practice of placing the
     declaration of a member function in the struct/class/union, and
     placing the definition of it at global scope in the module or even
     in another module.

     http://wiki.dlang.org/DIP47

Ok, basically you are trying to add some language complexity just to help with the use case where you can't, or is not convenient, to use an IDE. (communication tools, diff viewers, etc.) I don't agree with this DIP then. Let' see: A) does this use case merit these languages changes? B) is this proposal short-sighted in what it improves? Regarding point B, I think that is the case. Reviewing code outside of an IDE is always going to be a limiting experience. (you don't see compilation errors/warnings, you can't do open definition, you can't see documentation hovers, etc.) And some of these limits you cannot work-around by making changes to the language and the code of your project. Consider this example, imagine you want to see the outline of a class (signatures of the members), like you sugest, but including the members of superclasses *as well* (this is a feature supported by some IDEs, and fairly useful for large hierarchical classes). How would you address this with a language feature? You can't, unless you want your DIP to allow the source class outline to include the superclass member signatures as well, but that would just be an insane amount of bloat and code duplication. :S BTW, some IDEs (JDT for example) support semantic functionality (code complete, etc) in their diff viewers, at least if one of the sides you are comparing with is your workspace code. -- Bruno Medeiros - Software Engineer
Sep 16 2013
prev sibling next sibling parent Peter Williams <pwil3058 bigpond.net.au> writes:
On 08/09/13 16:47, Walter Bright wrote:
 On 9/7/2013 11:08 PM, Peter Williams wrote:
 In summary, you've gotten rid of the need for this type of duplication
 so why
 would you introduce it?

I believe that is covered in the "Rationale" section of the dip.

Couldn't see a rational answer to my question in the rationale. Looked more like a "I want to do this and I think that we should change the language syntax to allow it" statement to me. It doesn't really add functionality just makes what's there more complex. Peter
Sep 08 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--089e01537e42a78c2904e5eb6daa
Content-Type: text/plain; charset=UTF-8

On 9 September 2013 05:46, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:

 On 9/8/13, Jesse Phillips <Jesse.K.Phillips+D gmail.com> wrote:
 I realize that we want to make it as painless as possible for
 Remedy to switch from C++ to D (along with the rest of the game
 developers).

FWIW I don't think this has anything to do with Remedy (afaik Manu doesn't work there anymore).

Indeed. These opinions are my own, and I raised it on the merit of our experience last weekend in a 48hour game-dev-jam with a few former colleagues (including one who still works at Remedy). This discussion has come up at remedy in the past, but I don't think this is of particular significance to the remedy workflow; the modules were small enough to not cause issues, at least not as I left it. I believe the scenarios I describe are going to be very typical though, at least in the game-dev context, particularly when larger volumes of D code emerge. I've demonstrated this across 2 separate 48 hour game-jam's now, which simulate the environment of a commercial crunch period quite faithfully. --089e01537e42a78c2904e5eb6daa Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 9 September 2013 05:46, Andrej Mitrovic <span dir=3D"lt= r">&lt;<a href=3D"mailto:andrej.mitrovich gmail.com" target=3D"_blank">andr= ej.mitrovich gmail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra">= <div class=3D"gmail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"><div class=3D"im">On 9/8/13, Jesse Phillips &lt;<a href=3D= "mailto:Jesse.K.Phillips%2BD gmail.com">Jesse.K.Phillips+D gmail.com</a>&gt= ; wrote:<br> &gt; I realize that we want to make it as painless as possible for<br> &gt; Remedy to switch from C++ to D (along with the rest of the game<br> &gt; developers).<br> <br> </div>FWIW I don&#39;t think this has anything to do with Remedy (afaik Man= u<br> doesn&#39;t work there anymore).<br> </blockquote></div><br></div><div class=3D"gmail_extra">Indeed. These opini= ons are my own, and I raised it on the merit of our experience last weekend= in a 48hour game-dev-jam with a few former colleagues (including one who s= till works at Remedy).</div> <div class=3D"gmail_extra">This discussion has come up at remedy in the pas= t, but I don&#39;t think this is of particular significance to the remedy w= orkflow; the modules were small enough to not cause issues, at least not as= I left it.</div> <div class=3D"gmail_extra"><br></div><div class=3D"gmail_extra">I believe t= he scenarios I describe are going to be very typical though, at least in th= e game-dev context, particularly when larger volumes of D code emerge. I&#3= 9;ve demonstrated this across 2 separate 48 hour game-jam&#39;s now, which = simulate the environment of a=C2=A0commercial=C2=A0crunch period quite fait= hfully.</div> </div> --089e01537e42a78c2904e5eb6daa--
Sep 08 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 9 September 2013 at 03:46:23 UTC, Manu wrote:
 For the record, I tend to agree with the arguments of many in 
 the 'against'
 camp *from a purist point of view*, but the problem remains, 
 and the reason
 I raised it; this has demonstrated to me and my colleagues on a 
 number of
 occasions that it is a consistent productivity hindrance.

I think that you guys being experienced C++ devs makes it worse. As a matter of fact, changing an habit is difficult. I suspect your experience here was in fact a source f increased difficulty. Let me take an actual example. When you put a total newbie in front of a linux or OSX, they usually manage pretty well (considering they are newbies). Now take the average windows user and put it in front of a linux or an OSX, and you'll notice that they have tremendous difficulties to use them. Because everything they know, every expectation they have, get into their way. Anyway, this outline, first, the need of better IDE support (but that isn't big news, I guess we all know that by now). Second some need of interface/implementation separation. For that second, it has been discussed in the thread to improve the di behavior to fit that role. Do think this is a viable approach, and that your team of happy devs would have benefited from that ?
Sep 08 2013
prev sibling next sibling parent "FrogLegs" <poopoo yahoo.com> writes:
  This seems like a waste of time compared to the other complaints 
Manu brought up(bad IDE/debugger support etc.)
Sep 08 2013
prev sibling next sibling parent "Ramon" <spam thanks.no> writes:
Manu has pointed to some issue behind the obvious issue that will 
come up again and again unless it's settled once and for all.

Let's call it "To please everyone somewhat (and never really 
enough) - vs - to stick to a clear and well founded concept".

My personal view is that we should make D a mixed pickles with 
lots of "but C++ has that" and then some more gadgets thrown in 
for good measure.

The point that triggered me was "quick and dirty throw away 
code". Frankly, I don't care batshit about that. Don't get me 
wrong, Manus desire is doubtlessly valid and I wish him the best 
of luck to achieve maximum happyness. But I also see that comfort 
for "throw away code" has a strong tendency to run counter 
reliability.

There's a gazillion C++ compilers, pretty printers, analysers and 
other tools out there. And C++ has proven to be useful as a throw 
away code language - just look at mountains of throw away code 
out there (they won't call it that, of course).
And there is C#, $Basic, Perl (a perfect language to create 
trobletickets - or to not even care to), etc, etc.

The issue is not to please crowd A or crowd B. The issue is to 
make up ones mind and to establish a clear definition of what D 
is meant to be - and than to bloody stick to it.

D had "reliability" and "safety" written in quite big letters in 
it's PR. It's a *major* reason for (sure enough not only) me to 
be here. Comfort and some luxury is important, too, when you make 
your living using a tool, sure. But that's no contradiction. One 
can have both.

If I wanted to play a mixture of hide and seek and lottery I'd 
use C++ in the first place (and would have tools thrown at me).

In case I missed it, could someone kindly point me to a more or 
less binding priorities list of what D is meant to be and in what 
order of priorities. Maybe it's my fault and I just didn't see 
that list. But in case #1 on the list was "to please everyone and 
then glue some more gadgets to it" I wouldn't be here.

Thanks -R
Sep 08 2013
prev sibling next sibling parent "Ramon" <spam thanks.no> writes:
Correction (3rd paragraph)

My personal view is that we should *not* make D a mixed pickles 
with
lots of "but C++ has that" and then some more gadgets thrown in
for good measure.

Sorry -R
Sep 08 2013
prev sibling next sibling parent "PauloPinto" <pjmlp progtools.org> writes:
On Monday, 9 September 2013 at 04:00:39 UTC, Manu wrote:
 On 9 September 2013 05:46, Andrej Mitrovic 
 <andrej.mitrovich gmail.com>wrote:

 On 9/8/13, Jesse Phillips <Jesse.K.Phillips+D gmail.com> wrote:
 I realize that we want to make it as painless as possible for
 Remedy to switch from C++ to D (along with the rest of the 
 game
 developers).

FWIW I don't think this has anything to do with Remedy (afaik Manu doesn't work there anymore).

Indeed. These opinions are my own, and I raised it on the merit of our experience last weekend in a 48hour game-dev-jam with a few former colleagues (including one who still works at Remedy). This discussion has come up at remedy in the past, but I don't think this is of particular significance to the remedy workflow; the modules were small enough to not cause issues, at least not as I left it. I believe the scenarios I describe are going to be very typical though, at least in the game-dev context, particularly when larger volumes of D code emerge. I've demonstrated this across 2 separate 48 hour game-jam's now, which simulate the environment of a commercial crunch period quite faithfully.

Game developers embracing Erlang, C#, Java and ActionScript don't seem to have issues with that, as far as I can tell.
Sep 08 2013
prev sibling next sibling parent "Paolo Invernizzi" <paolo.invernizzi gmail.com> writes:
On Monday, 9 September 2013 at 04:00:39 UTC, Manu wrote:
 Indeed. These opinions are my own, and I raised it on the merit 
 of our
 experience last weekend in a 48hour game-dev-jam with a few 
 former
 colleagues (including one who still works at Remedy).
 This discussion has come up at remedy in the past, but I don't 
 think this
 is of particular significance to the remedy workflow; the 
 modules were
 small enough to not cause issues, at least not as I left it.

 I believe the scenarios I describe are going to be very typical 
 though, at
 least in the game-dev context, particularly when larger volumes 
 of D code
 emerge. I've demonstrated this across 2 separate 48 hour 
 game-jam's now,
 which simulate the environment of a commercial crunch period 
 quite
 faithfully.

I don't believe that typical. We are working with some very big modules, and we have _no_ problems at all regarding that aspect. I think that this is a swift for the discussion: discussing about an issue that it is present _today_ in a commercial user of the product, or a discussion about an a _potential_ problem. The worst part of all this mess it is that the proposal ditches one of the *strong* selling point of D: no code duplication, use documentation if you want an overview. I also strongly disagree that this way of coding is not typical: here at work we are using it without problems with D, and, again, DDocs are the right way. I would also add that also here we have a lot of time pressures for the releases... as in every commercial software company I know of... ;-P - Paolo Invernizzi
Sep 08 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-09-07 19:00, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

What's wrong with the code below, that works today: class Foo { void foo (); void foo () { writeln("Foo.foo"); } } void main () { auto foo = new Foo; foo.foo(); } -- /Jacob Carlborg
Sep 09 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 9 September 2013 at 07:00:23 UTC, Jacob Carlborg wrote:
 On 2013-09-09 05:46, Manu wrote:
 Missed the action...

 Well it's clear this is not a popular proposal.
 And even to me personally, it's certainly not of critical 
 importance. If
 there was a single thing I'd like to see *DONE* in D, it would 
 be
 temporary/r-value->ref args, without question (really, really 
 annoying
 to work around).

So what's wrong with this approach, that's already working today: class Foo { void foo (); void foo () { } } void main () { auto foo = new Foo; foo.foo(); } BTW, this feature was implemented because you asked for it.

This is super useful to generate boilerplate from compile time reflection !
Sep 09 2013
prev sibling next sibling parent "sclytrack" <sclytrack fake.com> writes:
On Saturday, 7 September 2013 at 17:00:08 UTC, Walter Bright 
wrote:
 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

--------------------------------------- unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls; type { TForm1 } TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { private declarations } public { public declarations } procedure ChangeTitle(x:string); procedure ChangeOtherTitle(x: string); end; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject); begin ChangeTitle('test'); end; procedure TForm1.ChangeTitle(x: string); begin Memo1.Lines.Add(x); end; procedure TForm1.ChangeOtherTitle(x: string); begin Memo1.Lines.Add(x); end; end. Here is how it looks like in Lazarus. In the class definition you type the declaration. public { public declarations } procedure ChangeTitle(x:string); Then you press "control shift c" this will create the empty implementation. Use "control shift up" to cycle between the interface section and the implementation section. There are two keywords "interface" and "implementation" to separate the two sections. Honestly. There is not much typing going on. If you go want to go the the next procedure in the implementation section it is faster to go "control shift up" back to the interface section. And then go to the next method and go back "control shift up" to the implentation section than to press the arrow down button until you are at the next method. Lazarus does not accept changes in the name of the parameter.
Sep 09 2013
prev sibling next sibling parent "Volcz" <volcz kth.se> writes:
On Sunday, 8 September 2013 at 04:47:04 UTC, Jonathan M Davis 
wrote:
 On Saturday, September 07, 2013 10:00:05 Walter Bright wrote:
 Outlining of member functions is the practice of placing the 
 declaration of
 a member function in the struct/class/union, and placing the 
 definition of
 it at global scope in the module or even in another module.
 
 http://wiki.dlang.org/DIP47

I confess that I really don't like this idea. I think that the separation of declarations and definitions is a serious downside of C++ and that it negatively impacts code maintenence. And from the recent discussion on this, it's clear that quite a few people agree with me. However, at the same time, there are some folks (like Manu) who really prefer to separate the declaration and definitions so that they can just see the signatures for an entire class' functions at once without seeing any definitions. Personally, I don't think that that's a big deal and that it's far better to just use generated documentation for that, but clearly there's not a consensus on that. </ snip> - Jonathan M Davis

I completely agree with Jonathan! This will only produce more code which will lead to more bugs and more maintenance.
Sep 09 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 9 September 2013 at 00:43:39 UTC, H. S. Teoh wrote:
 Therefore, the *real* solution to this problem is to fix the 
 compiler's
 .di output to give a proper overview of the class 
 *automatically*, and
 nicely pretty-printed.

Yes, that should be superior approach in general though exact usability is very detail-specific - currently relation between .di and .d and not really well-defined and pulling this off will requires its own DIP at the very least. For example, it is not entirely clear to me, what should happen if there are both .di and .d files in the file system at the same time and they have minor difference (remember, it is perfectly legal to tweak .di manually). It is likely, that improving .di tool chain will require similar signature matching verification anyway. Also I am wondering how to differ purely auto-generated .di files (should be updated completely upon build) and ones with manual changes (should be only verified). It is all about small details.
Sep 09 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--001a11c3367677293804e5f2a4f2
Content-Type: text/plain; charset=UTF-8

On 9 September 2013 18:08, deadalnix <deadalnix gmail.com> wrote:

 On Monday, 9 September 2013 at 07:00:23 UTC, Jacob Carlborg wrote:

 On 2013-09-09 05:46, Manu wrote:

 Missed the action...

 Well it's clear this is not a popular proposal.
 And even to me personally, it's certainly not of critical importance. If
 there was a single thing I'd like to see *DONE* in D, it would be
 temporary/r-value->ref args, without question (really, really annoying
 to work around).

So what's wrong with this approach, that's already working today: class Foo { void foo (); void foo () { } } void main () { auto foo = new Foo; foo.foo(); } BTW, this feature was implemented because you asked for it.

This is super useful to generate boilerplate from compile time reflection !

Which is what I requested it for, and use it very extensively. --001a11c3367677293804e5f2a4f2 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 9 September 2013 18:08, deadalnix <span dir=3D"ltr">&lt= ;<a href=3D"mailto:deadalnix gmail.com" target=3D"_blank">deadalnix gmail.c= om</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_= quote"><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-= left:1px #ccc solid;padding-left:1ex"> <div class=3D"HOEnZb"><div class=3D"h5">On Monday, 9 September 2013 at 07:0= 0:23 UTC, Jacob Carlborg wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> On 2013-09-09 05:46, Manu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> Missed the action...<br> <br> Well it&#39;s clear this is not a popular proposal.<br> And even to me personally, it&#39;s certainly not of critical importance. I= f<br> there was a single thing I&#39;d like to see *DONE* in D, it would be<br> temporary/r-value-&gt;ref args, without question (really, really annoying<b= r> to work around).<br> </blockquote> <br> So what&#39;s wrong with this approach, that&#39;s already working today:<b= r> <br> class Foo<br> {<br> =C2=A0 =C2=A0 void foo ();<br> <br> =C2=A0 =C2=A0 void foo ()<br> =C2=A0 =C2=A0 {<br> <br> =C2=A0 =C2=A0 }<br> }<br> <br> void main ()<br> {<br> =C2=A0 =C2=A0 auto foo =3D new Foo;<br> =C2=A0 =C2=A0 foo.foo();<br> }<br> <br> BTW, this feature was implemented because you asked for it.<br> </blockquote> <br></div></div> This is super useful to generate boilerplate from compile time reflection != <br> </blockquote></div><br></div><div class=3D"gmail_extra">Which is what I req= uested it for, and use it very extensively.</div></div> --001a11c3367677293804e5f2a4f2--
Sep 09 2013
prev sibling next sibling parent "Joseph Rushton Wakeling" <joseph.wakeling webdrake.net> writes:
On Monday, 9 September 2013 at 04:18:29 UTC, deadalnix wrote:
 For that second, it has been discussed in the thread to improve 
 the di behavior to fit that role. Do think this is a viable 
 approach, and that your team of happy devs would have benefited 
 from that ?

Correct me if I'm wrong, but isn't the problem of using manually-written .di files to separate out class declaration and definition, that you consequently also have to manually include all the declarations of all the other module content?
Sep 09 2013
prev sibling next sibling parent "PauloPinto" <pjmlp progtools.org> writes:
On Monday, 9 September 2013 at 12:28:54 UTC, Dicebot wrote:
 On Monday, 9 September 2013 at 00:43:39 UTC, H. S. Teoh wrote:
 Therefore, the *real* solution to this problem is to fix the 
 compiler's
 .di output to give a proper overview of the class 
 *automatically*, and
 nicely pretty-printed.

Yes, that should be superior approach in general though exact usability is very detail-specific - currently relation between .di and .d and not really well-defined and pulling this off will requires its own DIP at the very least. For example, it is not entirely clear to me, what should happen if there are both .di and .d files in the file system at the same time and they have minor difference (remember, it is perfectly legal to tweak .di manually). It is likely, that improving .di tool chain will require similar signature matching verification anyway. Also I am wondering how to differ purely auto-generated .di files (should be updated completely upon build) and ones with manual changes (should be only verified). It is all about small details.

In languages like Modula-2, it is a compile error if there are differences. So I would say D compilers should follow the same behavior, unless it is requested to generate .di files automatically, which will then overwrite the corresponding .di files.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 15:12, Daniel Murphy wrote:
 "Jacob Carlborg" <doob me.com> wrote in message
 news:l0jrm7$3199$1 digitalmars.com...
 So what's wrong with this approach, that's already working today:

 class Foo
 {
      void foo ();

      void foo ()
      {

      }
 }

 void main ()
 {
      auto foo = new Foo;
      foo.foo();
 }

 BTW, this feature was implemented because you asked for it.

 --
 /Jacob Carlborg

Whoa, I didn't think of applying that to member functions. This seems like the answer. Put your variables and function prototypes at the top of your class. Done.

Problem -- what about: class Foo { // Declarations void foo(); int bar(double n); // Definitions void foo() { .... } int bar(double n) { ....} // Whoops! Forgot to include this one in the // declarations list, but it's still accepted // as part of the class void goo() { ... } } A well-defined rule for separating out declarations and definitions would check for that and throw a compile error.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 05:46, Manu wrote:
 For the record, I tend to agree with the arguments of many in the 'against'
camp
 *from a purist point of view*, but the problem remains, and the reason I raised
 it; this has demonstrated to me and my colleagues on a number of occasions that
 it is a consistent productivity hindrance.

For what it's worth, I think this kind of baptism-by-fire practical experience is very valuable, and that it's worth considering carefully even if the final decision is not to implement the requested feature. Question: do you have any access to information about similar short-deadline programming activity using other languages (Java, C# ...) that also forbid the separation of declaration and definition, and how devs using those languages cope with that? It might offer an alternative solution that no one here has thought of.
 I support this DIP, obviously, but I'd suggest perhaps a conservative
 restriction that definitions should only be allowed to appear within the same
 module as the declaration. This would seem to simplify things like mangling
 issues and access rights. In my own use case, I have no reason to spread
 definitions across files. I just want to see class outlines clearly summarised
 at the top of the file. This saves time, and time is money.

I think the conservative approach is probably correct -- the class outline and the function definitions should have to be in the same module, and the outline and definitions should match precisely. Any mismatch (including in variable names)? Compile error. A function in the outline that isn't implemented? Compile error. A function implemented that isn't in the outline? Compile error. That should greatly reduce the possibility of error caused by code duplication. Then it simply becomes a question of deciding if the manual labour of writing separate outlines and definitions is worth it. I guess this is probably somewhere where a tool really _can_ be useful, to ensure that the definitions and the outline stay in sync. Writing D code in this way should probably be disapproved of in the D style guidelines, but with the proviso that it's there for the circumstances where it really is useful.
Sep 09 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 9 September 2013 at 14:22:15 UTC, Joseph Rushton 
Wakeling wrote:
 Then it simply becomes a question of deciding if the manual 
 labour of writing separate outlines and definitions is worth 
 it.  I guess this is probably somewhere where a tool really 
 _can_ be useful, to ensure that the definitions and the outline 
 stay in sync.

 Writing D code in this way should probably be disapproved of in 
 the D style guidelines, but with the proviso that it's there 
 for the circumstances where it really is useful.

Very well spoken, this is exactly how I see it.
Sep 09 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 09, 2013 at 03:26:23PM +0200, PauloPinto wrote:
 On Monday, 9 September 2013 at 12:28:54 UTC, Dicebot wrote:
On Monday, 9 September 2013 at 00:43:39 UTC, H. S. Teoh wrote:
Therefore, the *real* solution to this problem is to fix the
compiler's .di output to give a proper overview of the class
*automatically*, and nicely pretty-printed.

Yes, that should be superior approach in general though exact usability is very detail-specific - currently relation between .di and .d and not really well-defined and pulling this off will requires its own DIP at the very least. For example, it is not entirely clear to me, what should happen if there are both .di and .d files in the file system at the same time and they have minor difference (remember, it is perfectly legal to tweak .di manually).


I'd propose to make it such that you *don't* have to tweak the .di manually. Maybe the use of UDAs could help get rid of the need to edit .di by hand, by instructing the compiler what kind of output is desired. Anything that requires hand-tweaking is unreliable and prone to errors and careless bugs. The best way is to have .di completely automated.
 It is likely, that improving .di
tool chain will require similar signature matching verification
anyway. Also I am wondering how to differ purely auto-generated .di
files (should be updated completely upon build) and ones with
manual changes (should be only verified).

It is all about small details.

In languages like Modula-2, it is a compile error if there are differences. So I would say D compilers should follow the same behavior, unless it is requested to generate .di files automatically, which will then overwrite the corresponding .di files.

I think it is a bug for the .di and .d to have mismatches. For example, I don't see how the following code could be correct: ---module.di--- int func(int x) pure; ---module.d--- int global; int func(int x) { return global; } Any such mismatch should be considered a bug. In fact, the current lax enforcement of matching makes it possible for something to be declared pure safe nothrow in .di, but impure system throwing in .d. I think there has been a few bugs like this in druntime that got fixed. T -- Microsoft is to operating systems & security ... what McDonalds is to gourmet cooking.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 16:34, Jacob Carlborg wrote:
 Doesn't this already solve what this DIP47 is trying to solve?

See the objection given in my reply to Daniel Murphy.
Sep 09 2013
prev sibling next sibling parent "Ettienne Gilbert" <ettienne.gilbert gmail.com> writes:
On Monday, 9 September 2013 at 13:51:20 UTC, Joseph Rushton 
Wakeling wrote:
 On 09/09/13 15:12, Daniel Murphy wrote:

 /

Whoa, I didn't think of applying that to member functions. This seems like the answer. Put your variables and function prototypes at the top of your class. Done.

Problem -- what about: class Foo { // Declarations void foo(); int bar(double n); // Definitions void foo() { .... } int bar(double n) { ....} // Whoops! Forgot to include this one in the // declarations list, but it's still accepted // as part of the class void goo() { ... } } A well-defined rule for separating out declarations and definitions would check for that and throw a compile error.

I would argue that it is actually better this way (that not all functions need to be in the declarations list) - its way more flexible! This way you can leave out function declarations that you are not really interested to see from a "functional overview perspective" of the class. AFAIC the cost of implementing this would be way too high for any potential benefit gained from this. And, since Walter already stated that this would "no way be mandatory", the implications are that the compiler would need to enforce it once any one function is declared in the declarations list, but... not enforce it if no functions are declared in the list! Also, leaving it flexible as it is now cannot silently break anything. Worse that can happen is that you may inadvertently try to implement goo() twice (since you may think the missing declaration imply there is no definition), but then the compiler will anyway complain about the duplicate definition. So I agree with Jacob Carlborg - I would also like to know why the above is not already sufficient...?
Sep 09 2013
prev sibling next sibling parent "jostly" <johan.f.ostling gmail.com> writes:
On Monday, 9 September 2013 at 14:22:15 UTC, Joseph Rushton 
Wakeling wrote:
 Question: do you have any access to information about similar 
 short-deadline programming activity using other languages 
 (Java, C# ...) that also forbid the separation of declaration 
 and definition, and how devs using those languages cope with 
 that?  It might offer an alternative solution that no one here 
 has thought of.

As a long-time Java developer, my answer would be that it's dealt with via careful code crafting. Keep classes small, follow the principle of single responsibility etc. There are tons of good advice for writing maintainable, easy-to-understand code. And there's certainly nothing stopping us from doing the same in D. However, if I understood Manu correctly, the issue here is those instances where there is not a lot of time, as in 48-hour game jams and game industry crunch mode. The cases where it is felt that code quality takes second place to getting things out fast. In those cases, I think Java people would feel the same problem. It can be alleviated, in Java, by making sure you write interfaces for all public-facing code. The same could be done in D, but I am unsure if that would involve a performance hit that might actually matter in games programming. So at that point, the Java programmer would rely on the IDE to make sense of the bigfiles they are producing. Now, I think an argument could be made that the initial productivity loss from performing refactorings to make sure you are producing maintainable code will pay off in a short while, even in crunchmode, but I realise this is something the games industry in general would have to deal with, and it should not be a burden put upon the individuals wishing to adopt D for making games. As for the DIP, I would not want to code using that style myself, but I wouldn't mind it if the requirement was to keep all parts of the same class in the same module. Once we start crossing file boundaries, finding out where stuff is is going to be terrible unless you have a good IDE support for things like "Go to definition".
Sep 09 2013
prev sibling next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Sunday, 8 September 2013 at 19:47:06 UTC, Andrej Mitrovic 
wrote:
 On 9/8/13, Jesse Phillips <Jesse.K.Phillips+D gmail.com> wrote:
 I realize that we want to make it as painless as possible for
 Remedy to switch from C++ to D (along with the rest of the game
 developers).

FWIW I don't think this has anything to do with Remedy (afaik Manu doesn't work there anymore).

I did not realize he had left, but I did realize he was speaking for himself. I'm mostly just using Remedy as the symbol of large C++ code bases/programmers which want to use D because they actually are. I could see Manu's position being common for this user type, I don't think it is common for most D or other language programmers.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 18:41, Ettienne Gilbert wrote:
 I would argue that it is actually better this way (that not all functions need
 to be in the declarations list) - its way more flexible! This way you can leave
 out function declarations that you are not really interested to see from a
 "functional overview perspective" of the class.

AFAICS the request is for separation of declaration and definition, so you'd be able to do things like this: class Foo { void foo(); int bar(double x); void goo(int n); // ... etc. } ... and then later in the same file: void Foo.foo() { /* ... function body ... */ } int Foo.bar(double x) { /* ... ditto ... */ } void Foo.goo(int n) { /* ... and so on ... */ } Now, you'd be at liberty to mix declarations and definitions in the _class_ (or struct) declaration, e.g.: class Foo { void foo(); // we define this somewhere else int bar(double x) { /* ... but we define this here */ } // ... etc. } But supposing that a function is declared but not defined inside the class declaration, it should be obligatory that it _is_ defined somewhere else in the file -- and conversely, if a class function is defined somewhere else in the file, it should be obligatory that it's declared in the class declaration. And on top of that, it should be obligatory that the declaration and definition match perfectly. (Note that for any function defined in the class declaration, this is automatically and unavoidably true:-)
 AFAIC the cost of implementing this would be way too high for any potential
 benefit gained from this. And, since Walter already stated that this would "no
 way be mandatory", the implications are that the compiler would need to enforce
 it once any one function is declared in the declarations list, but... not
 enforce it if no functions are declared in the list!

I am personally inclined to leave it to Walter to decide whether the cost of this is too much. At the very least having this possibility seems to be in line with earlier plans.
 Also, leaving it flexible as it is now cannot silently break anything. Worse
 that can happen is that you may inadvertently try to implement goo() twice
 (since you may think the missing declaration imply there is no definition), but
 then the compiler will anyway complain about the duplicate definition.

 So I agree with Jacob Carlborg - I would also like to know why the above is not
 already sufficient...?

Because it allows a situation where you can have an incomplete list of member function declarations for a class or struct, and yet not know that it's incomplete without manual checking -- which I think fails to satisfy the needs Manu has identified. We can reasonably debate whether those needs are worth addressing at all, and whether addressing them comes at too high a cost, but we should be clear on what solutions address them properly and what don't.
Sep 09 2013
prev sibling next sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Monday, 9 September 2013 at 03:46:23 UTC, Manu wrote:
 People make claims like "write better code, split it up better, 
 document
 your code better, use the IDE folding", blah blah, but it's 
 simply not the
 practical reality. The budget and schedule does not typically 
 allow for
 careful consideration, design, and documentation of such throw 
 away code
 which glues the project together.

I think DDOC should be improved to handle this scenario. Being able to generate docs with undocumented members would be great for internal development of the module. I realize that doesn't address all your problems, but I think that is the correct direction.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 20:05, Jesse Phillips wrote:
 I think DDOC should be improved to handle this scenario. Being able to generate
 docs with undocumented members would be great for internal development of the
 module. I realize that doesn't address all your problems, but I think that is
 the correct direction.

Better DDoc is always going to be nice, but come on -- that doesn't address the issue of looking at code in a diff or a copy-paste via chat software, and in the scenarios Manu has described, no one's going to have time to write documentation comments. OK, you could have a DDoc setting to at least _list_ all elements of class interfaces etc., even if there's no doc comment, but that doesn't address the other factors.
Sep 09 2013
prev sibling next sibling parent "Gary Willoughby" <dev nomad.so> writes:
On Monday, 9 September 2013 at 18:23:21 UTC, Joseph Rushton 
Wakeling wrote:
 Better DDoc is always going to be nice, but come on -- that 
 doesn't address the issue of looking at code in a diff or a 
 copy-paste via chat software, and in the scenarios Manu has 
 described, no one's going to have time to write documentation 
 comments.

This is such a poor argument for changing and further complicating the language. There are so many ways to get a class overview *even* in plain text. I can't honestly believe this is the catalyst for this DIP.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 20:30, Gary Willoughby wrote:
 This is such a poor argument for changing and further complicating the
language.
 There are so many ways to get a class overview *even* in plain text. I can't
 honestly believe this is the catalyst for this DIP.

I can understand anyone feeling that the costs aren't worth it, but I don't think it's ever good to dismiss battle experience of skilled developers, especially when it comes from scenarios that you or I may not have personal experience of. I don't mind finding out I'm wrong (actually, I'd quite like to be in this case:-), but I'd like to understand how I could get the class overview in the plain-text scenarios described in my previous email.
Sep 09 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 09, 2013 at 08:23:07PM +0200, Joseph Rushton Wakeling wrote:
 On 09/09/13 20:05, Jesse Phillips wrote:
I think DDOC should be improved to handle this scenario. Being able
to generate docs with undocumented members would be great for
internal development of the module. I realize that doesn't address
all your problems, but I think that is the correct direction.

Better DDoc is always going to be nice, but come on -- that doesn't address the issue of looking at code in a diff or a copy-paste via chat software, and in the scenarios Manu has described, no one's going to have time to write documentation comments. OK, you could have a DDoc setting to at least _list_ all elements of class interfaces etc., even if there's no doc comment, but that doesn't address the other factors.

Auto-generation of .di files solves this problem. (Provided we fix the mess that is the current implementation of .di generation, of course.) T -- It said to install Windows 2000 or better, so I installed Linux instead.
Sep 09 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/9/13, Joseph Rushton Wakeling <joseph.wakeling webdrake.net> wrote:
 A well-defined rule for separating out declarations and definitions would
 check
 for that and throw a compile error.

You could use compile-time introspection where the API would look like: class C { void foo(); void foo() { } void bar() { } // missing declaration mixin VerifyDeclarations; } And this would statically assert if there's a missing declaration for a definition. I think this might even be doable with the current introspection features, although I'm not sure whether we have a way to determine if something is a declaration or a definition. Certainly such a trait could easily be added to the compiler.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 22:01, Andrej Mitrovic wrote:
 You could use compile-time introspection where the API would look like:

 class C
 {
      void foo();
      void foo() { }
      void bar() { }  // missing declaration
      mixin VerifyDeclarations;
 }

 And this would statically assert if there's a missing declaration for
 a definition. I think this might even be doable with the current
 introspection features, although I'm not sure whether we have a way to
 determine if something is a declaration or a definition. Certainly
 such a trait could easily be added to the compiler.

Fair enough. In that case I guess my objections don't really hold water.
Sep 09 2013
prev sibling next sibling parent "Brian Schott" <briancschott gmail.com> writes:
On Monday, 9 September 2013 at 21:20:34 UTC, Andrei Alexandrescu 
wrote:
 On 9/9/13 12:35 PM, H. S. Teoh wrote:
 Auto-generation of .di files solves this problem. (Provided we 
 fix the
 mess that is the current implementation of .di generation, of 
 course.)

OK, so what's the trouble with .di generation today? Andrei

Related to this: Is semantic information necessary for .di generation, or can it be built from the AST?
Sep 09 2013
prev sibling next sibling parent "Ettienne Gilbert" <ettienne.gilbert gmail.com> writes:
On Monday, 9 September 2013 at 17:34:23 UTC, Joseph Rushton 
Wakeling wrote:
 On 09/09/13 18:41, Ettienne Gilbert wrote:
 I would argue that it is actually better this way (that not 
 all functions need
 to be in the declarations list) - its way more flexible! This 
 way you can leave
 out function declarations that you are not really interested 
 to see from a
 "functional overview perspective" of the class.

AFAICS the request is for separation of declaration and definition, so you'd be able to do things like this: class Foo { void foo(); int bar(double x); void goo(int n); // ... etc. } ... and then later in the same file: void Foo.foo() { /* ... function body ... */ } int Foo.bar(double x) { /* ... ditto ... */ } void Foo.goo(int n) { /* ... and so on ... */ } Now, you'd be at liberty to mix declarations and definitions in the _class_ (or struct) declaration, e.g.: class Foo { void foo(); // we define this somewhere else int bar(double x) { /* ... but we define this here */ } // ... etc. } But supposing that a function is declared but not defined inside the class declaration, it should be obligatory that it _is_ defined somewhere else in the file -- and conversely, if a class function is defined somewhere else in the file, it should be obligatory that it's declared in the class declaration. And on top of that, it should be obligatory that the declaration and definition match perfectly. (Note that for any function defined in the class declaration, this is automatically and unavoidably true:-)

Ahh, ok. I see where you are coming from - you were evaluating the implications of what Jacob Carlborg proposed if "mixed" in with Walter's DIP47, right? My points though was specifically on the implications of Jacob Carlborg's proposal "in isolation" i.e. as an acceptable alternative to DIP47. And, AFAICS, Jacob posed the question to Manu this way as well (I think - but maybe Jacob can confirm/deny). If you mix the 2 I agree with you for the most part. But the real question for me (and I suspect Jacob) is this: Is this...
     class Foo
     {
         void foo();
         int bar(double x);
         void goo(int n);
         // ... etc.
     }

     void Foo.foo()
     {
         /* ... function body ... */
     }

     int Foo.bar(double x)
     {
         /* ... ditto ... */
     }

     void Foo.goo(int n)
     {
         /* ... and so on ... */
     }

...really so much better than this?
     class Foo
     {
         void foo();
         int bar(double x);
         void goo(int n);
         // ... etc.
         void foo()
         {
              /* ... function body ... */
         }

         int bar(double x)
         {
              /* ... ditto ... */
         }

         void goo(int n)
         {
              /* ... and so on ... */
         }
     }

Granted, this sacrifices some flexibility from DIP47. But these are of such dubious quality/use/potential pitfalls (as discussed in this thread), that I hardly think DIP47 is worth implementing as a result. Especially since, what we currently have (as shown by Carl,) already gives you arguably 90%+ (IMHO) of Manu's request for (I quote) "You don't need to see the function bodies in the class definition, you want to quickly see what a class has and does". Does it really matter that the function definitions are also present inside the class definition, as long as you can also see "what a class has and does" in the declarations list at the top? Of course fixing the current issues with .di generation is important as a separate issue.
Sep 09 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 09, 2013 at 02:20:34PM -0700, Andrei Alexandrescu wrote:
 On 9/9/13 12:35 PM, H. S. Teoh wrote:
Auto-generation of .di files solves this problem. (Provided we fix the
mess that is the current implementation of .di generation, of course.)

OK, so what's the trouble with .di generation today?

1) It could be pretty-printed (it currently tries to, but it's not very pretty). 2) Eponymous templates look ugly. I.e., this: template MyClass(T) { class MyClass { ... } } instead of: class MyClass(T) { ... } 3) It loses manual formatting, like turning this: writeln("This is a very very long string "~ "broken across multiple lines"); into: writeln("This is a very very long string "~ "broken across multiple lines"); which detracts from readability when the expression is very long. This also applies to signature contraints, which are just concatenated onto an already-over-long function signature. A related issue concerns reordering of function qualifiers, e.g., if your code looks like this: void func(int a) pure safe nothrow { ... } it gets turned into: pure safe nothrow void func(int a) { ... } which is a bit jarring since when reviewing the .di file you may be expecting what you wrote, not what the compiler thinks you should have written. 4) It includes template function bodies inline, which means it fails to serve as a class-at-a-glance format in that case. It could use the declare-first, implement-later approach some have suggested, i.e.: class MyTemplateClass(T) { void member(); ... void member() { /* implementation here */ } } instead of the current: class MyTemplateClass(T) { void member() { /* implementation here */ } ... } 5) Private templates are included along with public ones: to achieve Manu's goal of interface-at-a-glance, private members and private templates should be put at the end of the file, rather than in the midst of the public symbols. Though this is a minor issue; you could just reorder code in the source manually. There may be a few other points I missed. But all in all, it's not *quite* ready to serve as an interface-at-a-glance format yet. I didn't find any inherent limitations, though (except possibly for templated private members, but those can be largely alleviated by suitable reordering), so once these issues are addressed, we should be good to go. T -- In theory, there is no difference between theory and practice.
Sep 09 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Sep 09, 2013 at 05:39:06PM -0700, Andrei Alexandrescu wrote:
 On 9/9/13 4:43 PM, H. S. Teoh wrote:
On Mon, Sep 09, 2013 at 02:20:34PM -0700, Andrei Alexandrescu wrote:
On 9/9/13 12:35 PM, H. S. Teoh wrote:
Auto-generation of .di files solves this problem. (Provided we fix
the mess that is the current implementation of .di generation, of
course.)

OK, so what's the trouble with .di generation today?

1) It could be pretty-printed (it currently tries to, but it's not very pretty).

Please paste all of the above into a bug report!

http://d.puremagic.com/issues/show_bug.cgi?id=11003 T -- "I suspect the best way to deal with procrastination is to put off the procrastination itself until later. I've been meaning to try this, but haven't gotten around to it yet. " -- swr
Sep 09 2013
prev sibling next sibling parent reply Martin Nowak <code dawg.eu> writes:
On 09/07/2013 07:00 PM, Walter Bright wrote:
 Outlining of member functions is the practice of placing the declaration
 of a member function in the struct/class/union, and placing the
 definition of it at global scope in the module or even in another module.

 http://wiki.dlang.org/DIP47

I'm really happy to see this discussed. The DIP misses to mention one of the most important rationale IMO, hiding of implementation details.
 http://wiki.dlang.org/DIP47#Semantics
 7. Outlined member function return types, parameter types, and 

declared. I think this is problematic because it gives up the nice everything-within-this-file property of private. Doesn't package access mitigate the need for private access? What about module scope functions?
Sep 09 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/9/2013 9:24 PM, Martin Nowak wrote:
  > 7. Outlined member function return types, parameter types, and function
 bodies have private access to the module where the aggregate is declared.

 I think this is problematic because it gives up the nice
 everything-within-this-file property of private.
 Doesn't package access mitigate the need for private access?

The trouble with eschewing private access for member functions is then arguably the member functions do not belong in the class at all - they should be UFCS functions.
Sep 09 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/10/2013 06:59 AM, Walter Bright wrote:
 The trouble with eschewing private access for member functions is then
 arguably the member functions do not belong in the class at all - they
 should be UFCS functions.

Functions are placed inside classes for convenient scoping and vtables.
Sep 10 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 23:45, Ettienne Gilbert wrote:
 Ahh, ok. I see where you are coming from - you were evaluating the implications
 of what Jacob Carlborg proposed if "mixed" in with Walter's DIP47, right?

The code that Jacob proposed is currently legit D code and that isn't going to change -- and if that solution works for you (or other people), great. However, I don't think it completely address the requirements the DIP is attempting to meet. In my previous email I was simply trying to show that implementing new functionality to allow class functions to be defined outside the class declaration, wouldn't be incompatible with writing code like Jacob's (although I don't see why anyone would mix the approaches in this way). In terms of where I'm coming from, it's more in line with Dicebot -- I think both of us have been focused on the simultaneous usefulness and necessity of being able to check declaration against definition for class member functions that are declared and defined separately.
 If you mix the 2 I agree with you for the most part. But the real question for
 me (and I suspect Jacob) is this:

 Is this...

  [ ... snip code ...]

...really so much better than this?
  [ ... snip again ...]

Granted, this sacrifices some flexibility from DIP47. But these are of such dubious quality/use/potential pitfalls (as discussed in this thread), that I hardly think DIP47 is worth implementing as a result. Especially since, what we currently have (as shown by Carl,) already gives you arguably 90%+ (IMHO) of Manu's request for (I quote) "You don't need to see the function bodies in the class definition, you want to quickly see what a class has and does". Does it really matter that the function definitions are also present inside the class definition, as long as you can also see "what a class has and does" in the declarations list at the top?

The point is about being able to check that your declaration list has a one-to-one match with your definition list. If you just decide to place declarations at the top of the class definition, and definitions lower down, you run the risk of accidentally missing one of the defined functions out of the declaration list: class Foo { // Declarations void foo(); void bar(); // Definitions void foo() { ... } void bar() { ... } void goo() { ... } // Whoops! This is part of the class API but // we forgot to include it in our declaration // list ... } But Andrej Mitrovic has suggested a means to implement those kind of introspective checks at compile-time, so maybe it's not as urgent as I first thought. (My one caveat is that I think solutions based on programmer virtue, like remembering to insert a line: "mixin VerifyDeclarations;" into a class, are generally less nice than solutions where the compiler does your checking for you without you having to ask.)
 Of course fixing the current issues with .di generation is important as a
 separate issue.

Yes, absolutely.
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 21:35, H. S. Teoh wrote:
 Auto-generation of .di files solves this problem. (Provided we fix the
 mess that is the current implementation of .di generation, of course.)

Maybe you'll think I'm being too picky, but I don't think that generated files of any kind (whether .di or Ddoc) really help with the situations Manu was describing. If you want to be able to look at the latest diff and see at a glance how the class API has changed, a generated file doesn't help (unless you store that generated file in the VCS, but I've always understood that to be bad practice).
Sep 09 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 10/09/13 09:59, Jacob Carlborg wrote:
 A mixin should not be necessary. RTInfo can be used for that:

 https://github.com/D-Programming-Language/druntime/blob/master/src/object.di#L575

 The compiler will instantiate RTInfo once for each user defined type. The only
 downside is that you need to modify druntime.

Can you explain a bit more about how that works? As long as it can provide a guarantee that everything declared has a definition, and everything defined has a declaration -- and that they match! -- then I think this is probably the solution required. What I mean is -- it needs to ensure that the issue identified in a couple of my earlier posts will be flagged and prevented: http://forum.dlang.org/post/mailman.1104.1378795749.1719.digitalmars-d puremagic.com However, I'm suspicious of anything that would require the programmer to be "virtuous" and manually ensure that those checks take place, rather than the checks simply being a natural part of the compilation process.
Sep 10 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
Main issue of .di files that make them useless for anything but 
providing declarations for blobs is that there is absolutely zero 
compiler control of .d and .di relation. Fixing this either 
implies providing good control of how .di is generated via 
compiler flags (and prohibiting manual modifications) or 
implementing good part of DIP47 restricted to .di/.d combo (all 
the signature verifications).

Also it does not seem defined in spec how lookup should happen if 
both .d and .di are present, and, for example, .di has only 
declaration. Will compiler check .d for possible inlining if it 
is present?

I think that .di should always contain only declarations and be 
_always_ auto-generated by compiler with strict 1-to-1 matching 
signatures. Then .d are also queried if implementation is 
needed/considered - but those are not mandatory (aside from 
templates). Blob bindings distributed may then simply have a 
stripped down version of .d file (similar to what is now 
generated by dmd -H).

Key point here is  that .di needs _always_ to be there, with hard 
guarantees that it is in sync with actual code. Add even one more 
extra step of getting those and it becomes considerably less 
convenient than C++-like overview.
Sep 10 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 10/09/13 14:12, Jacob Carlborg wrote:
 verifyDeclarations would look something like this, in pseudo code:

 void* verifyDeclarations (T) ()
 {
      static if (is(T == class))
      {
          foreach (member ; methods!(T))
          {
              static if (!hasDefinition!(member))
                  static assert (false, "The member '" fullyQualifiedName!(T) ~
 "." ~ member.stringof ~ "' doesn't have a definition");
          }
      }

      return null;
 }

But the problem that I identified wasn't the possibility of members that are declared but not defined. It was the possibility of members that are defined but not included in the top-of-the-class list of separate declarations. The whole point is that both the author and the recipient of the code should be able to verify at compile-time that the list of declarations is an accurate summary of the class. I imagine you could define a verifySeparateDeclarations that would indeed enforce that (for every declaration a definition, and for every definition a separate declaration) but that would have its own issues.
Sep 10 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/10/13, Jacob Carlborg <doob me.com> wrote:
 A mixin should not be necessary. RTInfo can be used for that:

 https://github.com/D-Programming-Language/druntime/blob/master/src/object.di#L575

The mixin was demonstrated for convenience so you don't have to manually type in the class name (or use typeof(this)).
Sep 10 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/10/13, Dicebot <public dicebot.lv> wrote:
 Main issue of .di files that make them useless for anything but
 providing declarations for blobs is that there is absolutely zero
 compiler control of .d and .di relation.

Yeah, I think we could attempt to provide an alternative to DIP47 by adding a compiler flag that verifies .d implementations match .di declarations. We don't even have to make the .d files explicitly import the .di files like Andrei proposed.
Sep 10 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 10 September 2013 at 13:32:14 UTC, Andrej Mitrovic 
wrote:
 On 9/10/13, Dicebot <public dicebot.lv> wrote:
 Main issue of .di files that make them useless for anything but
 providing declarations for blobs is that there is absolutely 
 zero
 compiler control of .d and .di relation.

Yeah, I think we could attempt to provide an alternative to DIP47 by adding a compiler flag that verifies .d implementations match .di declarations. We don't even have to make the .d files explicitly import the .di files like Andrei proposed.

Please, no compiler flags. It should be default behavior. We are speaking about fundamental binary-level application sanity here.
Sep 10 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Walter Bright:

 Outlining of member functions is the practice of placing the 
 declaration of a member function in the struct/class/union, and 
 placing the definition of it at global scope in the module or 
 even in another module.

 http://wiki.dlang.org/DIP47

I was away and very busy, I have read only part of the answers in this thread. I don't like this DIP. If this DIP passes I am probably not going to use this feature in my code. Go and Python show that it's good to minimize the number of trivially different ways to write code in a language. This DIP does the opposite.
 or even in another module.

This is not a good idea.
 "If you rely on tools to make the code _readable_,

In my opinion this DIP makes the code less readable, and makes the code less DRY.
 3. Parameter names need not match.

This seems bad. What's the rationale for this? (One perhaps acceptable solution is to put no parameter names in the signature inside the class). Generally I suggest to fix the biggest module system bugs before modifying the design of related features, like the ones discussed in DIP47. ----------------- Daniel Murphy:
 Let's solve a documentation issue with documentation 
 improvements.

This seems one better solution to the problem. But I also suggest people here to read and discuss about the post written by Andrei that touches deeper issues. The module system is currently significantly buggy, and it needs a principled design before trying to add DIP47. ----------------- Manu:
 People make claims like "write better code, split it up better,
 document your code better,

The D compiler could be modified a bit to generate a bare bones documentation even with not even a comment written in the code. Bye, bearophile
Sep 10 2013
prev sibling next sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Tuesday, 10 September 2013 at 13:49:21 UTC, bearophile wrote:
 Walter Bright:

 3. Parameter names need not match.

This seems bad. What's the rationale for this? (One perhaps acceptable solution is to put no parameter names in the signature inside the class).

in a declaration, but to me this doesn't make much sense. If people want separate declaration/definition so that they can get an idea of what a class does, then for non-trivial functions if the variable names are omitted then your more or less have to look at the definition anyway. I must admit whenever I come across such declarations in code I am reading I always find them kind of irritating. Apart from functions with say variadic parameter lists, is this really all that useful? clip
 The D compiler could be modified a bit to generate a bare bones 
 documentation even with not even a comment written in the code.

 Bye,
 bearophile

I agree on this last point.
Sep 10 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Craig Dillabaugh:

 Apart from functions with say variadic parameter lists, is this
 really all that useful?

There are rare situations when you need to add a certain argument to the function signature, but you don't need to use that argument inside the method/function. This happens for example because of code evolution. In such cases not giving a name to the argument is good, you avoid introducing a useless and unused variable name, making the code simpler, safer, and more clear. Bye, bearophile
Sep 10 2013
prev sibling next sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Tuesday, 10 September 2013 at 14:15:19 UTC, bearophile wrote:
 Craig Dillabaugh:

 Apart from functions with say variadic parameter lists, is this
 really all that useful?

There are rare situations when you need to add a certain argument to the function signature, but you don't need to use that argument inside the method/function. This happens for example because of code evolution. In such cases not giving a name to the argument is good, you avoid introducing a useless and unused variable name, making the code simpler, safer, and more clear. Bye, bearophile

I think using calling the variable 'dummy' would likely do the trick in those instances, but this makes sense.
Sep 10 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Tuesday, 10 September 2013 at 14:15:19 UTC, bearophile wrote:
 Craig Dillabaugh:

 Apart from functions with say variadic parameter lists, is this
 really all that useful?

There are rare situations when you need to add a certain argument to the function signature, but you don't need to use that argument inside the method/function. This happens for example because of code evolution. In such cases not giving a name to the argument is good, you avoid introducing a useless and unused variable name, making the code simpler, safer, and more clear. Bye, bearophile

It is never the case in the declaration though. You always want parameter names there, to reference them in DDOC comment at the very least.
Sep 10 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 09/09/13 16:29, Dicebot wrote:
 On Monday, 9 September 2013 at 14:22:15 UTC, Joseph Rushton Wakeling wrote:
 Then it simply becomes a question of deciding if the manual labour of writing
 separate outlines and definitions is worth it.  I guess this is probably
 somewhere where a tool really _can_ be useful, to ensure that the definitions
 and the outline stay in sync.

 Writing D code in this way should probably be disapproved of in the D style
 guidelines, but with the proviso that it's there for the circumstances where
 it really is useful.

Very well spoken, this is exactly how I see it.

Thank you! :-)
Sep 10 2013
prev sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Monday, 9 September 2013 at 18:23:21 UTC, Joseph Rushton 
Wakeling wrote:
 On 09/09/13 20:05, Jesse Phillips wrote:
 I think DDOC should be improved to handle this scenario. Being 
 able to generate
 docs with undocumented members would be great for internal 
 development of the
 module. I realize that doesn't address all your problems, but 
 I think that is
 the correct direction.

Better DDoc is always going to be nice, but come on -- that doesn't address the issue of looking at code in a diff or a copy-paste via chat software, and in the scenarios Manu has described, no one's going to have time to write documentation comments. OK, you could have a DDoc setting to at least _list_ all elements of class interfaces etc., even if there's no doc comment, but that doesn't address the other factors.

I hope you realize you've restated what I said? Include undocumented members, won't address all problems. There can definitely be value for diff; if you're objective is to find modifications to public API. I don't want to have a class pasted in a chat window, with or without function definitions (Unavoidable I know). If I need to do anything complicated with that information, into a text editor it goes (and on linux this would be in /tmp and easy to compile docs for; Windows, I just hope I'm not there).
Sep 10 2013