September 09, 2013
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
September 09, 2013
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.
September 09, 2013
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.

September 09, 2013
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
September 09, 2013
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
September 09, 2013
On Monday, 9 September 2013 at 13:51:20 UTC, Joseph Rushton Wakeling wrote:
> On 09/09/13 15:12, Daniel Murphy wrote:
[snip]
>>> /
>>
>> 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...?
September 09, 2013
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".
September 09, 2013
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.
September 09, 2013
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.
September 09, 2013
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.