April 21, 2009
Leandro Lucarella wrote:
> Andrei Alexandrescu, el 21 de abril a las 07:38 me escribiste:
>> Lars T. Kyllingstad wrote:
>>> Walter Bright wrote:
>>>> This is a major revision to Phobos, including Andrei's revolutionary new range support.
>>>>
>>>> http://www.digitalmars.com/d/2.0/changelog.html
>>>> http://ftp.digitalmars.com/dmd.2.029.zip
>>> This is looking very nice! I want to switch from D1 to D2, but...
>>> I don't want to sound greedy or anything, and I know others have asked for this before, but is making a 64-bit Linux version of DMD a lot of work?
>> I would kill for a 64-bit Linux DMD. I think it could take a lot of ways of coding to a whole new level. Sean and I have also been discussing how to integrate memory-mapped files with the garbage collector. In a 64-bit environment this makes for an awesome programming model.
> 
> Can you elaborate on that?

Not much time, but in short: Memory-mapped files are not a pure library thing, they are core because they manipulate the address space. So they are quite like memory allocation. Unmapping files by hand is as unsafe as calling delete. So memory mapped files must be integrated with the collector: you map a file by hand, and the garbage collector closes it when there are no more references to the memory mapped for the file.

The programming model is pretty cool - in 32 bit I always need to mind the address space because it's so densely populated. In 64 bits I can map all of my data files in memory and let the paging system and the garbage collector take care of the rest.


Andrei
April 21, 2009
I have also tested the semantics of nested function purity:

import std.c.stdio: printf;
import std.conv: to;

pure int double_sqr(int x) {
    pure int sqr(int y) { return y * y; }
    return sqr(x) + sqr(x);
}

void main(string[] args) {
    int x = args.length == 2 ? to!(int)(args[1]) : 10;
    int y = double_sqr(x) + double_sqr(x);
    printf("4 * x * x = %d\n", y);
}

Compiled without inlining:
-O -release

double_sqr.sqr:
        mov EAX,4[ESP]
        imul    EAX,EAX
        ret 4

double_sqr:
L0:     push    EAX
        push    EAX
        xor EAX,EAX
        call    near ptr double_sqr.sqr
        push    EAX
        sub ESP,4
        xor EAX,EAX
        push    dword ptr 8[ESP]
        call    near ptr double_sqr.sqr
        add ESP,4
        mov ECX,EAX
        pop EAX
        add EAX,ECX
        pop ECX
        ret

main:
L0:     push    EAX
        cmp dword ptr 8[ESP],2
        jne L1D
        mov EDX,0Ch[ESP]
        mov EAX,8[ESP]
        push    dword ptr 0Ch[EDX]
        push    dword ptr 8[EDX]
        call    near ptr to!(int)()
        jmp short   L22
L1D:        mov EAX,0Ah
L22:        call    near ptr double_sqr
        add EAX,EAX
        mov ECX,offset FLAT:_DATA
        push    EAX
        push    ECX
        call    near ptr printf

There's one call to double_sqr but unfortunately two to double_sqr.sqr.

Bye,
bearophile
April 21, 2009
bearophile wrote:
> I have also tested the semantics of nested function purity:
> 
> import std.c.stdio: printf;
> import std.conv: to;
> 
> pure int double_sqr(int x) {
>     pure int sqr(int y) { return y * y; }
>     return sqr(x) + sqr(x);
> }
> 
> void main(string[] args) {
>     int x = args.length == 2 ? to!(int)(args[1]) : 10;
>     int y = double_sqr(x) + double_sqr(x);
>     printf("4 * x * x = %d\n", y);
> }
> 
> Compiled without inlining:
> -O -release
> 
> double_sqr.sqr:
>         mov EAX,4[ESP]
>         imul    EAX,EAX
>         ret 4
> 
> double_sqr:
> L0:     push    EAX
>         push    EAX
>         xor EAX,EAX
>         call    near ptr double_sqr.sqr
>         push    EAX
>         sub ESP,4
>         xor EAX,EAX
>         push    dword ptr 8[ESP]
>         call    near ptr double_sqr.sqr
>         add ESP,4
>         mov ECX,EAX
>         pop EAX
>         add EAX,ECX
>         pop ECX
>         ret
> 
> main:
> L0:     push    EAX
>         cmp dword ptr 8[ESP],2
>         jne L1D
>         mov EDX,0Ch[ESP]
>         mov EAX,8[ESP]
>         push    dword ptr 0Ch[EDX]
>         push    dword ptr 8[EDX]
>         call    near ptr to!(int)()
>         jmp short   L22
> L1D:        mov EAX,0Ah
> L22:        call    near ptr double_sqr
>         add EAX,EAX
>         mov ECX,offset FLAT:_DATA
>         push    EAX
>         push    ECX
>         call    near ptr printf
> 
> There's one call to double_sqr but unfortunately two to double_sqr.sqr.
> 
> Bye,
> bearophile

Yes. Actually, marking a nested function as pure doesn't make much sense.
It's entirely equivalent to moving it outside the function; a nested pure function shouldn't be able to access any members of the enclosing function, otherwise it's not pure. But DMD doesn't enforce that, and so it creates inefficient and possibly buggy code.

I'm not sure that nested pure member functions should be legal.
April 21, 2009
bearophile wrote:
> I have tried the following code:
> 
> import std.c.stdio: printf;
> import std.conv: to;
> 
> nothrow pure int double_sqr(int x) { // line 4
>     int y, z;
>     nothrow void do_sqr() { y *= y; }
>     y = x;
>     do_sqr();
>     z += y;
>     y = x;
>     do_sqr();
>     z += y;
>     return z;
> }
> 
> void main(string[] args) {
>     int x = args.length == 2 ? to!(int)(args[1]) : 10;
>     int y = double_sqr(x) + double_sqr(x);
>     printf("4 * x * x = %d\n", y);
> }
> 
> The compiler spits the following error:
> 
> pure_impure_test.d(4): Error: function pure_impure_test.double_sqr 'double_sqr' is nothrow yet may throw
> 
> but I don't understand why. What are the things inside it that can throw an exception?
> 
> Bye,
> bearophile

Obviously my 2808 patch only solved one part of the problem.
It compiles if you change do_sqr to
void do_sqr() nothrow { y *= y; }
Please add a bug report to Bugzilla.
April 21, 2009
Don wrote:
> bearophile wrote:
>> I have also tested the semantics of nested function purity:
>>
>> import std.c.stdio: printf;
>> import std.conv: to;
>>
>> pure int double_sqr(int x) {
>>     pure int sqr(int y) { return y * y; }
>>     return sqr(x) + sqr(x);
>> }
>>
>> void main(string[] args) {
>>     int x = args.length == 2 ? to!(int)(args[1]) : 10;
>>     int y = double_sqr(x) + double_sqr(x);
>>     printf("4 * x * x = %d\n", y);
>> }
>>
>> Compiled without inlining:
>> -O -release
>>
>> double_sqr.sqr:
>>         mov EAX,4[ESP]
>>         imul    EAX,EAX
>>         ret 4
>>
>> double_sqr:
>> L0:     push    EAX
>>         push    EAX
>>         xor EAX,EAX
>>         call    near ptr double_sqr.sqr
>>         push    EAX
>>         sub ESP,4
>>         xor EAX,EAX
>>         push    dword ptr 8[ESP]
>>         call    near ptr double_sqr.sqr
>>         add ESP,4
>>         mov ECX,EAX
>>         pop EAX
>>         add EAX,ECX
>>         pop ECX
>>         ret
>>
>> main:
>> L0:     push    EAX
>>         cmp dword ptr 8[ESP],2
>>         jne L1D
>>         mov EDX,0Ch[ESP]
>>         mov EAX,8[ESP]
>>         push    dword ptr 0Ch[EDX]
>>         push    dword ptr 8[EDX]
>>         call    near ptr to!(int)()
>>         jmp short   L22
>> L1D:        mov EAX,0Ah
>> L22:        call    near ptr double_sqr
>>         add EAX,EAX
>>         mov ECX,offset FLAT:_DATA
>>         push    EAX
>>         push    ECX
>>         call    near ptr printf
>>
>> There's one call to double_sqr but unfortunately two to double_sqr.sqr.
>>
>> Bye,
>> bearophile
> 
> Yes. Actually, marking a nested function as pure doesn't make much sense.
> It's entirely equivalent to moving it outside the function; a nested pure function shouldn't be able to access any members of the enclosing function, otherwise it's not pure. But DMD doesn't enforce that, and so it creates inefficient and possibly buggy code.

The bug is bugzilla 2807.

> I'm not sure that nested pure member functions should be legal.

And it turns out that sqr() isn't actually pure, in the same way that it wasn't nothrow in your first example. The 'pure' marker is silently being ignored. If you put the 'pure' at the end, you get bug 2807.

--
April 21, 2009
Don:
> Yes. Actually, marking a nested function as pure doesn't make much sense.
> It's entirely equivalent to moving it outside the function; [...]
> I'm not sure that nested pure member functions should be legal.

It's not fully equivalent to moving it out of the function because once you pull it out you add a name to the outer namespace: nested functions are useful to keep namespaces tidy too.
So I'd like to have nested pure functions too.

pure int foo(int y) { return y + y; } // outer foo
pure void bar(int x) {
  pure int foo(int y) { return y * y; }
  return foo(x) * .foo(x);
}

Thank you,
bye,
bearophile
April 21, 2009
Lutger wrote:
> what the hell...this code can't be human.

I was replaced by Colossus years ago.
April 21, 2009
bearophile wrote:
> Don:
>> Yes. Actually, marking a nested function as pure doesn't make much sense.
>> It's entirely equivalent to moving it outside the function; [...]
>> I'm not sure that nested pure member functions should be legal.
> 
> It's not fully equivalent to moving it out of the function because once you pull it out you add a name to the outer namespace: nested functions are useful to keep namespaces tidy too.
> So I'd like to have nested pure functions too.
> 
> pure int foo(int y) { return y + y; } // outer foo
> pure void bar(int x) {
>   pure int foo(int y) { return y * y; }
>   return foo(x) * .foo(x);
> }
> 
> Thank you,
> bye,
> bearophile

That's true, but it seems quite difficult to get right. A pure nested function can in theory access immutable members in the outer function -- but must not access the parameters of the outer function.
If there are no immutable members in the outer function, the compiler would ideally convert it into an external pure function, so that it
doesn't need a frame pointer to the outer function. But it would need error messages for any use of mutable outer function members. Etc.
It seems quite a lot of work for something of very limited use.
Making it into a external, private pure function is almost the same.


April 21, 2009
Walter Bright wrote:
> Stewart Gordon wrote:
>> Walter, how often do you update your working copy from the SVN? Obviously less than once every 2 releases.
> 
> As far as I know, it is current. Everything got checked in.

So how has the fix for
http://d.puremagic.com/issues/show_bug.cgi?id=2580
(and probably others) not been included?

Stewart.
April 21, 2009
Walter Bright wrote:
> Lutger wrote:
>> what the hell...this code can't be human.
> 
> I was replaced by Colossus years ago.

Michael A. Jackson wouldn't approve 1175 gotos in 113 files.