December 30, 2016
Stefan Koch <uplink.coder@googlemail.com> wrote:
> On Friday, 30 December 2016 at 22:29:18 UTC, Chris Wright wrote:
>> * Performance improvements, primarily when a module imports
>> another,
>> bulky module for optional functionality.
> That is solved by selective imports.
> 
>> * Making it easier to locate where things are defined when reading code.
> 
> That is solved by selective imports.
> 
>> * Making it easier to move declarations between files.
> 
> That is solved by selective imports.
> 
> Inline imports are really just a addition retrive the the deprecated behavior of fullyQualifedNames which would implicitly import.
> 

The main win, which indeed is not emphasized enough, is better encapsulation. Walter pointed that out, and I will redo the DIP to put that front and center.

December 30, 2016
On Friday, 30 December 2016 at 23:49:23 UTC, Andrei Alexandrescu wrote:

> The main win, which indeed is not emphasized enough, is better encapsulation. Walter pointed that out, and I will redo the DIP to put that front and center.

Maybe i can provide an example where i think DCD's would be usefull.
Im experimenting with a more Qt like signals and slots implementation,
it introspects some type for function declarations with the @("Signal") uda
and mixes them into the current type.
It currently looks like this:

// moda.d
interface TestSignals
{
   import modb: TestType;
   @("Signal"):
      void someTestSig(TestType);
}

// modb.d
struct TestType{}

// test.d
class A : SignalObject
{
   import moda: TestSignals;
   import modb: TestType; // has to be manually imported for the generated signal

   mixin signalsOf!(SignalList, TestSignals);

   interface SignalList
   {
      @("Signal"):
         void foo(int);
         void bar(string, int = 100);
         int bar(int a, int b);
   }

   void someFun(string s) { s.writeln; }
}

class B : SignalObject
{
   struct SignalList
   {
      @("Signal"):
         void someSig(string);
   }

   mixin signalsOf!SignalList;

   void fooHandler(int i){ i.writeln; }

   int onBar(int a, int b){ writeln(a + b); return a + b; }
   void onBar(string s, int i){ writeln(s, i); }

   import modb: TestType;
   void someTestSigHandler(TestType t){ t.writeln; }
}

class C : SignalObject
{
   import modb: TestType; // has to be manually imported for the generated signal

   mixin signalsOf!(A, B);

   // i wanted to support string based signal declaration
   // but that would require double manual import declarations

   // import modb: TestType;

   // enum signalList =
   // q{
   //    import modb: TestType;
   //    @("Signal"):
   //    void someSig(TestType);
   //    int someOtherSig();
   // }

   // mixin signalsOf!signalList;
}

void main(string[] args)
{
   auto a = new A;
   auto b = new B;
   auto c = new C;

   a.connect!"foo"(&b.fooHandler);
   a.connect(b); // connect all bar's with all onBar's

   a.foo(66);
   a.bar("asd");
   a.bar(4, 6);

   c.connect!"someSig"(&b.someSig);
   b.connect!"someSig"(&a.someFun);

   c.someSig("emitted by c forwarded by b handled by a");

   a.connect!"someTestSig"(&b.someTestSigHandler);
   c.connect!"someTestSig"(&b.someTestSigHandler);

   import modb: TestType;
   TestType t;
   a.someTestSig(t);
   c.someTestSig(t);
}

i assume with DCD's i could remove those manual imports if they get some traits.


December 31, 2016
On Fri, 30 Dec 2016 22:42:39 +0000, Stefan Koch wrote:

> On Friday, 30 December 2016 at 22:29:18 UTC, Chris Wright wrote:
>> * Performance improvements, primarily when a module imports another, bulky module for optional functionality.
> That is solved by selective imports.

Well, not today, but it could be. Same with static imports. Both accomplish this goal better than DIP1005.

>> * Making it easier to locate where things are defined when reading code.
> 
> That is solved by selective imports.

Static imports do that better than selective imports, though it's more typing.

With selective imports, you can either find the declaration in the current module, or find the symbol in an import list. If it's imported, and the module author is using standard code formatting, you will find the import at the top of the module, which will be fast. This is less true with arbitrarily scoped imports.

With DIP1005, you rely on there also being selective or static imports. If the module author didn't use them, then you have to pull out grep.

>> * Making it easier to move declarations between files.
> 
> That is solved by selective imports.

That helps a bit. You still need to exercise discipline in only using selective imports for what you need for visible declarations.

Static imports work about as well, except you can probably write a complicated regex replacement to extract out the imports you need.

DIP1005 is a solid improvement here.

Unfortunately, this is a rather marginal usecase.

-- Another thing that just occurred to me: if you're modifying a function signature and that brings in another imported symbol, you don't have to move to the top of the file or struct to add the necessary import. It's a small thing for vim users, who are used to using marks and fast movement commands, but if you're using, say, VSCode, that might be painful.
December 31, 2016
On Fri, 30 Dec 2016 23:49:23 +0000, Andrei Alexandrescu wrote:
> The main win, which indeed is not emphasized enough, is better encapsulation. Walter pointed that out, and I will redo the DIP to put that front and center.

Encapsulation is an abstraction over several concrete benefits. We're not horribly constrained in time or cognitive effort, so we can talk about the concrete benefits instead of the abstraction.
December 30, 2016
On 12/30/16 7:32 PM, Chris Wright wrote:
> On Fri, 30 Dec 2016 22:42:39 +0000, Stefan Koch wrote:
>
>> On Friday, 30 December 2016 at 22:29:18 UTC, Chris Wright wrote:
>>> * Performance improvements, primarily when a module imports another,
>>> bulky module for optional functionality.
>> That is solved by selective imports.
>
> Well, not today, but it could be. Same with static imports. Both
> accomplish this goal better than DIP1005.

Is this fact or opinion? If the former, could you please point where DIP1005 is getting it wrong. Thanks.

>>> * Making it easier to locate where things are defined when reading
>>> code.
>>
>> That is solved by selective imports.
>
> Static imports do that better than selective imports, though it's more
> typing.

So whether that's overall better is not settled, is it? We can't really define "better" as whatever each participant believes.

> With selective imports, you can either find the declaration in the
> current module, or find the symbol in an import list. If it's imported,
> and the module author is using standard code formatting, you will find
> the import at the top of the module, which will be fast. This is less
> true with arbitrarily scoped imports.
>
> With DIP1005, you rely on there also being selective or static imports.
> If the module author didn't use them, then you have to pull out grep.

DIP1005 allows the declaration to encapsulate its own dependencies. Of course if top-level imports are also present, the benefit erodes.

>>> * Making it easier to move declarations between files.
>>
>> That is solved by selective imports.
>
> That helps a bit. You still need to exercise discipline in only using
> selective imports for what you need for visible declarations.
>
> Static imports work about as well, except you can probably write a
> complicated regex replacement to extract out the imports you need.
>
> DIP1005 is a solid improvement here.
>
> Unfortunately, this is a rather marginal usecase.
>
> -- Another thing that just occurred to me: if you're modifying a function
> signature and that brings in another imported symbol, you don't have to
> move to the top of the file or struct to add the necessary import. It's a
> small thing for vim users, who are used to using marks and fast movement
> commands, but if you're using, say, VSCode, that might be painful.

That's one of the many benefits of encapsulation.


Andrei


December 30, 2016
On 12/30/16 7:34 PM, Chris Wright wrote:
> On Fri, 30 Dec 2016 23:49:23 +0000, Andrei Alexandrescu wrote:
>> The main win, which indeed is not emphasized enough, is better
>> encapsulation. Walter pointed that out, and I will redo the DIP to put
>> that front and center.
>
> Encapsulation is an abstraction over several concrete benefits. We're not
> horribly constrained in time or cognitive effort, so we can talk about
> the concrete benefits instead of the abstraction.

Framing things this way would be really ignorant. DIP1005 can't be in the business of arguing that encapsulation is good by means of examples. First off, there is no undeniable proof that encapsulation is advantageous and not even simple obvious examples; encapsulation has had many opponents, most notably Fred Brooks (the author of "The Mythical Man-Month"), who used a process specifically antithetic to encapsulation in the development of IBM System/360 and OS/360. Far as I recall Fred ultimately ceded the point that encapsulation is superior, but IIRC that was after 2000. I have no doubt there are competent folks out there who think encapsulation is a crock.

So it would be goofy if DIP1005 took the onus to show the advantages of improved encapsulation by means of concrete examples (such don't exist outside of large-scale projects for any kind of encapsulation). What DIP1005 can do is show to someone who already believes that encapsulation is good, that the proposed feature improves encapsulation.


Andrei

December 31, 2016
On Fri, 30 Dec 2016 21:13:19 -0500, Andrei Alexandrescu wrote:
> DIP1005 can't be in
> the business of arguing that encapsulation is good by means of examples.

Right. I said we should talk about the concrete benefits of the proposal instead of talking about encapsulation.
December 31, 2016
On 12/30/16 11:10 PM, Chris Wright wrote:
> On Fri, 30 Dec 2016 21:13:19 -0500, Andrei Alexandrescu wrote:
>> DIP1005 can't be in
>> the business of arguing that encapsulation is good by means of examples.
>
> Right. I said we should talk about the concrete benefits of the proposal
> instead of talking about encapsulation.

Why would the DIP hamstring itself by not discussing its most important advantage? -- Andrei
December 31, 2016
On 31.12.2016 13:23, Andrei Alexandrescu wrote:
> On 12/30/16 11:10 PM, Chris Wright wrote:
>> On Fri, 30 Dec 2016 21:13:19 -0500, Andrei Alexandrescu wrote:
>>> DIP1005 can't be in
>>> the business of arguing that encapsulation is good by means of examples.
>>
>> Right. I said we should talk about the concrete benefits of the proposal
>> instead of talking about encapsulation.
>
> Why would the DIP hamstring itself by not discussing its most important
> advantage? -- Andrei

Because it is a slippery slope if you subscribe to the notion that "D's unit of encapsulation is the module".

Do we need to rethink encapsulation in D? Should there be an additional 'internal' visibility modifier that hides members even to other declarations in the same module?


On an unrelated note: I'm still not a fan of the with(import) syntax as it morally promotes a lack of turtles (even if not technically so).
December 31, 2016
On Tuesday, 13 December 2016 at 22:33:24 UTC, Andrei Alexandrescu wrote:
> Destroy.
>
> https://github.com/dlang/DIPs/pull/51/files

FYI, from the DIP, this is false:

"The static import setup does not share the issue above, at the cost of being cumbersome to use---all imported symbols must use full lookup everywhere. A reasonable engineering approach would be to define shorter names:"

It then proceeds to list a bunch of local aliases. That's not how I'd do it because you can also simply use a renamed import:

static import r = std.range.primitives;

void foo(R)(R range) if(r.isInputRange!(range)) // works today


If the import were lazy - which there's no reason not to be with a static import, renamed or not, since its use is always explicit - then this gives most the same advantages of the DIP.

Granted, you'd still have to look up what `r` means, so it isn't 100% dependency carrying.



Another current language option not discussed in the document is an eponymous template.


But there is another language option today: an eponymous template.

Consider the following:

with (import std.stdio) void process(File input) ;

Let's rewrite that to be:

template process() {
   import std.stdio;
   void process(File input) {

   }
}


The whole symbol is now lazy and encapsulated... and thanks to the existing eponymous rules, it'd be semi-transparent to the user (just error messages would be the main source of leakage, oh god the error messages could be so ugly).

But it works in today's D.



BTW it is my opinion that the "one file, one module" rule is a mistake. Even with all these things, the declarations are still not *guaranteed* to carry their dependencies, since top-level imports still leak in. Separate modules don't have that problem, and if we could just define several modules in one file, we'd basically destroy this DIP in one swift stroke.

I doubt y'all would change that, but still, I'd list that as an alternative in the section that lists many small files as being a major disadvantage, since while we are discussing changing the language, that's a possible change too unless explicitly off the table.