February 26, 2003
"Walter" <walter@digitalmars.com> wrote in news:b3fdlo$kp1$1 @digitaldaemon.com:

> Some long overdue features.
> 
> www.digitalmars.com/d/changelog.html
> 
> 
> 
e:\Programming\tools\dmd\bin\..\..\dm\bin\link.exe err,,,user32
+kernel32/noi;
OPTLINK (R) for Win32  Release 7.50B1
Copyright (C) Digital Mars 1989 - 2001  All Rights Reserved

err.obj(err)
 Error 42: Symbol Undefined __init_TypeInfo_Ag
--- errorlevel 1

int main(char[][] argv)
{
  int[byte[]] foo;

  static byte[] bar = [ 65, 66, 67 ];

  foo[bar] = 1;

  return 0;
}
February 26, 2003
"Walter" <walter@digitalmars.com> writes:

> I knew there was a difference, but I didn't know the right terminology. Now that I know it, I'll update the documentation. Semantic closure, at least in a C-style language, just does not feel intuitive to me. The vault style closures, especially the example they give on what values the captured variables have, to me just seems mighty peculiar. Implementing them is also

However, it would seem that lexical closures can be a source of annoying bugs, since they contain implicit pointers to the stack frame.  So beware of introducing them to beginners before they know and understand what the stack is ;)

They're a useful feature, anyhow.

Probably some kind of semantic closures could be feasible, even in a language that allows allocating local variables on the stack:

- creating a semantic closure would require allocating space for and making a copy of each reference to each heap-allocated object that is used inside the closure

- however, stack-allocated objects could not be referred to, since they will be lost when the stack frame goes away -> yet another difference between integral/struct and class objects, or more appropriately, stack-allocated/heap-allocated objects

-Antti
February 26, 2003
Actually, if you'll tolerate overly imaginative ideas...

One solution would be to make semantic closures the default.

This would mean, naturally, that part of the local variables would have to be heap-allocated.

void delegate() f()
{
        int x;  //  <------ allocated from the heap, since it's needed
                //          in the closure

        Object y; // <----- allocated from the heap anyway

        int z; //   <------ stack-allocated because not referred by closures
        x = 5; y = new Whatever(6); z = 7;

        void foo() {
              print(x);
              print(y);
        }

        return foo;
}

Now, before someone yells, "that's inefficient", consider this:

If the compiler could prove (or the programmer could assert) that f's lifetime will be longer than foo's, then it could implement above as lexical closure and stack-allocate everything.  But this would be an optimization, not the default method.

This would mean, though, that the semantics of

     X x, X y;

     x = y;

would *have* be the same whether x is heap-allocated and stack-allocated.  Possibly needs to have different "value-assignment" and "reference-assignment" operators, or something similar. (Oops, starting to sound like Eiffel?) I'm not sure how this would be achieved.

Anyway, lexical closures by default are unsafe. I'm not someone to
decide it's best to make the unsafe but efficient feature the default
(like the C/C++-programming world feels), or if it's better to stay on
the safe side by default and implement stack allocation etc. as an
optimization (like the functional programming world seems to
feel). It's up to the language designed.  But having both optionally
would be nice.

-Antti

Antti Sykari <jsykari@gamma.hut.fi> writes:
> "Walter" <walter@digitalmars.com> writes:
>
>> I knew there was a difference, but I didn't know the right terminology. Now that I know it, I'll update the documentation. Semantic closure, at least in a C-style language, just does not feel intuitive to me. The vault style closures, especially the example they give on what values the captured variables have, to me just seems mighty peculiar. Implementing them is also
>
> However, it would seem that lexical closures can be a source of annoying bugs, since they contain implicit pointers to the stack frame.  So beware of introducing them to beginners before they know and understand what the stack is ;)
>
> They're a useful feature, anyhow.
>
> Probably some kind of semantic closures could be feasible, even in a language that allows allocating local variables on the stack:
>
> - creating a semantic closure would require allocating space for and making a copy of each reference to each heap-allocated object that is used inside the closure
>
> - however, stack-allocated objects could not be referred to, since they will be lost when the stack frame goes away -> yet another difference between integral/struct and class objects, or more appropriately, stack-allocated/heap-allocated objects
>
> -Antti
February 26, 2003
Again to clarify my earlier mistatement:

 What D implements is called a "dynamic closure", and the Lisp/Scheme
closure which does capture locals on the heap is actually the "lexical
closure".

 Those names make more sense anyway.  Its called lexical because it
preserves the lexical scope, or the scope as the source code would indicate,
regardless of execution context.

Dan


"Antti Sykari" <jsykari@gamma.hut.fi> wrote in message news:87lm03ldoy.fsf@hoastest1-8c.hoasnet.inet.fi...
> Actually, if you'll tolerate overly imaginative ideas...
>
> One solution would be to make semantic closures the default.
>
[...]


February 26, 2003
"Dan Liebgold" <dliebgold@yahoo.com> writes:

> Again to clarify my earlier mistatement:
>
>  What D implements is called a "dynamic closure", and the Lisp/Scheme
> closure which does capture locals on the heap is actually the "lexical
> closure".
>
>  Those names make more sense anyway.  Its called lexical because it
> preserves the lexical scope, or the scope as the source code would indicate,
> regardless of execution context.

There seems to be quite a bit of confusion around this matter, and I fell to the trap myself.  Probably everything I said seems unintelligible because of the vocabulary. :)

I don't think closures cannot be called dynamic or lexical.

The distiction is between dynamic scoping and lexical scoping.  In dynamic scoping, a variable refers to its last binding.  In lexical scoping, the variable refers the binding which is nearest to it lexically.

Lisp dialects used dynamic scoping and changed to lexical scoping
(with the exception of elisp).

http://www.gnu.org/manual/elisp-manual-21-2.8/html_node/elisp_147.html

Closures (as used in Common Lisp, Scheme, and other functional languages, and languages like Perl, I think) capture the environment which contains the variables referred to.

You need closures to implement lexical scoping.
You don't need closured to implement dynamic scoping.
(For example,
http://www.gnu.org/manual/elisp-manual-21-2.8/html_node/elisp_150.html#SEC150
)

D's closures/delegates look like they don't actually capture the variables (in the sense that they remain in existence after the block in which they have been declared in has exit) but merely refer to them.

-Antti

> Dan
>
>
> "Antti Sykari" <jsykari@gamma.hut.fi> wrote in message news:87lm03ldoy.fsf@hoastest1-8c.hoasnet.inet.fi...
>> Actually, if you'll tolerate overly imaginative ideas...
>>
>> One solution would be to make semantic closures the default.
>>
> [...]
February 26, 2003

Walter wrote:
> "Jeroen van Bemmel" <anonymous@somewhere.com> wrote in message
> news:b3grne$1hat$1@digitaldaemon.com...
> 
>>OK, I'm gonna play the devil's advocate some more now, hope you'll excuse
> 
> me
> 
>>for that, but...why is it useful to be able to declare nested functions?
> 
> 
> Speak of the devil <g> I just wrote this example:
> 
> www.digitalmars.com/d/pretod.html#codefactoring
> 
> The C version is done with macros, but if you want, try it with C++ inline
> functions.

Why does function nesting impact automatic in-lining?  Is a nested function more likely to be in-lined?

Bill

February 26, 2003
"Antti Sykari" <jsykari@gamma.hut.fi> wrote in message news:878yw3e5h3.fsf@hoastest1-8c.hoasnet.inet.fi...
> D's closures/delegates look like they don't actually capture the variables (in the sense that they remain in existence after the block in which they have been declared in has exit) but merely refer to them.

That's correct.


February 26, 2003
"Bill Cox" <bill@viasic.com> wrote in message news:3E5CEABE.30501@viasic.com...
> Walter wrote:
> > Speak of the devil <g> I just wrote this example:
> >
> > www.digitalmars.com/d/pretod.html#codefactoring
> >
> > The C version is done with macros, but if you want, try it with C++
inline
> > functions.
> Why does function nesting impact automatic in-lining?  Is a nested function more likely to be in-lined?

A D nested function is equally likely to be inlined as a non-nested one.


February 26, 2003
> See the next example
> www.digitalmars.com/d/ctod.html#traversal which is a (again, greatly
> simplified) piece of code from my own work.

.. and then there's for example a (not "the") Java way:

static void findMember( Map[] symtables, String id ) {
   for (int s=0; s<symtables.length; ++s) {
      Symbol s = (Symbol) symtables[s].get(id);
      if (s!=null) {
        // do whatever you want here
      }
   }
}

No need for any inline functions or nested functions or whatever other functions :)

I'm sorry, but the days for programming recursive pointer traversal algorithms have long been over for Java programmers. I'm using Java as an example here, I'm sure there are other languages that can do the same. Regardless of whether you like Java or not, if possible it would be nice to have examples that compare D features with state-of-the-art options in other languages. The fact that they occur in production code doesn't automatically mean they are a good (I won't say 'the right', there are always trade-offs ) approach

As an objective person looking at D, I would be looking for features that help me solve problems that are not addressed adequately by what I am using today. Less lines of code, better maintainable code, better runtime support, "if you do it like this you automagically get <nifty feature>", all of these can be reasons. Until now the examples provided have not been convincing to me.



February 26, 2003
In article <878yw3e5h3.fsf@hoastest1-8c.hoasnet.inet.fi>, Antti Sykari says...
>
>The distiction is between dynamic scoping and lexical scoping.  In dynamic scoping, a variable refers to its last binding.  In lexical scoping, the variable refers the binding which is nearest to it lexically.
>
>Lisp dialects used dynamic scoping and changed to lexical scoping
>(with the exception of elisp).
>

Good, I'm not totally botching these descriptions ;)


>You need closures to implement lexical scoping.
>You don't need closured to implement dynamic scoping.

True true.  Dynamic scoping is what exists in C/C++/C#/Java, and is what most programmers *expect*, and is straightfoward to implement.

>
>D's closures/delegates look like they don't actually capture the variables (in the sense that they remain in existence after the block in which they have been declared in has exit) but merely refer to them.
>

Yes, D has dynamic scoping.  Lexical scoping opens up possibilities for different (often more powerful) styles of programming, but like a few of the other features of Lisp and its ilk, it is rarely implemented in an optimal way. So while it has a theoretic performance that is in the league of the C/C++ paradigm but you will rarely encounter it in the field.

D, it seems, is designed for practical performance to be of higher priority that theoretically powerful constructs that complicate implementation, like lexical scoping.    BTW, I believe that is the ultimate downfall of first class functions.



Dan