View mode: basic / threaded / horizontal-split · Log in · Help
April 04, 2012
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
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
Re: DIP16: Transparently substitute module with package
> 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.
1 2 3 4 5 6 7 8 9
Top | Discussion index | About this forum | D home