March 30, 2012
On Friday, March 30, 2012 20:06:57 Andrej Mitrovic wrote:
> On 3/30/12, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> > Destroy!
> 
> "That means a program that imports std.algorithm may use "std.sort" for the symbol "std.algorithm.sort"."
> 
> That's quite interesting. Would that also mean that you could do:
> import std.algorithm; // has indexOf
> import std.string; // has indexOf
> void main() {
> string.indexOf("foo", "foo"); -> std.string.indexOf
> }

No, I don't think so. If I understand the proposal correctly, it would enable std.indexOf (which doesn't help you at all in this case), not string.indexOf. It's trying to make it so that you can treat a symbol in a sub-module as it were in a higher module, and string.indexOf doesn't help with that at all.

- Jonathan M Davis
March 30, 2012
On Friday, March 30, 2012 12:15:44 Brad Anderson wrote:
> On Fri, Mar 30, 2012 at 12:06 PM, Andrej Mitrovic <
> 
> andrej.mitrovich@gmail.com> wrote:
> > On 3/30/12, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> > > Destroy!
> > 
> > "That means a program that imports std.algorithm may use "std.sort" for the symbol "std.algorithm.sort"."
> > 
> > That's quite interesting. Would that also mean that you could do:
> > import std.algorithm; // has indexOf
> > import std.string; // has indexOf
> > void main() {
> > 
> > string.indexOf("foo", "foo"); -> std.string.indexOf
> > 
> > }
> 
> I was actually kind of surprised when I found out this doesn't work. It seems so natural to resolve ambiguity using as little context as necessary.

It would certainly be desirable in some cases, but I believe that the reason that it doesn't work is due to the ambiguities that it would create. I'd have to go dig up old discussions on it though to remember all of the details.

alias is supposed to solve the problem, but it doesn't really work all that well for it, since private doesn't hide symbols, it only makes them inaccessible (just like with C++). So, creating aliases in a module causes problems in other modules that import that module, even if the aliases are private. There are definitely some folks pushing for private to actually start hiding symbols (IIRC, there's even a pull request for it), but I don't know what the odds of convincing Walter are. If/Once that happens, alias will actually become usable for this sort of situation, and the inability to do string.indexOf won't be as big a deal.

- Jonathan M Davis
March 30, 2012
On Friday, 30 March 2012 at 18:39:44 UTC, Jonathan M Davis wrote:
> I'd propose that we make it so that if a module publicly imports another
> module, then you could treat it as if it were in that module. So, because
> std.datetime.package publicly imports std.datetime.systime, you could use
> std.datetime.SysTime instead of std.datetime.systime.SysTime.

I'm not sure if that's a good idea. I'd prefer a new kind of import statement, perhaps something like:

// module std.datetime.package
alias import std.datetime.systime;

which is similar to a public alias of everything in that module?
March 30, 2012
On 3/30/12 1:39 PM, Jonathan M Davis wrote:
> However, I'm very nervous about the second part. e.g. std.sort instead of
> std.algorithm.sort seems like a bad idea to me. It increases the odds of name
> conflicts for little benefit.

Example?

> Not to mention, it'll make it a lot more confusing
> to find what modules stuff is actually in if people start doing stuff like
>
> std.sort(arr);
>
> In the case of sort, you may know where it's from - particularly since it's so
> common - but the less well-known the function is, the less likely that is at
> all obvious where it comes from, and if you're dealing with 3rd party
> software, then it wouldn't be at all obvious. For instance, how would you know
> that party.foo is really party.bar.foo? You wouldn't.

Why should you?

> Being so lax about
> importing could really harm code readibility (and maintainibility, since it
> increases the odds of name clashes). So, I'm inclined to say that that is a
> _bad_ idea.

Maybe if you produce a solid example, I'd be convinced.


Andrei
March 30, 2012
My comments:

1. My first impression was that using "foo/bar/package.d" instead of "foo/bar.d" seemed a bit odd and messy. But I realize now that cleverly solves the issue where "foo/bar.d" would be considered to be inside a different package from "foo/bar/*.d". So I like that. Personally, I think I would have gone with "foo/bar/_.d" as that sorts much, much better, but naming debates can go on forever, and I can live with "package.d"

2. I don't understand any of this:

-------------------------------------------
When looking up the symbol "foo.bar.baz", currently an exact match is needed. However. when looking up ".baz" or simply "baz", a flexible lookup is used that has many advantages (less verbose, hijacking detection etc). Therefore we think similar flexibility should be imparted to "foo.bar.baz", as follows:

If a qualified symbol "foo.bar.baz" appears in code, the compiler considers "foo.bar" a prefix that sets the starting point of the lookup, and then proceeds with looking up "baz" from that starting point. That means a program that imports std.algorithm may use "std.sort" for the symbol "std.algorithm.sort".
-------------------------------------------

I *do* understand "a program that imports std.algorithm may use "std.sort" for the symbol 'std.algorithm.sort'", and I think that's a good idea. It solves a problem I hadn't even thought of. But I don't understand that stuff I quoted above. Perhaps you could reword/clarify?

3. Other than that stuff, I'm very much in favor of this. I'll have some of that!


March 30, 2012
On Friday, 30 March 2012 at 18:15:57 UTC, Brad Anderson wrote:
> On Fri, Mar 30, 2012 at 12:06 PM, Andrej Mitrovic <
> andrej.mitrovich@gmail.com> wrote:
>
>> On 3/30/12, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> > Destroy!
>>
>> "That means a program that imports std.algorithm may use "std.sort"
>> for the symbol "std.algorithm.sort"."
>>
>> That's quite interesting. Would that also mean that you could do:
>> import std.algorithm;  // has indexOf
>> import std.string;  // has indexOf
>> void main() {
>>    string.indexOf("foo", "foo"); -> std.string.indexOf
>> }
>>
>>
> I was actually kind of surprised when I found out this doesn't work.  It
> seems so natural to resolve ambiguity using as little context as necessary.

Ya that was the behavior I expected as well. Would be great if it worked like that. Just back trace the reference until the ambiguity is resolved.


// -----

Also, I'm probably missing something here, but I never understood why importing a package doesn't work like it does in Actionscript/Java/others...

import foo.bar.*; // everything
import foo.bar.all; // custom

That makes a lot of sense to me.

March 30, 2012
"Timon Gehr" <timon.gehr@gmx.ch> wrote in message news:jl4jmg$2j1r$1@digitalmars.com...
>
> I don't really like the second one.
>
> 1. It is an over-general solution, because it does not solve a general problem.
>
> Maybe it would be better to just interpret foo.bar.baz as foo.bar.package.baz if foo.bar is a package that has been imported via the foo.bar.package rewrite?

That occurred to me, and I thought about proposing the same thing you're suggesting, but on second thought I wasn't so sure:

If I need to disambiguate between "std.algorithm.find" and "foo.bar.baz.find", it might be nice to be able to just say "Meh, just...that one in Phobos, ie 'std'". Or "Just go with that 'foo' one".

I could go either way, really.


March 30, 2012
"Robert Clipsham" <robert@octarineparrot.com> wrote in message news:jl4l5t$2m62$1@digitalmars.com...
> On 30/03/2012 15:46, Andrei Alexandrescu 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
>
> The proposal doesn't say what happens when package.d is not found but foo/bar/ exists.
>
> Given that a lot of people will just use public import foo.bar.*; in that file, would it make sense for package.d missing to imply import foo.bar.*? That would save typing out every single file in there. Of course it would also be annoying if you wanted to import everything except one file, as you'd then have to type out every single import anyway.
>

That would effectively be the same as Java's "import foo.*" and a lot of people have issues with that.

> The other option is to error, which is probably a more sane option.
>

That's what I'd suggest doing. Just treat it like importing any other missing package.


March 30, 2012
On Friday, March 30, 2012 14:33:58 Andrei Alexandrescu wrote:
> On 3/30/12 1:39 PM, Jonathan M Davis wrote:
> > However, I'm very nervous about the second part. e.g. std.sort instead of std.algorithm.sort seems like a bad idea to me. It increases the odds of name conflicts for little benefit.
> 
> Example?

std.sort works because there's only one sort. If there are two, you get a conflict (e.g. if you had std.path.sort which sorted paths in some path-specific manner). If std.path.sort existed now, then std.sort wouldn't work, and you'd be forced to specify std.algorithm.sort or std.path.sort, and that's fine. It would be similar to having to specify std.algorithm.indexOf when you've imported both std.string and std.algorithm. But the problem is when std.path.sort is added _later_.

All of a sudden, code which used std.sort and worked is now broken. The problem does currently exist in that if we added indexOf to another module - say std.array - then code which imported either std.string or std.algorithm as well as std.array would break with the addition of std.array.indexOf, but your proposal makes it worse. Not only does it provide another way in which adding a function could result in conflicts when existing code is recompiled, but it makes it so that if you add any function anywhere in the _entire standard library_ which has the name as an existing one, you get a conflict (if anyone uses std.x rather than x or the full import path).

D does a good job of providing ways to fix name conflicts, but it doesn't do a good job of preventing them when adding new symbols to a library (primarily because it doesn't use static imports by default), and your proposal makes that part of the problem worse. If std.x were to become common practice, then any time that you added a symbol to a library when that symbol was already used by another module, you'd create conflicts (combined with the fact that private doesn't hide symbol names but merely makes them inaccessible, this could result in a lot of symbol name conflicts).

> > Not to mention, it'll make it a lot more confusing
> > to find what modules stuff is actually in if people start doing stuff like
> > 
> > std.sort(arr);
> > 
> > In the case of sort, you may know where it's from - particularly since it's so common - but the less well-known the function is, the less likely that is at all obvious where it comes from, and if you're dealing with 3rd party software, then it wouldn't be at all obvious. For instance, how would you know that party.foo is really party.bar.foo? You wouldn't.
> 
> Why should you?

Do you know what the foo function does? If you don't, you're going to have to look it up. And if you don't know what module it comes from, you can't do that. You also have to know where foo is from if a foo function is added to another module and causes a conflict, because you're going to have to give the full import path to actually use it. That's currently true with just bare foo as well, but party.foo gives the illusion of specifying where foo is from without actually specifying where it's from. At least right now, if foo is used with its import path, you know that that's actually its import path.

Also, what happens if we want to add a module named sort later? The fact that people are using std.sort means that adding std.sort as a module will break code. Granted, it's not very likely that we're going to add a module named sort, but there are plenty of other symbol names that it could happen with. But then again, if we decided to provide a module with all of the major sort algorithms, then maybe we _would_ create a module named std.sort. Just because we don't see a need now doesn't mean that we won't later. In either case, by allowing std.x where x is a symbol in any sub-module of std, you're going to create conflicts any time that you add a module which has the same name as an existing symbol anywhere in the library.

> > Being so lax about
> > importing could really harm code readibility (and maintainibility, since
> > it
> > increases the odds of name clashes). So, I'm inclined to say that that is
> > a
> > _bad_ idea.
> 
> Maybe if you produce a solid example, I'd be convinced.

Well, as I've pointed with a few examples here, your proposal will increase the chances of adding symbol conflicts any time that a symbol is added to a library all just so that you can do std.algorithm.sort instead of std.algorithm.submodule1.sort once sort has been moved to std.algorithm.sumodule1. And we could make it possible to do std.algorithm.sort without adding all of those possible conflicts.

The simplest solution would simply be to make it so that if std.algorithm.sort is used, and std.algorithm is a package with a std.algorithm.package module, then the compiler looks in all of the sub-modules of std.algorithm to find sort. That solves the problem right there without increasing the odds of symbol conflicts across the entire library like your proposal does.

But personally, I like the idea of making it so that publicly imported symbols can be accessed as if they were in the module that publicly imported them (with package.d being treated as if it had the same name as the package that it's in). That's essentially how it already works except when specifying the full import path for a symbol. And that way, you can specify in std.algorithm.package.d exactly what you want to be imported when std.algorithm is imported (including using : to restrict it to specific symbols in a module), and only those symbols will be treated as if they were part of std.algorithm - both for importing purposes and when specifying the import path when using a symbol. The library maintainer then has control over which symbols get used with which import paths.

- Jonathan M Davis
March 30, 2012
"Andrej Mitrovic" <andrej.mitrovich@gmail.com> wrote in message news:mailman.1240.1333130858.4860.digitalmars-d@puremagic.com...
>
> Still this is one of the few proposals I like. My only caveat is the
> comment: "except the file is not allowed to use the "module"
> declaration.". Wouldn't it be better if we explicitly declared a
> module as a package instead? In foo\bar\package.d:
> package foo.bar;
>
> Since the "module" declaration must be on the first line (or second line after shebang), you could special-case DMD to allow the package keyword to be used here. I know D likes to abuse a keyword for multiple things (hello Mr. Static!), but I think we could live with it.

Or maybe just require the module name ends with ".package"