July 07, 2006
Fredrik Olsson wrote:
>
> Yet again I must point out that D really should have sets and ranges! ;)

Ada has constrained types as well and I think it's a terrific feature. Perhaps 2.0 :-)


Sean
July 07, 2006
Fredrik Olsson wrote:
> kris skrev:
> 
>> Just for fun, how many folks here have hands-on experience with any of the following languages?
>>
>> Algol
> 
> Nope
> 
>> Pascal
> 
> Hobby projects since 1988, professionally since 1995. I would hardly classify Pascal as a historical language.
> 
>> BCPL
> 
> nope
> 
>> Ada
> 
> For a few months in 1999, army stuff.
> 
>> Modula
> 
> Only Modula-2, back in 1992 on Atari ST, and barely a few hundred lines of code in Objective Modula-2 this year.
> 
>> Simula
> 
> nope.
> 
> 
> Since Pascal fits the bill I think you should also add LISP, FORTRAN, COBOL, and Prolog :).


hehe ... the list is comprised of pure Algol derivatives. It ignores those with only a little Algol influence, such as Fortran-77 and PL1 for example. C & C++ are a true part of the Algol family, but pretty much everyone here has been exposed to those.

The 'historical' attribute was a poor choice of word on my part ~ intended only to tie into the derivation aspect (from Algol)
July 07, 2006
Sean Kelly wrote:
> Walter Bright wrote:
>>
>> And I still don't know anything about M3 <g>. But being able to extend imports without breaking users can easily be done with some variation on the PIMPL technique or interfaces.
> 
> But PIMPL only works if combined with header files, and it shouldn't be necessary to resort to this just to avoid symbol collisions with implementation-level stuff.  I do think it's a useful tool when complete implementation hiding is necessary for business reasons, but not as a general tool to work around what feels like a language issue.

It isn't to avoid symbol collisions, it's to make the user of the class immune to adding new members to the implementation of the class.
July 07, 2006
Walter Bright wrote:
> Sean Kelly wrote:
>> Walter Bright wrote:
>>>
>>> And I still don't know anything about M3 <g>. But being able to extend imports without breaking users can easily be done with some variation on the PIMPL technique or interfaces.
>>
>> But PIMPL only works if combined with header files, and it shouldn't be necessary to resort to this just to avoid symbol collisions with implementation-level stuff.  I do think it's a useful tool when complete implementation hiding is necessary for business reasons, but not as a general tool to work around what feels like a language issue.
> 
> It isn't to avoid symbol collisions, it's to make the user of the class immune to adding new members to the implementation of the class.

Ah, my mistake then.  I confused what you were saying with my comment on the D import rules.


Sean
July 07, 2006
kris wrote:
> D imports an entire module, into the current namespace (or some variation upon that). This means that any additions to the original module have to be aware of the namespace usage of *any* module that imports the original. Otherwise, a namespace collision will occur and the combination will fail to compile. M3 import explicitly from each module instead ~ you can't have such a collision. The value of that is just as solid today as it was in 1989.
> 
> One might argue that with D, one should create new modules instead of extending existing ones? That's a fair point until you consider that the module namespace is limited to one file, and the 'friend' aspect is limited to one module (private attributes being visible within the one module). Thus, D suffers this problem in a notable manner.
> 
> I forget whether M3 supports importing into a distinct namespace or not --- the "import x.y.z. as foo;" syntax -- but that can alleviate related problems, and would help resolve the current D namespace conflicts that are quite prevalant?

import namespaces are second class citizens in D - they are easily overridden by using aliases or fully qualified lookups:

import a;	// defines foo()
import b;	// defines foo()

foo();		// ambiguous
a.foo();	// doesn't matter if there's a b.foo
b.foo();	// works

alias a.foo foo;
foo();		// works

As for import x.y.z. as foo;, you can do:

alias x.y.z foo;
foo.bar();

alias x.y abc;
abc.x.bar();

alias x def;
def.y.z.bar();

The alias works at any level you choose to make it. Alias can be used to 'import' any name into the current namespace, making it first class.

The second class lookup capability is to make it easier to write quick and dirty programs. Aliases or fully qualified names should be used when writing large, complex apps. Think of it like using private - you wouldn't bother with it for small or throwaway programs, but you wouldn't think of not using it for long lived or complex apps.
July 07, 2006
Sean Kelly wrote:
> Peter C. Chapin wrote:
>> kris <foo@bar.com> wrote in news:e8kg0a$14hu$1@digitaldaemon.com:
>>
>>> Ada
>>
>> I'm not sure how "historical" Ada is... there is currently an active community of Ada users. In any case, I use Ada a fair amount. In fact, as I write this I have some Ada code that I'm working on open in another window.
> 
> For whatever reason, Ada doesn't seem to be a terribly popular language for everyday programming.  It has a lot of nice features though, and I've always been somewhat interested in finding the time to play with it a bit.  In many respects it seems like a stricter version of D.
> 

Isn't Ada still used (required?) for a lot of Dept. of Defense software in the U.S.?

I did see some postings for Java a while back, which surprised me because I had thought Ada was basically mandated for all DOD work, but maybe that still isn't the case.

> I suppose I could add to the list with:
> 
> BASIC
> Prolog
> 
> 
> Sean
July 07, 2006
Walter Bright wrote:
> kris wrote:
> 
>> D imports an entire module, into the current namespace (or some variation upon that). This means that any additions to the original module have to be aware of the namespace usage of *any* module that imports the original. Otherwise, a namespace collision will occur and the combination will fail to compile. M3 import explicitly from each module instead ~ you can't have such a collision. The value of that is just as solid today as it was in 1989.
>>
>> One might argue that with D, one should create new modules instead of extending existing ones? That's a fair point until you consider that the module namespace is limited to one file, and the 'friend' aspect is limited to one module (private attributes being visible within the one module). Thus, D suffers this problem in a notable manner.
>>
>> I forget whether M3 supports importing into a distinct namespace or not --- the "import x.y.z. as foo;" syntax -- but that can alleviate related problems, and would help resolve the current D namespace conflicts that are quite prevalant?
> 
> 
> import namespaces are second class citizens in D - they are easily overridden by using aliases or fully qualified lookups:
> 
> import a;    // defines foo()
> import b;    // defines foo()
> 
> foo();        // ambiguous
> a.foo();    // doesn't matter if there's a b.foo
> b.foo();    // works
> 
> alias a.foo foo;
> foo();        // works
> 
> As for import x.y.z. as foo;, you can do:
> 
> alias x.y.z foo;
> foo.bar();
> 
> alias x.y abc;
> abc.x.bar();
> 
> alias x def;
> def.y.z.bar();
> 
> The alias works at any level you choose to make it. Alias can be used to 'import' any name into the current namespace, making it first class.
> 
> The second class lookup capability is to make it easier to write quick and dirty programs. Aliases or fully qualified names should be used when writing large, complex apps. Think of it like using private - you wouldn't bother with it for small or throwaway programs, but you wouldn't think of not using it for long lived or complex apps.


Yes, I'm aware of those various workarounds, but none of them address the issue. As I'm sure you're aware of, all of these need to be used at the import site ... not in the importee code. This is where the issues arise.

What I was getting at is this:

-------------
module importee;

class Foo {}
-------------

and

-------------
module importer;

import importee;

class Bar {}

class Bazooka {}
-------------


now, suppose we later change module importee like so:

-------------
module importee;

class Foo {}

class Bazooka {}
-------------

Now, module importer will not compile. It needs to be re-engineered regardless, since no amount of aliasing of the /importee module/ will work. This is where a bit of foresight should come into play regarding import namespaces and so on (within the D language). There are a number of solutions available. It is precicely this kind of re-engineering that should be rendered completely unecessary.

The second aspect is the whole alias notion is just too weak to handle large-scale development. In other languages, the syntax "import x.y.z as foo;" actually does create a unique namespace, achieving two things:

a) there's no other way to refer to x.y.z content other than through the "foo." prefix. This eliminates the potential for conflicting names across multiple modules, regardless of long-term maintenance in any of them. Relying on the D "alias" mechanism for such needs is prone to abject failure.

b) alias simply provides an /additional/ means of referring to some element. All of the original names are still there, from the entirety of the imported module. The potential for name collisions, such as two classes called 'Bazooka' is painfully obvious.

The whole concept of long-term and/or large-scale development using D as a tool is marred by such problems -- it's not very hard to fix either -- perhaps as simple as the "import x.y.z as foo;" syntax, which is quite quite different from the concept of alias. I sincerely hope you'll agree on that distinction?



July 07, 2006
Walter Bright wrote:
> kris wrote:
>> D imports an entire module, into the current namespace (or some variation upon that). This means that any additions to the original module have to be aware of the namespace usage of *any* module that imports the original. Otherwise, a namespace collision will occur and the combination will fail to compile. M3 import explicitly from each module instead ~ you can't have such a collision. The value of that is just as solid today as it was in 1989.
>>
>> One might argue that with D, one should create new modules instead of extending existing ones? That's a fair point until you consider that the module namespace is limited to one file, and the 'friend' aspect is limited to one module (private attributes being visible within the one module). Thus, D suffers this problem in a notable manner.
>>
>> I forget whether M3 supports importing into a distinct namespace or not --- the "import x.y.z. as foo;" syntax -- but that can alleviate related problems, and would help resolve the current D namespace conflicts that are quite prevalant?
> 
> import namespaces are second class citizens in D - they are easily overridden by using aliases or fully qualified lookups:
> 
> import a;    // defines foo()
> import b;    // defines foo()
> 
> foo();        // ambiguous
> a.foo();    // doesn't matter if there's a b.foo
> b.foo();    // works
> 
> alias a.foo foo;
> foo();        // works
> 
> As for import x.y.z. as foo;, you can do:
> 
> alias x.y.z foo;
> foo.bar();
> 
> alias x.y abc;
> abc.x.bar();
> 
> alias x def;
> def.y.z.bar();
> 
> The alias works at any level you choose to make it. Alias can be used to 'import' any name into the current namespace, making it first class.
> 
> The second class lookup capability is to make it easier to write quick and dirty programs. Aliases or fully qualified names should be used when writing large, complex apps. Think of it like using private - you wouldn't bother with it for small or throwaway programs, but you wouldn't think of not using it for long lived or complex apps.

I like the second class lookup capability as it leads to clear and predictable behavior.  And I agree that 'alias' is a very useful tool for handling more advanced requirements.  Kris does as well, I beleive, as the "import x.y.z as foo;" proposal was meant as a shorthand for:

    import x.y.z;
    alias x.y.z foo;

With the issue of whether the contents of x.y.z are visible without the 'foo' qualifier as an open issue (IMO).

However, the current lookup rules are such that the need to alias or fully-qualify names is really quite common, and it is confusing for those new to the language.  For example:

    module modA;

    void someFunc() {}

----------

    module modB;

    private void someFunc() {}
    void doSomething() { someFunc(); }

----------

    import modA;
    import modB;

    void main()
    {
        doSomething();
        someFunc();
    }

Compiling the above gives:

    modA.d(3): function modA.someFunc conflicts with
               modB.someFunc at modB.d(3)

Thus requiring the user to fully qualify his call to someFunc even though the collision is with a function that he shouldn't be aware of in the first place.

Now I'll admit that I used to fully support the current lookup mechanism, but I've since used D a lot more and this issue has bitten me quite a bit since then.  So I decided to do some digging and discovered that the lookup mechanism for C++ classes (which the D mechanism is obviously based on) was done mostly for practical reasons to deal with compiling out-of-class member definitions, and that the current suggestion for modules in C++ includes making module-level declarations truly invisible to importing modules (the original post is here: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/39072).

I have no intentions of suggesting that the import mechanism be fundamentally changed from how it works now, but is there any chance symbol lookup and visibility rules could be examined a bit before 1.0? I know others have brought up related problems in the past regarding mixin visiblity rules and such as well, and perhaps it would do to establish whether things could be tweaked a bit to resolve these complaints without pressing for a sea change?


Sean
July 07, 2006
Dave wrote:
> Sean Kelly wrote:
>> Peter C. Chapin wrote:
>>> kris <foo@bar.com> wrote in news:e8kg0a$14hu$1@digitaldaemon.com:
>>>
>>>> Ada
>>>
>>> I'm not sure how "historical" Ada is... there is currently an active community of Ada users. In any case, I use Ada a fair amount. In fact, as I write this I have some Ada code that I'm working on open in another window.
>>
>> For whatever reason, Ada doesn't seem to be a terribly popular language for everyday programming.  It has a lot of nice features though, and I've always been somewhat interested in finding the time to play with it a bit.  In many respects it seems like a stricter version of D.
>>
> 
> Isn't Ada still used (required?) for a lot of Dept. of Defense software in the U.S.?

I believe Ada was designed on a DoD contract, so it's not surprising that it's used quite a bit in the military.  More generally however, Ada seems be the language of choice for systems that simply cannot fail, be they railway switches, supertanker engine systems, etc.  However, I was surprised to hear that C/C++ is making inroads in these areas--probably because so many more people know C/C++ than Ada.


Sean
July 07, 2006
to clarify, here's some examples:

--------------
module foo;

import bar;
import wumpus;

extern (C) int printf (char*, ...);

class Bar {char[] toString() {return "foo.Bar";}}

void main()
{
        auto bar = new Bar;
        auto wumpus = new Wumpus;

        printf ("%.*s\n", bar.toString);
        printf ("%.*s\n", wumpus.toString);
}
-------------


-------------
module bar;

class Bar {char[] toString() {return "bar.Bar";}}
-------------


-------------
module wumpus;

class Wumpus {char[] toString() {return "wumpus.Wumpus";}}
-------------


What's interesting here is the lack of conflict between bar.Bar and foo.Bar. The compiler ignores the conflicting names and uses foo.Bar within main().

Now, assume both modules foo and bar are from different vendors. Module bar gets changed at some point to this:

-------------
module bar;

class Bar {char[] toString() {return "bar.Bar";}}

class Wumpus {char[] toString() {return "bar.Wumpus";}}
-------------


The vendor added a Wumpus class to the module. Quite innocent. In this case, the program now fails to compile, and the user-code needs to be re-engineered. The amount of redundant work may be small, or it may be very large. This is simply redundant work ~ it should not be necessary at all.

One way to avoid the re-engineering is to use
"import wumpus as ...."
"import bar as ...."

In this case, the instances of Bar and Wumpus must be fully qualified -- you can't access them any other way. Thus it would be "auto bar = new bar.Bar;", or whatever.

Another approach is to import explicitly, just like Modula-3 does:

import Bar from bar;
import Wumpus from wumpus;

In this case, it's pretty clear than any additions to modules from either vendor will not result in re-engineering work. It's also a bit closer to the current D model.


Another question is this: why is there no conflict between the two Bar declarations in the first case, while there is between the two Wumpus instances in the second case? I suspect this is down to where the decl actually resides (which module).






kris wrote:
> Walter Bright wrote:
> 
>> kris wrote:
>>
>>> D imports an entire module, into the current namespace (or some variation upon that). This means that any additions to the original module have to be aware of the namespace usage of *any* module that imports the original. Otherwise, a namespace collision will occur and the combination will fail to compile. M3 import explicitly from each module instead ~ you can't have such a collision. The value of that is just as solid today as it was in 1989.
>>>
>>> One might argue that with D, one should create new modules instead of extending existing ones? That's a fair point until you consider that the module namespace is limited to one file, and the 'friend' aspect is limited to one module (private attributes being visible within the one module). Thus, D suffers this problem in a notable manner.
>>>
>>> I forget whether M3 supports importing into a distinct namespace or not --- the "import x.y.z. as foo;" syntax -- but that can alleviate related problems, and would help resolve the current D namespace conflicts that are quite prevalant?
>>
>>
>>
>> import namespaces are second class citizens in D - they are easily overridden by using aliases or fully qualified lookups:
>>
>> import a;    // defines foo()
>> import b;    // defines foo()
>>
>> foo();        // ambiguous
>> a.foo();    // doesn't matter if there's a b.foo
>> b.foo();    // works
>>
>> alias a.foo foo;
>> foo();        // works
>>
>> As for import x.y.z. as foo;, you can do:
>>
>> alias x.y.z foo;
>> foo.bar();
>>
>> alias x.y abc;
>> abc.x.bar();
>>
>> alias x def;
>> def.y.z.bar();
>>
>> The alias works at any level you choose to make it. Alias can be used to 'import' any name into the current namespace, making it first class.
>>
>> The second class lookup capability is to make it easier to write quick and dirty programs. Aliases or fully qualified names should be used when writing large, complex apps. Think of it like using private - you wouldn't bother with it for small or throwaway programs, but you wouldn't think of not using it for long lived or complex apps.
> 
> 
> 
> Yes, I'm aware of those various workarounds, but none of them address the issue. As I'm sure you're aware of, all of these need to be used at the import site ... not in the importee code. This is where the issues arise.
> 
> What I was getting at is this:
> 
> -------------
> module importee;
> 
> class Foo {}
> -------------
> 
> and
> 
> -------------
> module importer;
> 
> import importee;
> 
> class Bar {}
> 
> class Bazooka {}
> -------------
> 
> 
> now, suppose we later change module importee like so:
> 
> -------------
> module importee;
> 
> class Foo {}
> 
> class Bazooka {}
> -------------
> 
> Now, module importer will not compile. It needs to be re-engineered regardless, since no amount of aliasing of the /importee module/ will work. This is where a bit of foresight should come into play regarding import namespaces and so on (within the D language). There are a number of solutions available. It is precicely this kind of re-engineering that should be rendered completely unecessary.
> 
> The second aspect is the whole alias notion is just too weak to handle large-scale development. In other languages, the syntax "import x.y.z as foo;" actually does create a unique namespace, achieving two things:
> 
> a) there's no other way to refer to x.y.z content other than through the "foo." prefix. This eliminates the potential for conflicting names across multiple modules, regardless of long-term maintenance in any of them. Relying on the D "alias" mechanism for such needs is prone to abject failure.
> 
> b) alias simply provides an /additional/ means of referring to some element. All of the original names are still there, from the entirety of the imported module. The potential for name collisions, such as two classes called 'Bazooka' is painfully obvious.
> 
> The whole concept of long-term and/or large-scale development using D as a tool is marred by such problems -- it's not very hard to fix either -- perhaps as simple as the "import x.y.z as foo;" syntax, which is quite quite different from the concept of alias. I sincerely hope you'll agree on that distinction?
> 
> 
>