April 04, 2012
Le 03/04/2012 19:44, Martin Nowak a écrit :
> On Fri, 30 Mar 2012 16:46:19 +0200, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Starting a new thread from one in announce:
>>
>> http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP16
>>
>> Please comment, after which Walter will approve. Walter's approval
>> means that he would approve a pull request implementing DIP16 (subject
>> to regular correctness checks).
>>
>>
>> Destroy!
>>
>> Andrei
>
> What about supporting package initalization?
> I basically proposed that if a submodule of a package
> was imported, a static import of the package is implicitly
> added.
> http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP15

That is pretty much what was proposed by people in this thread.

Basically, it boils down to adding automatically aliases with public imports.

I would prefer use pkg.d file instead of pkg/_.d (I though of it a lot recently, and this is what make more sense, even if not my initial proposal).

With pkg/package.d or pkg/_.d you can ends up with unnecessary complexity in choosing the file wich is imported, and create error cases. For instance :

What happen if both pkg.d and pkg/_.d exists ? If it is not in the same path (think -I compiler option). In one case, this is an issue, in the other this isn't.

This file convention solution is superior to the _.d one or package.d one. DIP15 is superior to D16 IMO.
April 04, 2012
On Mon, 02 Apr 2012 20:44:09 -0400, Michel Fortin <michel.fortin@michelf.com> wrote:

> On 2012-04-02 13:04:31 +0000, "Steven Schveighoffer" <schveiguy@yahoo.com> said:
>
>> On Fri, 30 Mar 2012 17:45:36 -0400, Michel Fortin
>>
>>> The problem is that if .std.algorithm.package
>>> contains a sort function and there is also a module called
>>> std.algorithm.sort, the fully-qualified name of that 'sort' module wil l
>>> become ambiguous. Moreover, whether the fully-qualified name
>>> .std.algorithm.sort is ambiguous or not depends on what modules were
>>> imported, which is not a very desirable behaviour.
>>  So this becomes an error.  I don't see this as a major problem.  Just
>> don't name a module sort inside std/algorithm.
>>  This is no different than ambiguous templates, which are allowed until y ou
>> want to instantiate one.
>
> If you have ambiguous templates in the same module, it'll always be ambiguous irrespective of what you import (and you can blame the module's designer for it). If you have ambiguous templates residing in different modules the symbol will be unambiguous until you've imported the second module (same as overloaded functions). At that point you can disambiguate using the fully-qualified name of the template (or function).
>
> Whereas if the fully-qualified name of a module becomes ambiguous because of a symbol in another module, there is no way to disambiguate. All you can do is avoid importing the two conflicting modules together, just like when you encounter two headers trying to define the same symbol in C/C++.

How does this happen?  The FQN cannot be ambiguous.

For example, if we change std/algorithm.d into:

std/algorithm/sorting.d which defines sort
std/algorithm/finding.d which defines find
std/algorithm/package.d which imports sorting.d and finding.d

Then how can importing some other module make the FQN ambiguous?  The FQN for sort is std.algorithm.sorting.sort.  Now, if you define the symbol sort inside std/algorithm/package.d, you have an ambiguity, but so what?  If you are responsible for the std.algorithm module, aren't you responsible for all the files in that pseudo-package?  I don't see how it changes things from today.  Basically, my point is the only ambiguity FQN in the package.d file can create is with other symbols within that same directory, therefore within the same module.

All we have to do is adopt the practice that phobos' package.d will only publicly import other modules.  It won't define any symbols.  Then there will always be an unambiguous FQN.

Hm... maybe you mean if you can have std/algorithm/package.d do something like import std.file, which contains another sort function, is that now packaged under std.algorithm.sort?  I don't think that's possible in the given DIP.

-Steve
April 04, 2012
On 2012-04-04 14:08:34 +0000, "Steven Schveighoffer" <schveiguy@yahoo.com> said:

> On Mon, 02 Apr 2012 20:44:09 -0400, Michel Fortin  <michel.fortin@michelf.com> wrote:
> 
>> Whereas if the fully-qualified name of a module becomes ambiguous  because of a symbol in another module, there is no way to disambiguate.  All you can do is avoid importing the two conflicting modules together,  just like when you encounter two headers trying to define the same  symbol in C/C++.
> 
> How does this happen?  The FQN cannot be ambiguous.

Sure it can if I follow DIP16, because module names can become ambiguous.

Let's try this with an example. First, let's define a pretty standard module:

std/algorithm/sort.d:

	module std.algorithm.sort;

	void sort(T)(T[] array);

Here the fully-qualified name of the sort function is .std.algorithm.sort.sort. But according to DIP16's lookup rules, the sort function is also available (if not ambiguous) at:

	std.sort
	std.algorithm.sort

Question 1: since there is already a module at .std.algorithm.sort, doesn't the module name become ambiguous with the sort function it itself contains?

Let's assume the module's name take priority and does not conflict so we can continue. Now we create the package.d file:

std/algorithm/package.d:

	import std.algorithm.sort;

And now I write this somewhere in my code:

	std.algorithm.sort

Question 2: does std.algorithm.sort refer to the std.algorithm.sort *module* or to std.algorithm.package.sort *function* publicly imported from the std.algorithm.sort module?

Again, we could decide that the module takes priority. But having symbols take priority over one another is not how D has resolved ambiguities up to now; what D does usually is make it a hard error. If we make it an error the fully-qualified name of anything in the std.algorithm.sort module becomes inaccessible. If we do not make it an error, the module name shadows the function imported in the package. And the problem with shadowing is that it can silently change what code you're calling depending on what you've imported (if you need an example, just ask).

You might think I'm trying to split hair in four to find flaws, that no one is going to do things that dumb, but I unfortunately think the problematic pattern is already quite common. How many times have we seen modules containing a class, variable, or function having the same name as the module's name? What should happen when you publicly import those modules in the package.d file?

The practice might not be too prevalent in Phobos because modules tend to do a lot of things and are therefore named more generically, but it still happens. For instance:

	std.array.array
	std.getopt.getopt
	std.regex.regex

Say you wanted to create a package.d file directly for the whole package std, what should be done for those?

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

April 04, 2012
On Wed, 04 Apr 2012 12:33:26 -0400, Michel Fortin <michel.fortin@michelf.com> wrote:

> On 2012-04-04 14:08:34 +0000, "Steven Schveighoffer" <schveiguy@yahoo.com> said:
>
>>  The FQN cannot be ambiguous.
>
> Sure it can if I follow DIP16, because module names can become ambiguous.
>
> Let's try this with an example. First, let's define a pretty standard module:
>
> std/algorithm/sort.d:
>
> 	module std.algorithm.sort;
>
> 	void sort(T)(T[] array);
>
> Here the fully-qualified name of the sort function is .std.algorithm.sort.sort. But according to DIP16's lookup rules, the sort function is also available (if not ambiguous) at:
>
> 	std.sort
> 	std.algorithm.sort
>
> Question 1: since there is already a module at .std.algorithm.sort, doesn't the module name become ambiguous with the sort function it itself contains?

OK, but when is it ever valid to refer to a module when the semantic expectations are for something other than a module?  I can only think of two places where module names are used, inside an import statement and inside a module statement (three if you count the prefix of a FQN).  Maybe I'm missing some case...

> Let's assume the module's name take priority and does not conflict so we can continue. Now we create the package.d file:
>
> std/algorithm/package.d:
>
> 	import std.algorithm.sort;
>
> And now I write this somewhere in my code:
>
> 	std.algorithm.sort
>
> Question 2: does std.algorithm.sort refer to the std.algorithm.sort *module* or to std.algorithm.package.sort *function* publicly imported from the std.algorithm.sort module?

The function.  A symbol that is not specified as the module name in import statement or in a module statement is always *not* a module.  I think our one saving grace here is that when you want to import a specific symbol from a module, this is not the syntax:

import std.stdio.writefln;

So there is never any ambiguity as to whether you mean a module identifier or other symbol.

> You might think I'm trying to split hair in four to find flaws, that no one is going to do things that dumb, but I unfortunately think the problematic pattern is already quite common. How many times have we seen modules containing a class, variable, or function having the same name as the module's name?

Tango anyone? :)  But yes, I think the issue really becomes, we need to look at context when deciding the semantic meaning of a symbol.  I don't think this violates the context-free grammar, because wouldn't this only come into play at the semantic level?  Not a compiler writer/hacker, so I don't know.

> Say you wanted to create a package.d file directly for the whole package std, what should be done for those?

No, let's not do that.  Ever. :)

-Steve
April 04, 2012
On 04/04/2012 07:53 PM, Steven Schveighoffer wrote:
> On Wed, 04 Apr 2012 12:33:26 -0400, Michel Fortin
> <michel.fortin@michelf.com> wrote:
>
>> On 2012-04-04 14:08:34 +0000, "Steven Schveighoffer"
>> <schveiguy@yahoo.com> said:
>>
>>> The FQN cannot be ambiguous.
>>
>> Sure it can if I follow DIP16, because module names can become ambiguous.
>>
>> Let's try this with an example. First, let's define a pretty standard
>> module:
>>
>> std/algorithm/sort.d:
>>
>> module std.algorithm.sort;
>>
>> void sort(T)(T[] array);
>>
>> Here the fully-qualified name of the sort function is
>> .std.algorithm.sort.sort. But according to DIP16's lookup rules, the
>> sort function is also available (if not ambiguous) at:
>>
>> std.sort
>> std.algorithm.sort
>>
>> Question 1: since there is already a module at .std.algorithm.sort,
>> doesn't the module name become ambiguous with the sort function it
>> itself contains?
>
> OK, but when is it ever valid to refer to a module when the semantic
> expectations are for something other than a module? I can only think of
> two places where module names are used, inside an import statement and
> inside a module statement (three if you count the prefix of a FQN).
> Maybe I'm missing some case...

__traits(allMembers, pack.age.mod.ule);

>
>...
>> You might think I'm trying to split hair in four to find flaws, that
>> no one is going to do things that dumb, but I unfortunately think the
>> problematic pattern is already quite common. How many times have we
>> seen modules containing a class, variable, or function having the same
>> name as the module's name?
>
> Tango anyone? :) But yes, I think the issue really becomes, we need to
> look at context when deciding the semantic meaning of a symbol. I don't
> think this violates the context-free grammar, because wouldn't this only
> come into play at the semantic level? Not a compiler writer/hacker, so I
> don't know.

No symbol is resolved until semantic, but I don't think hiding the module/package symbol if any clashing symbol in the module/any subpackage exists is a satisfactory solution.

April 04, 2012
On 2012-04-04 18:33, Michel Fortin wrote:

> You might think I'm trying to split hair in four to find flaws, that no
> one is going to do things that dumb, but I unfortunately think the
> problematic pattern is already quite common. How many times have we seen
> modules containing a class, variable, or function having the same name
> as the module's name? What should happen when you publicly import those
> modules in the package.d file?

I do that all the time in my libraries.

-- 
/Jacob Carlborg
April 04, 2012
On Wed, 04 Apr 2012 14:03:07 -0400, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 04/04/2012 07:53 PM, Steven Schveighoffer wrote:
>> OK, but when is it ever valid to refer to a module when the semantic
>> expectations are for something other than a module? I can only think of
>> two places where module names are used, inside an import statement and
>> inside a module statement (three if you count the prefix of a FQN).
>> Maybe I'm missing some case...
>
> __traits(allMembers, pack.age.mod.ule);

hm... maybe we'd have to have new __traits that would disambiguate, like __traits(allModuleMembers...)

This doesn't seem like a huge barrier.

>
>>
>> Tango anyone? :) But yes, I think the issue really becomes, we need to
>> look at context when deciding the semantic meaning of a symbol. I don't
>> think this violates the context-free grammar, because wouldn't this only
>> come into play at the semantic level? Not a compiler writer/hacker, so I
>> don't know.
>
> No symbol is resolved until semantic, but I don't think hiding the module/package symbol if any clashing symbol in the module/any subpackage exists is a satisfactory solution.

Then we must come up with a way to hide the submodules of a virtual module.

I tried this, which fails on the current compiler:

import x;

int x;

So it seems we have two choices here:

1. DIP16 needs to get more complex to make package submodules not accesible as individual modules.
2. Start contextually interpreting identifiers at least in the case of modules vs. non-modules.

I'd suggest option 2 allows for better backwards compatibility and more flexibility.

-Steve
April 05, 2012
On 2012-04-04 17:53:24 +0000, "Steven Schveighoffer" <schveiguy@yahoo.com> said:

> But yes, I think the issue really becomes, we need to  look at context when deciding the semantic meaning of a symbol.  I don't  think this violates the context-free grammar, because wouldn't this only  come into play at the semantic level?  Not a compiler writer/hacker, so I  don't know.

You'd need a whole lot of context.

Let's say I write:

	.a.b.c.d = .e.f.g.h;

Can you tell me which letters are the name of a package/module, and which are the name of something else? It could be this:

	module a.b;
	struct c { static int d; }

	module e.f.g;
	int h;

or it could be this:

	module a;
	struct b { struct c { struct d { static void opAssign(int); } } }

	module e;
	struct f { enum g { h = 1 } }

or a multitude of other variants. If you can't know by looking at the assignment above, how will the parser know?

Fully qualified names really need to refer to a single thing.


>> Say you wanted to create a package.d file directly for the whole package  std, what should be done for those?
> 
> No, let's not do that.  Ever. :)

Phobos is just an example. People will want to use "package.d" files for their own libraries too, and will complain if it doesn't work.


-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

April 05, 2012
On 2012-04-04 19:48:32 +0000, "Steven Schveighoffer" <schveiguy@yahoo.com> said:

> On Wed, 04 Apr 2012 14:03:07 -0400, Timon Gehr <timon.gehr@gmx.ch> wrote:
> 
>> No symbol is resolved until semantic, but I don't think hiding the  module/package symbol if any clashing symbol in the module/any  subpackage exists is a satisfactory solution.
> 
> Then we must come up with a way to hide the submodules of a virtual module.
> 
> I tried this, which fails on the current compiler:
> 
> import x;
> 
> int x;
> 
> So it seems we have two choices here:
> 
> 1. DIP16 needs to get more complex to make package submodules not  accesible as individual modules.
> 2. Start contextually interpreting identifiers at least in the case of  modules vs. non-modules.
> 
> I'd suggest option 2 allows for better backwards compatibility and more  flexibility.

I don't think option 2 is realistic (see my other post).

I don't think option 1 is an improvement over what we have. I mean, if you're going to hide the submodules, what is the benefit compared to just using a different package name for the implementation modules? You can already refactor std.algorithm this way with no change in the compiler:

	module std.algorithm;

	public import std.algorithm_impl.sort;
	public import std.algorithm_impl.map;
	public import std.algorithm_impl.blah_blah_blah;
	…

If we add a language feature, it should be an noticeable improvement over this situation.

I think we need a third option.

Here's an idea: we could allow modules having a single symbol with the same name as the module to behave as if they were the symbol itself, just like templates behaves. For instance:

	module std.algorithm.sort;

	void sort(int[] t);

Now you can import std.algorithm.sort and then use the std.algorithm.sort fully qualified name as if it was a function, even though it's the module name (std.algorithm.sort.sort would be the function's name).

Or maybe we could just allow "alias sort this" at module level? Or is it allowed already?


-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

April 05, 2012
> What happen if both pkg.d and pkg/_.d exists ? If it is not in the same path (think -I compiler option). In one case, this is an issue, in the other this isn't.
pkg.d would always be a module, hence result in a module/package conflict.
We'd need to directly search for a subdirectory to decide whether it's a package.

Maybe someone with experience of big Python projects has some valuable
insights, but I think one point of adding the file inside a folder is to
prevent from unintended pickup of folders.