www.digitalmars.com         C & C++   DMDScript  

D - DMD 0.57 release

reply "Walter" <walter digitalmars.com> writes:
Some long overdue features.

www.digitalmars.com/d/changelog.html
Feb 25 2003
next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Walter wrote:

 Some long overdue features.

 www.digitalmars.com/d/changelog.html
Non C-style function pointer declaration? Function literals? Nested functions? Closures??? YAAAAAAAAAAAAAAAAAAAAAAAAAY!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Feb 25 2003
parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
I second that,
anon delegates do replace inner classes in most places (but I still like
them).
before I run into problems I just want to check something

in your example of a nested function uses as a delegate
A delegate can be set to a non-static nested function:
	int delegate() dg;

	void test()
	{   int a = 7;
	    int foo() { return a + 3; }

	    dg = foo;
	    int i = dg();	// i is set to 10
	}
I assume at the time dg = foo is executed foo is closed so changes to a do
not effect the return value of foo
also is the following valid
	int delegate() dg;

	dg test( int param )
	{
            int a = param+1;
            int foo() { return a + 3; }

	    return foo;
	}

or will foo try to reference a value on the stack which will not exist when
test returns
or even worse
	int delegate() dg;

	dg test( int param )
	{            int a = param+1;            int foo() { return a = a + 3; }

	    return foo;
	}

fyi: Java does have closures of a sort
MyInferface foo( int param ) {
    final int a = param + 1; // is realy int[]a = new int [1]; a[0] =
param+1;
    return new MyInterface() { int func() { return a = a + 3; }
// class this$0 implements MyInterface { final int[] _a; this$0(int[] a0)
{ _a = a0; }
// public int func() { return _a[0] = _a[0] + 3; }
// }
// return new this$0( a );
}



"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3E5B8A00.5E699634 deming-os.org...
 Walter wrote:

 Some long overdue features.

 www.digitalmars.com/d/changelog.html
Non C-style function pointer declaration? Function literals? Nested functions? Closures??? YAAAAAAAAAAAAAAAAAAAAAAAAAY!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Feb 25 2003
parent "Walter" <walter digitalmars.com> writes:
"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:b3gj28$1bii$1 digitaldaemon.com...
 in your example of a nested function uses as a delegate
 A delegate can be set to a non-static nested function:
 int delegate() dg;

 void test()
 {   int a = 7;
     int foo() { return a + 3; }

     dg = foo;
     int i = dg(); // i is set to 10
 }
 I assume at the time dg = foo is executed foo is closed so changes to a do
 not effect the return value of foo
No. Both foo() and bar() are referring to the same instance of 'a', so either can read/write to it and affect the other. It works exactly as if foo() was passed &a, and the body of foo() was accessing it through that pointer.
 also is the following valid
 int delegate() dg;

 dg test( int param )
 {
             int a = param+1;
             int foo() { return a + 3; }

     return foo;
 }

 or will foo try to reference a value on the stack which will not exist
when
 test returns
That is invalid code. The reference to 'a' is invalid after test() returns. If you think about it as being implemented with pointers to 'a', the semantics will become clear.
 or even worse
 int delegate() dg;

 dg test( int param )
 {            int a = param+1;            int foo() { return a = a + 3; }

     return foo;
 }
That's invalid too for the same reason. As Dan pointed out, D implements lexical closures, not semantic closures.
 fyi: Java does have closures of a sort
 MyInferface foo( int param ) {
     final int a = param + 1; // is realy int[]a = new int [1]; a[0] =
 param+1;
     return new MyInterface() { int func() { return a = a + 3; }
 // class this$0 implements MyInterface { final int[] _a; this$0(int[] a0)
 { _a = a0; }
 // public int func() { return _a[0] = _a[0] + 3; }
 // }
 // return new this$0( a );
 }
I'm not sure if those could be considered closures or not.
Feb 25 2003
prev sibling next sibling parent Patrick Down <pat codemoon.com> writes:
"Walter" <walter digitalmars.com> wrote in news:b3fdlo$kp1$1
 digitaldaemon.com:

 Some long overdue features.
 
 www.digitalmars.com/d/changelog.html
 
Walter, you are the man!
Feb 25 2003
prev sibling next sibling parent reply Jonathan Andrew <Jonathan_member pathlink.com> writes:
In article <b3fdlo$kp1$1 digitaldaemon.com>, Walter says...
Some long overdue features.

www.digitalmars.com/d/changelog.html
Cool! Quick question: In the delegates section under types, a function pointer is shown as: int function(int) fp; //function pointer int func(int); fp = &func; //now points to func whereas, in the functions section under closures, the assignment is shown as: fp = foo; Is one of these incorrect? If so, just for the record I like not needing the address-of operator. Thanks, -Jon
Feb 25 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Jonathan Andrew" <Jonathan_member pathlink.com> wrote in message
news:b3g944$14k4$1 digitaldaemon.com...
 Quick question: In the delegates section under types, a function pointer
is
 shown as:

 int function(int) fp;     //function pointer
 int func(int);

 fp = &func;               //now points to func

 whereas, in the functions section under closures, the assignment is shown
 as:

 fp = foo;

 Is one of these incorrect? If so, just for the record I like not needing
the
 address-of operator.
In earlier versions, the & was required. In 0.57, either will work. I'm thinking of obsoleting the & version.
Feb 25 2003
parent reply Burton Radons <loth users.sourceforge.net> writes:
Walter wrote:
 "Jonathan Andrew" <Jonathan_member pathlink.com> wrote in message
 news:b3g944$14k4$1 digitaldaemon.com...
 
Quick question: In the delegates section under types, a function pointer
is
shown as:

int function(int) fp;     //function pointer
int func(int);

fp = &func;               //now points to func

whereas, in the functions section under closures, the assignment is shown
as:

fp = foo;

Is one of these incorrect? If so, just for the record I like not needing
the
address-of operator.
In earlier versions, the & was required. In 0.57, either will work. I'm thinking of obsoleting the & version.
Removing that would make properties impossible.
Feb 25 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Burton Radons" <loth users.sourceforge.net> wrote in message
news:b3gis9$1bf0$1 digitaldaemon.com...
 In earlier versions, the & was required. In 0.57, either will work. I'm
 thinking of obsoleting the & version.
Removing that would make properties impossible.
Please elaborate.
Feb 25 2003
parent reply Burton Radons <loth users.sourceforge.net> writes:
Walter wrote:
 "Burton Radons" <loth users.sourceforge.net> wrote in message
 news:b3gis9$1bf0$1 digitaldaemon.com...
 
In earlier versions, the & was required. In 0.57, either will work. I'm
thinking of obsoleting the & version.
Removing that would make properties impossible.
Please elaborate.
You wouldn't be able to differentiate between a property access and a function pointer access. For example: class Class { void *method () { } } Class object = new Class; void *pointer = object.method; Am I getting the pointer to the method or the pointer from the method? This decision could be deferred to the semantic phase, but that's pretty late to be making such an important decision on what code is representing.
Feb 26 2003
parent "Walter" <walter digitalmars.com> writes:
"Burton Radons" <loth users.sourceforge.net> wrote in message
news:3E5D5FAD.80605 users.sourceforge.net...
 You wouldn't be able to differentiate between a property access and a
 function pointer access.  For example:

     class Class
     {
         void *method () { }
     }

     Class object = new Class;
     void *pointer = object.method;

 Am I getting the pointer to the method or the pointer from the method?
 This decision could be deferred to the semantic phase, but that's pretty
 late to be making such an important decision on what code is representing.
Ah, I see what you mean.
Feb 26 2003
prev sibling next sibling parent reply Burton Radons <loth users.sourceforge.net> writes:
Excellent all around.  You needn't thank me for berating you.  :-)

Here's a couple problems:

    void delegate () delegate (int x) store;

    void delegate () zoom (int x)
    {
       return delegate void () { };
    }

    void main ()
    {
       store = &zoom;
    }

Which is to say that I'm attempting to assign an incorrect type to 
"store"; I get:

    Assertion failure: '!ident' on line 1854 in file 'mtype.c'

Also:

    void delegate () delegate (int x) store;

    void delegate () zoom (int x)
    {
       return delegate void () { };
    }

    void main ()
    {
       store = &zoom;
       store () ();
    }

Where I'm not passing an argument to the delegate in main, I get "Error: 
expected 1 arguments to constructor, not 0"; calling "zoom" directly 
with the same error results in the proper "function zoom (int x) does 
not match argument types ()".

Finally:

    void main ()
    {
        { const int [] list = [ 1, 2 ]; }
        { const int [] list = [ 3, 4 ]; }
    }

Each "list" is in its own scope, but it fails with a "Previous 
Definition Different" error in linking.  While I'm dealing with scopes:

    void main ()
    {
       while (1)
       {
          int x;
       }

       while (1)
       {
          int x;
       }
    }

Fails with "declaration main.x is already defined"; this is long 
standing.  Finally:

    void main ()
    {
       int x;

       for (int x; ; )
       {
       }
    }

Compiles, even though the "for" loop covers the previous variable; this 
is also long standing.
Feb 25 2003
parent "Walter" <walter digitalmars.com> writes:
"Burton Radons" <loth users.sourceforge.net> wrote in message
news:b3gavs$15ol$1 digitaldaemon.com...
 Excellent all around.  You needn't thank me for berating you.  :-)
Your idea of using the frame pointer as the hidden this pointer was pretty cool.
Feb 25 2003
prev sibling next sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
Kudos and many thanks for the new function/delegate types!

Some notes:

Especially for marketing purposes, you may want to refer to D's closures as
"lexical closures", as most closures I've seen implented currently are "semantic
closures" -- or "real" closures if you listen to the academics.  This is an old
dead battle in the Lisp community.

Essentially, semantic closures are those that are described in the Vault
language description (there are a few links in previous posts). Lisp and Scheme
also implement them.  They are "full" closures in that when a function is
defined it fully captures its enclosing scope, such that even variables on the
stack are retained for later reference.

The lexical closures are the more implementationally sane version, which only
captures the scope that exists anyway at the moment the function is called
later. So in the documentation's example:

int delegate () dg;

void test()
{   int a = 7;
int foo() { return a + 3; }

dg = foo;
}

void bar()
{   test();
int i = dg();	// error, test.a no longer exists
return;
}

In semantic closure, there would be no error. The definition of "foo" would
invisibily capture the scope of "test()" in a garbage collected block, so that
when it is called later through the dg delegate, "a" exists and is still valid.


Semantic closures can play havoc with memory and performance. The scope
retention happens invisibly, and can keep otherwise gc-able memory tied up.  The
implementation is also complex.  I believe these are reasons you don't see them

usage is atrocious (even the mature commercial environments) and its garbage
collection is often a joke.

Dan

p.s. I don't want to start a Lisp flame war, so I take it all back if you're
offended!  Also, I use Lisp (again, a commercial version) daily so I'm not
(necessarily) speaking from ignorance....


In article <b3fdlo$kp1$1 digitaldaemon.com>, Walter says...
Some long overdue features.

www.digitalmars.com/d/changelog.html
Feb 25 2003
next sibling parent reply "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
obviously far more complex and expensive, and doesn't look worthwhile for
something that is just confusing anyway.

The lexical closure implementation turns out to be reasonably simple, easy
to understand, and efficiently implementable.

Thanks,
-Walter
Feb 25 2003
parent reply 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
Feb 25 2003
parent reply Antti Sykari <jsykari gamma.hut.fi> writes:
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
Feb 25 2003
parent reply "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.

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.
[...]
Feb 26 2003
parent reply Antti Sykari <jsykari gamma.hut.fi> writes:
"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.
[...]
Feb 26 2003
next sibling parent "Walter" <walter digitalmars.com> writes:
"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.
Feb 26 2003
prev sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
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.
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
Feb 26 2003
parent "Walter" <walter digitalmars.com> writes:
"Dan Liebgold" <Dan_member pathlink.com> wrote in message
news:b3j9p5$39b$1 digitaldaemon.com...
 D, it seems, is designed for practical performance to be of higher
priority that
 theoretically powerful constructs that complicate implementation, like
lexical
 scoping.
Correct. Also, D tries to avoid features that are overly complex to implement.
 BTW, I believe that is the ultimate downfall of first class
 functions.
Implementing lexical closure would kill off the uses of nested functions in the examples I used, because the performance would be unacceptable.
Feb 26 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Dan Liebgold" <Dan_member pathlink.com> wrote in message
news:b3ghmn$1al3$1 digitaldaemon.com...
 p.s. I don't want to start a Lisp flame war, so I take it all back if
you're
 offended!
Not at all! I'm in the wrong business if I'm easilly offended!
 Also, I use Lisp (again, a commercial version) daily so I'm not
 (necessarily) speaking from ignorance....
And that makes your comments on it especially worth reading. My knowledge of Lisp is minimal, and I've written little more in it than a few emacs functions.
Feb 25 2003
prev sibling next sibling parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
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?

The reason for having general functions / procedures is to have the ability
to break up a problem into smaller subproblems, and then solving each
subproblem which is easier to do. You continue to do so until you arrive at
problems that can be solved by single statements or machine instructions.
Basic divide-and-conquer

Nested functions are normal functions with additional scoping restrictions.
Do they allow you to better match the structure of a problem? Could it be a
matter of taste perhaps? I don't see a real use case, and since I am sort of
a minimalist I would leave them out unless there is a good reason to put
them in. Yes, I believe you can implement them, even efficiently. But being
able to jump off a cliff doesn't mean that you have to...
Feb 25 2003
parent reply "Walter" <walter digitalmars.com> writes:
"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.
Feb 25 2003
next sibling parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
That's fast....

I can see your point when comparing it to old-style C macro's, no argument
there. However, in the "OO world" ( many discussions on OO vs functional
aside ) you would probably introduce 'stack' as an abstract data type (it
might already be in your runtime libary under, say, lang.util...) and
encapsulate all those little functions there. Agreed, it's a matter of
taste/hype/era, a different cross section of the problem domain. But still,
thinking also in terms of reuse, if you end up with a couple of those inline
functions you'll probably find yourself declaring them time and time again
( the push() and pop() in your example are most likely not the only place in
the program where they are used, JVMs tend to push and pop a lot) until you
finally decide to factor them out to only have to declare them once...

So, resuming, nested functions are one way of factoring, there are others
Feb 25 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3guds$1ja3$1 digitaldaemon.com...
 I can see your point when comparing it to old-style C macro's, no argument
 there. However, in the "OO world" ( many discussions on OO vs functional
 aside ) you would probably introduce 'stack' as an abstract data type (it
 might already be in your runtime libary under, say, lang.util...) and
 encapsulate all those little functions there. Agreed, it's a matter of
 taste/hype/era, a different cross section of the problem domain.
Also, nested functions aren't really an OO concept. But the example I used is a (greatly simplified) example of production quality code I've encountered more than once. The nested function route has the great advantage of resulting in code that is every bit as efficient as the C macro technique - there's no compromise.
 But still,
 thinking also in terms of reuse, if you end up with a couple of those
inline
 functions you'll probably find yourself declaring them time and time again
 ( the push() and pop() in your example are most likely not the only place
in
 the program where they are used, JVMs tend to push and pop a lot) until
you
 finally decide to factor them out to only have to declare them once...
Inline functions suffer from the same problem of lack of access to local variables in the enclosing scope - you need to create a context struct and pass that as a pointer. See the next example www.digitalmars.com/d/ctod.html#traversal which is a (again, greatly simplified) piece of code from my own work.
 So, resuming, nested functions are one way of factoring, there are others
Sure. But nested functions are a simple and direct way of doing it without using pointers or creating extra wrapper object types just to encapsulate/transmit them.
Feb 25 2003
parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
 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.
Feb 26 2003
next sibling parent "Walter" <walter digitalmars.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3j9no$38n$1 digitaldaemon.com...
 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.
No, it's just been hidden away inside the implementation of the get(id) function, and *that* code will need some sort of context pointer. Consider also the case of applying an arbitrary function to each member of the table (see the example in www.digitalmars.com/d/cpptod.html).
 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.
Ok, how in Java do you apply an arbitrary piece of code to all the elements in some generic container?
Feb 26 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3j9no$38n$1 digitaldaemon.com...
 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.
Here's another one. Suppose we have in our generic library a function to perform numerical integration: ------------------------------------------ // Integrate f(x) from x1..x2 by dx real integrate(real delegate(real x) f, real x1, real x2, real dx) { real sum = 0.0; for (real x = x1; x < x2; x += dx) { real y1, y2; y1 = f(x); y2 = f(x + dx); sum += (y1 + y2) * dx / 2.0; } return sum; } --------------------------------------------- Then, in our application code, we want to integrate from 0..x a polynomial of the form: f(x) = a + b*x + c*x**2 + ... Here's a function to do it with coeff[] representing the a, b, c coefficients: ----------------------------------------------- real integrate_polynomial(real coeff[], real x) { real f(real x) { real y = 0.0; real xp = 1.0; for (int i = 0; i < coeff.length; i++) { y += coeff[i] * xp; xp *= x; } return y; } return integrate(f, 0, x, .01); } ---------------------------------------- Notice how the function f(x) can be written to arbitrarilly reference other data in a typesafe manner, without any need to modify the generic library routine. numerical improvements, which isn't the point here.)
Feb 26 2003
parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
 -----------------------------------------------

 real integrate_polynomial(real coeff[], real x)
 {
     real f(real x)
     {
         real y = 0.0;
         real xp = 1.0;

         for (int i = 0; i < coeff.length; i++)
         {
             y += coeff[i] * xp;
             xp *= x;
         }
         return y;
     }

     return integrate(f, 0, x, .01);
 }
 ----------------------------------------
 Notice how the function f(x) can be written to arbitrarilly reference
other
 data in a typesafe manner, without any need to modify the generic library
 routine.

(Overlooking
 numerical improvements, which isn't the point here.)
I won't say it's better, but in Java you can do more or less the same: real integrate_polynomial( final real coeff[], real x) { Fuction f = new Function() { public int evaluate( real x ) { real y = 0.0; real xp = 1.0; for (int i = 0; i < coeff.length; i++) { y += coeff[i] * xp; xp *= x; } return y; } }; return integrate(f, 0, x, .01); } Note the 'final' to make coeff accessible. Alternatively, I could pass it as an argument to the constructor of f, but then I would need to define it as a datamember too. That is, you create a function object implementing some 'Function' interface which has an 'evaluate' method. One possible advantage here is that the D program you wrote only supports single argument functions f(x). If I wanted to also have f(x,y), I could add this to the interface, whereas in D it would have to be a different delegate (-parameter). In this sense I think interfaces (and anonymous implementations as shown above) are more generic that function pointers / delegates
Feb 27 2003
parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
BTW, now that I'm thinking about this: One of the worse features of Java IMO
is the rediculous amount of resources (memory) it uses for simple things.
The garbage collector is good, but it allocates so many small objects (the
example I gave allocates one for the function object).

The advantage is though that I can return this object from my function, and
use it elsewhere. What happens if I return a reference to a nested function
delegate in D? Is it still valid, is there also some memory allocated
underneath? You would expect it to go out of scope, so the compiler should
issue a warning "returning reference to local function" or something
Feb 27 2003
next sibling parent reply "Dan Liebgold" <dliebgold yahoo.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3kh99$qoj$1 digitaldaemon.com...
 The advantage is though that I can return this object from my function,
and
 use it elsewhere. What happens if I return a reference to a nested
function
 delegate in D? Is it still valid, is there also some memory allocated
 underneath? You would expect it to go out of scope, so the compiler should
 issue a warning "returning reference to local function" or something
That's the rub. The nested function has static scope, so it will always be accesible and callable. It's enclosing environment is the problem. Local variables on the stack in its enclosing environment will become invalid when the surrounding function exits, so it's caller beware. An example where the D version will get you (by letting you introduce a subtle runtime bug) is this (shamelessly stolen from the Vault page): void startLogging (string logFilename) { file_handle logfile = openFile(logFilename, "a"); void handleInterrupt (int interrupt) { writeMessage(interrupt, logfile); } registerInterruptHandler(12, handleInterrupt); } When "handleInterrupt" is called later, "startLogging" will have exited, and "logfile" will have fallen out of scope. It is a local stack variable, so it will point to what is likely to be invalid memory. Cue access violation or worse. Dan
Feb 27 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Dan Liebgold" <dliebgold yahoo.com> wrote in message
news:b3kj07$rnc$1 digitaldaemon.com...
 That's the rub.  The nested function has static scope, so it will always
be
 accesible and callable. It's enclosing environment is the problem. Local
 variables on the stack in its enclosing environment will become invalid
when
 the surrounding function exits, so it's caller beware.

 An example where the D version will get you (by letting you introduce a
 subtle runtime bug) is this (shamelessly stolen from the Vault page):

 void startLogging (string logFilename) {
   file_handle logfile = openFile(logFilename, "a");
   void handleInterrupt (int interrupt) {
     writeMessage(interrupt, logfile);
   }
   registerInterruptHandler(12, handleInterrupt);
 }

 When "handleInterrupt" is called later, "startLogging" will have exited,
and
 "logfile" will have fallen out of scope. It is a local stack variable, so
it
 will point to what is likely to be invalid memory. Cue access violation or
 worse.
Yup, you're right, that will fail in D. The way to make it work is to make handleInterrupt a member of a class: void startLogging(string logFilename) { class Foo { file_handle logfile; void handleInterrupt(int interrupt) { writeMessage(interrupt, logfile); } } Foo f = new Foo; f.logfile = openFile(logFilename, "a"); registerInterruptHandler(12, f.handleInterrupt); } It's a little more work, but not so bad.
Feb 27 2003
next sibling parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
 It's a little more work, but not so bad.
The point is not that you wouldn't be able to make it work, the point is that you create a bug that is hard to find. This kind of use of nested functions should be detected and refused. It should be illegal to store a reference to a nested local function. In fact, the type of a nested function should not be 'delegate' but "non_copyable_delegate' - can you make this ?
Feb 27 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3ligi$1gno$1 digitaldaemon.com...
 The point is not that you wouldn't be able to make it work, the point is
 that you create a bug that is hard to find. This kind of use of nested
 functions should be detected and refused. It should be illegal to store a
 reference to a nested local function. In fact, the type of a nested
function
 should not be 'delegate' but "non_copyable_delegate' - can you make this ?
I agree that as much as possible the compiler should detect and reject such usage as illegal. But it cannot do it 100%. Another possibility would be to add a runtime check.
Feb 27 2003
parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
What information would the compiler need to have in order to be able to
detect such usage 100%?

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b3lnk1$1jv2$1 digitaldaemon.com...
 "Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
 news:b3ligi$1gno$1 digitaldaemon.com...
 The point is not that you wouldn't be able to make it work, the point is
 that you create a bug that is hard to find. This kind of use of nested
 functions should be detected and refused. It should be illegal to store
a
 reference to a nested local function. In fact, the type of a nested
function
 should not be 'delegate' but "non_copyable_delegate' - can you make this
?
 I agree that as much as possible the compiler should detect and reject
such
 usage as illegal. But it cannot do it 100%. Another possibility would be
to
 add a runtime check.
Mar 01 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
news:b3r11a$2aq1$1 digitaldaemon.com...
 What information would the compiler need to have in order to be able to
 detect such usage 100%?
It would have to know that any function you passed the delegate to would not store it in some global data structure. I think that's not possible. But, I think a runtime check can be done.
Mar 01 2003
parent "Jeroen van Bemmel" <anonymous somewhere.com> writes:
 It would have to know that any function you passed the delegate to would
not
 store it in some global data structure. I think that's not possible.
No, but I believe it could be implemented as a compile-time check the way I indicated before: no function is allowed to store a delegate (assign it to a member variable / static variable, local variables could be allowed) unless it declares so as a flag to the delegate parameter. So class X { void delegate(int) memberDelegate; void f( void delegate( int ) ptr ) { memberDelegate = ptr; // <= Compiler error: "Cannot store a reference to a delegate parameter that is not declared 'global'" } } if the programmer needs f to store the delegate anyway, he would have then to e.g. change it to: "void f( void delegate( int ) global ptr )" Passing a nested function as delegate to such a function would then generate another compiler error: "Cannot pass local delegate as global delegate parameter" or something
Mar 01 2003
prev sibling parent Burton Radons <loth users.sourceforge.net> writes:
Sean L. Palmer wrote:
 What information would the compiler need to have in order to be able to
 detect such usage 100%?
It would need to allocate an object at the start of the function that contains the frame pointer - this is what's now passed as the nested function's parent frame pointer. When the function exits, it sets the pointer's contents to null; nested functions that are called check that the pointer is currently non-null before continuing. Then it unpacks the value and continues. The compiler will have to check that a delegate does use the parent frame pointer before making this check.
Mar 01 2003
prev sibling next sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
In article <b3ko0o$ueh$1 digitaldaemon.com>, Walter says...
Yup, you're right, that will fail in D. The way to make it work is to make
handleInterrupt a member of a class:

void startLogging(string logFilename)
{
    class Foo
    {    file_handle logfile;
         void handleInterrupt(int interrupt) { writeMessage(interrupt,
logfile); }
    }
    Foo f = new Foo;
    f.logfile = openFile(logFilename, "a");
    registerInterruptHandler(12, f.handleInterrupt);
}

It's a little more work, but not so bad.
Ah.. clever approach, certainly. Do-it-yourself lexical closures, similar to the Java approach. I'm afraid I agree with Jeroen on this point though, it is very easy to introduce that subtle bug of referencing de-scoped locals. Also, in the above example, won't f get garbage collected soon? Does the collector need to track references to f's members for this construct to work? (Does it anyway? I'm not familiar with the techniques it uses...) Dan
Feb 27 2003
next sibling parent Patrick Down <Patrick_member pathlink.com> writes:
In article <b3lri6$1m8f$1 digitaldaemon.com>, Dan Liebgold says...
In article <b3ko0o$ueh$1 digitaldaemon.com>, Walter says...
Yup, you're right, that will fail in D. The way to make it work is to make
handleInterrupt a member of a class:

void startLogging(string logFilename)
{
    class Foo
    {    file_handle logfile;
         void handleInterrupt(int interrupt) { writeMessage(interrupt,
logfile); }
    }
    Foo f = new Foo;
    f.logfile = openFile(logFilename, "a");
    registerInterruptHandler(12, f.handleInterrupt);
}

It's a little more work, but not so bad.
Ah.. clever approach, certainly. Do-it-yourself lexical closures, similar to the Java approach. I'm afraid I agree with Jeroen on this point though, it is very easy to introduce that subtle bug of referencing de-scoped locals. Also, in the above example, won't f get garbage collected soon? Does the collector need to track references to f's members for this construct to work? (Does it anyway? I'm not familiar with the techniques it uses...) Dan
No the pointer will be held in a delegate which is a object/function pointer pair. Since there is an active pointer to the object it won't be collected.
Feb 27 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Dan Liebgold" <Dan_member pathlink.com> wrote in message
news:b3lri6$1m8f$1 digitaldaemon.com...
 I'm afraid I agree with Jeroen on this point though, it is very easy to
 introduce that subtle bug of referencing de-scoped locals.
I'm thinking it may be possible to add a runtime check for that.
 Also, in the above
 example, won't f get garbage collected soon?
No.
 Does the collector need to track
 references to f's members for this construct to work? (Does it anyway? I'm
not
 familiar with the techniques it uses...)
It scans the entire stack for references. f.handleInterrupt will contain a reference to f, and the usual places that the delegate will be stored will be scanned.
Feb 27 2003
parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
 I'm thinking it may be possible to add a runtime check for that.
It may even be possible to do static checking: the 'registerInterruptHandler(12, handleInterrupt)' in the example would have to be declared as registerInterruptHandler( int, global delegate()) to be allowed to store the reference to the delegate somewhere. Passing 'handleInterrupt' would then be disallowed, since nested functions are of type "local delegate" and thus not assignment compatible You could discuss about the wording (local vs global or something else) or perhaps define a default ( all 'delegate' parameter values are assumed local (not storable) unless explicitly declared "global" (or "storable"), or vice versa )
Feb 27 2003
next sibling parent "Walter" <walter digitalmars.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3mab5$1vde$1 digitaldaemon.com...
 I'm thinking it may be possible to add a runtime check for that.
It may even be possible to do static checking: the 'registerInterruptHandler(12, handleInterrupt)' in the example would have to be declared as registerInterruptHandler( int, global delegate())
to
 be allowed to store the reference to the delegate somewhere. Passing
 'handleInterrupt' would then be disallowed, since nested functions are of
 type "local delegate" and thus not assignment compatible

 You could discuss about the wording (local vs global or something else) or
 perhaps define a default ( all 'delegate' parameter values are assumed
local
 (not storable) unless explicitly declared "global" (or "storable"), or
vice
 versa )
Some good thoughts there.
Feb 27 2003
prev sibling next sibling parent "Peter Hercek" <vvp no.post.spam.sk> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3mab5$1vde$1 digitaldaemon.com...
 I'm thinking it may be possible to add a runtime check for that.
It may even be possible to do static checking: the 'registerInterruptHandler(12, handleInterrupt)' in the example would have to be declared as registerInterruptHandler( int, global delegate()) to be allowed to store the reference to the delegate somewhere. Passing 'handleInterrupt' would then be disallowed, since nested functions are of type "local delegate" and thus not assignment compatible You could discuss about the wording (local vs global or something else) or perhaps define a default ( all 'delegate' parameter values are assumed local (not storable) unless explicitly declared "global" (or "storable"), or vice versa )
I think it can be done even without the "global" keyword, by analyzing the program and anotating every delegate argument of every fucntion with the golobal flag. This way you can get a initial set of functions and a set of rules. To get a result you would find the transitive closure. This is something like forward inference of expert sytems. I believe that you can solve this also using "backward inference" (like prolog uses) to resolve only one specific case. On the other side having the flag explicit can be good hint for a programmer.
Mar 01 2003
prev sibling parent reply Antti Sykari <jsykari gamma.hut.fi> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> writes:
 I'm thinking it may be possible to add a runtime check for that.
It may even be possible to do static checking: the 'registerInterruptHandler(12, handleInterrupt)' in the example would have to be declared as registerInterruptHandler( int, global delegate()) to be allowed to store the reference to the delegate somewhere. Passing 'handleInterrupt' would then be disallowed, since nested functions are of type "local delegate" and thus not assignment compatible You could discuss about the wording (local vs global or something else) or perhaps define a default ( all 'delegate' parameter values are assumed local (not storable) unless explicitly declared "global" (or "storable"), or vice versa )
Okay, let's discuss. First, let's make the vocabulary clear. There are three kinds of callable entities: "function" - just the normal function. Contains the address of the function. "local delegate" - created by nested function or function literal Contains the address of the function and a pointer to the activation record of the function it is defined in. That activation record will be demolished (if it's allocated from the stack which is what we usually do) at some point. "global delegate" - created from a class member function Contains the address of the function and a pointer to its environment, which is an object allocated on the heap. The environment won't be destroyed until the delegate itself disappears. [I intentionally avoid the term "closure" because of my superstitiously traditional definition of closure: that it captures its environment. Global delegates are kind-of closures (although there environment == object), and local delegates are pseudo-closures which act like "real" closures until the environment goes out of scope, after which they cause terror and destruction.] Now the situation is that local delegates cannot be safely stored, while global delegates can. This is the fundamental difference. However, at the moment, there is only a single "delegate" concept in D. The user of a delegate doesn't know if it can store it or not. If this situation stays, it's likely that "Don't store local delegates" will be the first item in the book "D traps and pitfalls". Which would be scaringly close to those "Remember to write a virtual destructor" hints that C++ books are full of. The best situation would be if there would be no need for such advice. Delegates can be made safe in different ways, some of which are: 1. Relying on global error checking After compilation, check every store of every delegate and ensure that they never originate from a nested function or function literal. Pros: - doesn't need changes in the language spec - will probably prevent majority of problems Cons: - the source must be available (or just the information about where delegates are stored) - complexity - the resulting error message might still be intimidating to someone who's about to shoot himself in the foot: "Illegal local delegate store in function void foobar(delegate int() x) in flabbergast.d:234, called in function void xyz() in application.d:95". Still, it would be better than letting the programmer actually shoot himself in the foot. 2. Relying on lint-like tools The same as above, except implemented as a separate tool. Pros: - doesn't complicate the compiler nor the language Cons: - makes the programmer's life more complex, though - and it goes without mention that the language would instantly have a C-like kludgy feeling 3. Making the two types of delegates different types. Like this: (assume that "global delegate" is made the default. This can be questioned, but at least that decision won't break the existing code) - objects of type "delegate" can be stored - objects of type "local delegate" can be used and passed around, but not stored - there should be an implicit conversion "delegate -> local delegate" - optionally, the programmer should be able to convert local delegates to "real" delegates, if he's 100% certain that the local delegate won't outlive its activation record. The cast should be as ugly and eye-catching as possible, by similar reasoning as with C++'s reinterpret_cast<>. For instance, it could be useful for storing a temporary copy of the delegate (for some reason). Pros: - safety: you cannot store a local delegate unknowingly, which catches the vast majority of possible delegate bugs - speed (the performance is the same as it is now) - simplicity (from the implementor's viewpoint) - just add a new type, a conversion, and there you go Cons: - complexity in the interface: you'll have to state "local delegate(...)" everywhere where you know that you won't be storing the delegate. This is precisely the same problem as with C interfaces and const: if you have, for example, the function void print(char *c);, you can't give it a string literal, because that's a const char *. 4. Getting rid of local delegates altogether by allocating some of the allocation records on the heap This one would be something pretty cool if only possible. The idea is to allocate from the heap those allocation records that have escaping delegates. It's just a hot-headed idea and I'm not sure if it's at all feasible. Usually actication records are either all allocated on the stack or on the heap. I found one description of a hybrid solution at http://www.cs.indiana.edu/~dyb/papers/stack-abstract.html, though. (Mainly targeted for languages with first-class continuations.) Pros: - safety: since all delegates are true closures, no need to worry about pointers to long-gone activation records. - simplicity: the programmer need not worry about local or global delegates - he'll only know about delegates. Cons: - Speed. Calling functions with escaping delegates is slower because of heap-allocation and potential cache misses due to lost memory locality. However, if the compiler could do global analysis and notice that the delegate won't be stored anywhere, it could put the allocation record in the stack as usually and refer to that. - Complexity in the implementation side, especially if the above optimization is required 5. Combining the approaches 3 and 4 Include both local delegates and delegates as distinct types. Whenever local delegate is converted into a global delegate is required, the activation record of the originating function of the delegate is marked to be heap-allocated. This ensures that there can be no dangling references to the activation record. Pros: - speed: when a local delegate is required, we can use one without allocating anything on the heap - flexibility: when a global delegate is required, we can still use a local one with the cost that the activation record is allocated from the heap Cons: - complexity of both the interface (need two different types) and the implementation (must be able to heap-allocate the activation records) In summary: all of solutions (3)-(5) are safe. Solution (3) is straightforward and emphasizes ease of implementation. Solution (4) emphasizes ease of use. Solution (5) provides both speed and flexibility with the cost of added complexity both on the usage and implementation side. In addition, there probably are feasible solutions that my imagination isn't capable of coming up with. Oh yeah, and then we have yet another alternative: 6. Letting things be as they are now - possibly unsafe, but simple, efficient and mostly useful. Delegates are definitely good, and experienced developers will know to be careful when they encounter a delegate. If they're even a bit safety-conscious, they'll never store the delegate, because it might contain a pointer to the stack frame. Especially in a context where you can never know where the delegate comes from, and you have no way to inform that you must be able to store the delegate. However, when programming projects get larger, someone will, eventually, in a moment of dim-wittedness, hurry, carelessness, or fatigue, store a pointer to a local delegate and then someone other will happily call it in an unexpected situation (say, an error handler which is called very rarely and tested only a couple of specific situations, or perhaps even untested.) And there we have a catastrophe. (To be dramatic, I'll now have to include some examples of software catastrophes to gain appreciation to my view :-) http://courses.cs.vt.edu/~cs3604/lib/Therac_25/Therac_1.html http://www.ima.umn.edu/~arnold/disasters/ariane.html http://www.cs.tau.ac.il/~nachumd/verify/horror.html I'd live happily with alternatives 3, 4 or 5 - and even 6, but I'd be much more comfortable with some kind of guarantee that a nonexistent stack frame will never be accessed. -Antti
Mar 01 2003
next sibling parent Patrick Down <pat codemoon.com> writes:
Antti Sykari <jsykari gamma.hut.fi> wrote in
news:87n0kebvdg.fsf_-_ hoastest1-8c.hoasnet.inet.fi: 

 The best situation would be if there would be no need for such advice.
 Delegates can be made safe in different ways, some of which are:
7. Marking functions that will hold a reference. void delagate() foo; // stored flag marks fn as a as being // stored by the function void setFn(stored void deligate() a) { foo = a; } void one() { // Global scope } void bar() { int i; void two() { // Does not access local scope } void three() { // Accesses local scope i = 5; } setFn(&one); // Ok setFn(&two); // Ok setFn(&three); // Error } Could be used for auto objects too void foo(stored Object a) { } void bar() { auto Object o = new Object(); foo(o); // Error }
Mar 01 2003
prev sibling parent Antti Sykari <jsykari gamma.hut.fi> writes:
A funny thought crossed my mind...

Are structs now equivalent to classes in the sense that struct member
functions can be stored into delegates?  (They would, usually, be local
delegates in the sense that structs tend to be stack-allocated.)

Should they?

-Antti
Mar 01 2003
prev sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
In article <b3ko0o$ueh$1 digitaldaemon.com>, Walter says...
void startLogging(string logFilename)
{
    class Foo
    {    file_handle logfile;
         void handleInterrupt(int interrupt) { writeMessage(interrupt,
logfile); }
    }
    Foo f = new Foo;
    f.logfile = openFile(logFilename, "a");
    registerInterruptHandler(12, f.handleInterrupt);
}

It's a little more work, but not so bad.
Here's an idea for some syntactic sugar to make that pill easier to swallow: In C++, classes can implement cast methods, for example: class IntObj { int data; operator float { return (float)data; } } How about an overloadable operator such that you can cast a class instance to a delegate? The declaration syntax may be difficult to get right. However, with it you could do this (the example assumes you add the keyword 'closure' to denote the technique): void startLogging(string logFilename) { class Foo { file_handle logfile; this (file_handle log) { logfile = log; } void handleInterrupt(int interrupt) { writeMessage(interrupt, logfile); } delegate void (int) closure { return handleInterrupt; } } Foo f = new Foo(openFile(logFilename, "a")); registerInterruptHandler(12, handleInterrupt); } So in this example registerInterruptHandler received a normal "delegate void (int)", just like it expected. "handleInterrupt" would be restricted by the compiler to only referencing globals or symbols within the Foo class (it would have no reference to anything in the startLogging function). Anything the delegate needs, pass it to Foo's constructor. One step further: void startLogging(string logFilename) { class Foo { file_handle logfile; this (char[] name) { logfile = openFile(name, "a") } void handleInterrupt(int interrupt) { writeMessage(interrupt, logfile); } delegate void (int) closure { return handleInterrupt; } } registerInterruptHandler(12, new Foo(logFilename)); } Voila... lexical closures, without the implementational complexity, and without any lurking stack traps for the unwary. Dan
Feb 28 2003
parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
 Here's an idea for some syntactic sugar to make that pill easier to
swallow:
 In C++, classes can implement cast methods, for example:

 class IntObj {
 int data;
 operator float { return (float)data; }
 }

 How about an overloadable operator such that you can cast a class instance
to a
 delegate?
Talking about hidden and obscure implicit behavior! (You should interpret the above as "no, I don't think that's a good idea") Why not? a) "f.handleInterrupt" is a lot shorter to type than declaring & implementing a 'delegator cast operator' b) since it's a local function/class, it's sure to have limited size and functionality. In fact, it should be as short as possible to keep readability acceptable c) overloadable operators are a questionable syntactic-sugar feature of C++. Overloadable type-cast operators are a nightmare, since the implicit type casts they cause go against all type safety principles d) "casting a class instance to a delegate" - just reading that should raise questions about the semantics...
Mar 01 2003
next sibling parent "Peter Hercek" <vvp no.post.spam.sk> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3qvu1$2a5o$1 digitaldaemon.com...
 a) "f.handleInterrupt" is a lot shorter to type than declaring &
 implementing a 'delegator cast operator'
I do agree.
 b) since it's a local function/class, it's sure to have limited size and
 functionality. In fact, it should be as short as possible to keep
 readability acceptable
When you need a lexical closures, you need to create an object for it currently. This adds lines for the object plus a line for the explicit delegate creation.
 c) overloadable operators are a questionable syntactic-sugar feature of C++.
 Overloadable type-cast operators are a nightmare, since the implicit type
 casts they cause go against all type safety principles
I do agree.
 d) "casting a class instance to a delegate" - just reading that should raise
 questions about the semantics...
I'm not sure about this one. You are probably right, but on the other side it looks very similar to C++ functors. That is not so bad. Still it can be cast to more delegates. Yes, it may be better to create the delegate explicitly (even when it is more to type). Still, there is diference when compared with point c. It canot cause some chain of implicit casts (delegate cannot be casted to anything else). So may be worth a try. What do other think?
Mar 01 2003
prev sibling parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
You're right... and you can't mark a user-defined cast as "explicit".  I'd
much rather have just constructors.  Problem is, you can't add constructors
to other classes such as "int".

Sean

 c) overloadable operators are a questionable syntactic-sugar feature of
C++.
 Overloadable type-cast operators are a nightmare, since the implicit type
 casts they cause go against all type safety principles
Mar 01 2003
parent reply "Jeroen van Bemmel" <anonymous somewhere.com> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
news:b3sc9l$2uvl$1 digitaldaemon.com...
 You're right... and you can't mark a user-defined cast as "explicit".  I'd
 much rather have just constructors.  Problem is, you can't add
constructors
 to other classes such as "int".
To me, a need for "explicit" is just a sign that there is something inherently wrong with the 'feature' of implicit object creation when a single-argument constructor exists. Consider a function void f( SomeClass c ) That means, that c needs to be of type 'SomeClass' (or a subclass of that). C++ actually allows you to have another class with a 1-argument constructor class CompletelyDifferentClass { CompletelyDifferentClass( SomeClass c ) // 1-argument constructor } and then (perhaps even depending on visiblity, I'm not sure here, and also if SomeClass is not abstract) you can do CompletelyDifferentClass d; f( d ) Reading this code without the class or function declarations would make you think that either (1) f takes a 'CompletelyDifferentClass' as an argument, or (2) a superclass thereof. Instead, _implicitly_ a new, temporary object of class SomeClass is created, using the 1-argument constructor. Horror! No reference to 'SomeClass' is made in the above code fragment, yet it is involved. So this means that a 1-argument constructor models "is_a" (while in fact it is "can_be_constructed_from_a") I vote for explicit object construction always, preferrably with always the same language construct ("new" will do fine). appeal to me either. They claim that "everything is an object" (Marketing: "much better than Java"), but underwater some things are more object than others, heavily affecting performance as a "side effect"
Mar 02 2003
next sibling parent Antti Sykari <jsykari gamma.hut.fi> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> writes:

 "Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
 news:b3sc9l$2uvl$1 digitaldaemon.com...
 You're right... and you can't mark a user-defined cast as "explicit".  I'd
 much rather have just constructors.  Problem is, you can't add
constructors
 to other classes such as "int".
To me, a need for "explicit" is just a sign that there is something inherently wrong with the 'feature' of implicit object creation when a single-argument constructor exists. Consider a function void f( SomeClass c ) That means, that c needs to be of type 'SomeClass' (or a subclass of that). C++ actually allows you to have another class with a 1-argument constructor class CompletelyDifferentClass { CompletelyDifferentClass( SomeClass c ) // 1-argument constructor }
You probably meant vice versa: class SomeClass { SomeClass( CompletelyDifferentClass c ); }
 and then (perhaps even depending on visiblity, I'm not sure here, and also
 if SomeClass is not abstract) you can do

 CompletelyDifferentClass d;
 f( d )
Could be useful, if, for example, SomeClass is replaced by "int" and CompletelyDifferentClass with "float". Sprinkling the code with explicit conversion function calls may make it less readable and make it more difficult to spot the "really dangerous" explicit conversions from the code. -Antti
Mar 02 2003
prev sibling parent "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
Perhaps they should have chosen to make explicit behavior the default, and
added an "implicit" keyword instead.  Implicit conversion is still very
useful under controlled circumstances.

I find that, like operator overloading and templates, implicit
construction/conversion is one of those language features that people
strongly lobby against because they have personally been burned by it at
some point in the past.  What they don't realize is that, with proper care,
it can be a VERY powerful language feature that make solving some particular
problem feasible or at least easier.  When combined with templates, implicit
conversion might allow you to express something that you couldn't otherwise
say because you don't know or don't have handy access to the name of the
type you want it converted to, or don't care if the types match exactly.

I can't justify exclusion of a feature because you don't happen to like it
and have a description of a circumstance in which you shot yourself in the
foot with it.

In C++ I use implicit user-defined conversion to bool, int, and float all
the time.  A colleague at work just made a "smart enum" class that uses it;
this enum knows how to convert itself to and from a string automatically.

Sean

"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3t8hp$blq$1 digitaldaemon.com...
 "Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
 news:b3sc9l$2uvl$1 digitaldaemon.com...
 You're right... and you can't mark a user-defined cast as "explicit".
I'd
 much rather have just constructors.  Problem is, you can't add
constructors
 to other classes such as "int".
To me, a need for "explicit" is just a sign that there is something inherently wrong with the 'feature' of implicit object creation when a single-argument constructor exists. Consider a function void f( SomeClass c ) That means, that c needs to be of type 'SomeClass' (or a subclass of
that).
 C++ actually allows you to have another class with a 1-argument
constructor
 class CompletelyDifferentClass
 {
     CompletelyDifferentClass( SomeClass c )    // 1-argument constructor
 }

 and then (perhaps even depending on visiblity, I'm not sure here, and also
 if SomeClass is not abstract) you can do

 CompletelyDifferentClass d;
 f( d )

 Reading this code without the class or function declarations would make
you
 think that either (1) f takes a 'CompletelyDifferentClass' as an argument,
 or (2) a superclass thereof. Instead, _implicitly_ a new, temporary object
 of class SomeClass is created, using the 1-argument constructor. Horror!
No
 reference to 'SomeClass' is made in the above code fragment, yet it is
 involved. So this means that a 1-argument constructor models "is_a" (while
 in fact it is "can_be_constructed_from_a")

 I vote for explicit object construction always, preferrably with always
the
 same language construct ("new" will do fine).


 appeal to me either. They claim that "everything is an object" (Marketing:
 "much better than Java"), but underwater some things are more object than
 others, heavily affecting performance as a "side effect"
Mar 02 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Jeroen van Bemmel" <anonymous somewhere.com> wrote in message
news:b3kh99$qoj$1 digitaldaemon.com...
 BTW, now that I'm thinking about this: One of the worse features of Java
IMO
 is the rediculous amount of resources (memory) it uses for simple things.
 The garbage collector is good, but it allocates so many small objects (the
 example I gave allocates one for the function object).
True, one thing I was going to point out about your example is that the D way of doing it is far more efficient of run time and memory.
 The advantage is though that I can return this object from my function,
and
 use it elsewhere. What happens if I return a reference to a nested
function
 delegate in D? Is it still valid, is there also some memory allocated
 underneath? You would expect it to go out of scope, so the compiler should
 issue a warning "returning reference to local function" or something
No memory is allocated underneath, a hidden pointer to the stack frame is just saved and passed as a parameter to f(). That means, if the function goes out of scope, it is just as much an error as returning a pointer to a local: int *wrong() { int i; return &i; }
Feb 27 2003
prev sibling parent reply Bill Cox <bill viasic.com> writes:
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
Feb 26 2003
parent "Walter" <walter digitalmars.com> writes:
"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.
Feb 26 2003
prev sibling next sibling parent reply Andy Friesen <andy ikagames.com> writes:
The linker doesn't seem to like it when you put two function literals in 
the same function.

Also, this doesn't seem to work.  Should it? (not that it's useful in 
any way)

delegate() { printf("stop the insanity!\n"); }();

Walter wrote:
 Some long overdue features.
 
 www.digitalmars.com/d/changelog.html
 
 
 
Feb 25 2003
parent "Walter" <walter digitalmars.com> writes:
"Andy Friesen" <andy ikagames.com> wrote in message
news:b3h201$1l7n$1 digitaldaemon.com...
 The linker doesn't seem to like it when you put two function literals in
 the same function.
I should fix that.
 Also, this doesn't seem to work.  Should it? (not that it's useful in
 any way)

 delegate() { printf("stop the insanity!\n"); }();
It should work, although I agree it's useless.
Feb 25 2003
prev sibling next sibling parent Patrick Down <pat codemoon.com> writes:
"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; }
Feb 25 2003
prev sibling next sibling parent reply Farmer <itsFarmer. freenet.de> writes:
"Walter" <walter digitalmars.com> wrote in 
news:b3fdlo$kp1$1 digitaldaemon.com:

Walter, 

here are three issues I encountered with DMD 0.56 and 0.57:

The template argument deduction seems to be broken. The Object type is 
ignored by the compiler. 

class A { }
class B : A { }

template TFoo(T : A) { }
instance TFoo(B);

Causes this error message:
instance TFoo(B ) does not match any template declaration


--

DMD.zip contains the compiler twice: See file "DMD\.EXE".


--

I compiled some D code that compiles and runs fine, if the option -O is not 
used. If option -O is turned on, the compiler says:
Internal error: ..\ztc\cgcod.c 2198



Farmer
Feb 26 2003
next sibling parent "Walter" <walter digitalmars.com> writes:
"Farmer" <itsFarmer. freenet.de> wrote in message
news:Xns932EE4CF28753itsFarmer 63.105.9.61...
 I compiled some D code that compiles and runs fine, if the option -O is
not
 used. If option -O is turned on, the compiler says:
 Internal error: ..\ztc\cgcod.c 2198
I need an example. Thanks! -Walter
Feb 26 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Farmer" <itsFarmer. freenet.de> wrote in message
news:Xns932EE4CF28753itsFarmer 63.105.9.61...
 DMD.zip contains the compiler twice: See file "DMD\.EXE".
Fixed.
Feb 26 2003
prev sibling next sibling parent Burton Radons <loth users.sourceforge.net> writes:
Function pointers don't print diagnostics using the new syntax, such as 
with:

    void main ()
    {
       void delegate () foo;
       static void bar () { }
       foo = bar;
    }

Prints "cannot implicitly convert void(*)() to void delegate()".
Feb 27 2003
prev sibling next sibling parent reply Burton Radons <loth users.sourceforge.net> writes:
This one is longstanding.

f.d:
    import g;

    void main ()
    {
       printf ("%d\n", foo); // "foo" shouldn't be imported!
    }

g.d:
    static int foo;

So "static" is being ignored.  Now would be a good time to move to 
"private" to mean the same thing instead, and to make applying "static" 
to a symbol at the module level an error.  I think it would be a good 
idea, anyway.

I would also like the change where "protected" means that the symbol 
isn't imported, but it IS accessible by using the module name.
Feb 27 2003
next sibling parent Patrick Down <pat codemoon.com> writes:
Burton Radons <loth users.sourceforge.net> wrote in news:b3ml3m$25bi$1
 digitaldaemon.com:

 I would also like the change where "protected" means that the symbol 
 isn't imported, but it IS accessible by using the module name.
I'll vote for this too.
Feb 27 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Burton Radons" <loth users.sourceforge.net> wrote in message
news:b3ml3m$25bi$1 digitaldaemon.com...
 This one is longstanding.

 f.d:
     import g;

     void main ()
     {
        printf ("%d\n", foo); // "foo" shouldn't be imported!
     }

 g.d:
     static int foo;

 So "static" is being ignored.  Now would be a good time to move to
 "private" to mean the same thing instead,
It already does.
 and to make applying "static"
 to a symbol at the module level an error.
At the moment, it's a no-op.
Feb 27 2003
next sibling parent Burton Radons <loth users.sourceforge.net> writes:
Walter wrote:
 "Burton Radons" <loth users.sourceforge.net> wrote in message
 news:b3ml3m$25bi$1 digitaldaemon.com...
 
So "static" is being ignored.  Now would be a good time to move to
"private" to mean the same thing instead,
It already does.
Ack, there're places in Phobos which assume that static has the C meaning then: crc32.d (crc32_table), regexp.d (isword, inf, replace3), and stream.d (iswhite, isdigit, isoctdigit, ishexdigit).
Feb 27 2003
prev sibling parent reply "Peter Hercek" <vvp no.post.spam.sk> writes:
"Walter" <walter digitalmars.com> wrote in message
news:b3mnhp$26ii$1 digitaldaemon.com...
 So "static" is being ignored.  Now would be a good time to move to
 "private" to mean the same thing instead,
It already does.
 and to make applying "static"
 to a symbol at the module level an error.
At the moment, it's a no-op.
Will this no-op change to "done"? I do not like too much when one has more options to do the same. There are already two ways how to define arrays: I'm also confused with the fucntion literal declaration. Grammar states: FunctionLiteral ::= function Type ( ParameterDeclarations ) but the example just below goes like: int function(char c) fp; instead of: function int(char c) fp; Is this intentional ambiguity? Or does it have some meaning unknown to me? I'm also playing with the idea that the return type of a function should be always explicitly stated - to enforce this by grammar. I have two reasons: a) looks beter b) your default is void (contrary to int in C/C++) These ambiguities at such a low level have some *bad* conssequences: a) one need to learne them, that there are more ways to achieve exaclty the same and less readable code thereof b) tool implementations will be more comlicated because of this (and reason? good feel only ... because it doe not add any new functionality) c) it makes seraching in the source code more complicated (transition to more complicated regular expressions) I do not know how other guys think about this, may be I'm alone who minds it :)
Mar 01 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Peter Hercek" <vvp no.post.spam.sk> wrote in message
news:b3rerf$2hdt$1 digitaldaemon.com...
 "Walter" <walter digitalmars.com> wrote in message
news:b3mnhp$26ii$1 digitaldaemon.com...
 So "static" is being ignored.  Now would be a good time to move to
 "private" to mean the same thing instead,
It already does.
 and to make applying "static"
 to a symbol at the module level an error.
At the moment, it's a no-op.
Will this no-op change to "done"?
?. no-op means "it's ignored".
 I'm also confused with the fucntion literal declaration.
  Grammar states:
 FunctionLiteral ::= function Type ( ParameterDeclarations )
  but the example just below goes like:
 int function(char c) fp;
That is not a function literal, but a declaration of a pointer to a function.
  instead of:
 function int(char c) fp;
That is invalid.
 I'm also playing with the idea that the return type of a function
  should be always explicitly stated - to enforce this by grammar.
  I have two reasons:
 a) looks beter
 b) your default is void (contrary to int in C/C++)
The default isn't int in C/C++ anymore, it must be specified.
 These ambiguities at such a low level have some *bad*
  conssequences:
 a) one need to learne them, that there are more ways to achieve
  exaclty the same and less readable code thereof
 b) tool implementations will be more comlicated because of this
  (and reason? good feel only ... because it doe not add any new
  functionality)
 c) it makes seraching in the source code more complicated
  (transition to more complicated regular expressions)
 I do not know how other guys think about this, may be I'm
  alone who minds it  :)
I did it that way because the function literal syntax was already rather longish.
Mar 01 2003
parent "Peter Hercek" <vvp no.post.spam.sk> writes:
"Walter" <walter digitalmars.com> wrote in message
news:b3rhmu$2iju$1 digitaldaemon.com...
 I'm also confused with the fucntion literal declaration.
  Grammar states:
 FunctionLiteral ::= function Type ( ParameterDeclarations )
  but the example just below goes like:
 int function(char c) fp;
That is not a function literal, but a declaration of a pointer to a function.
  instead of:
 function int(char c) fp;
That is invalid. I did it that way because the function literal syntax was already rather longish.
Got it! Thanks.
Mar 01 2003
prev sibling next sibling parent Burton Radons <loth users.sourceforge.net> writes:
Weird bug with static:

    struct foo
    {
       static struct bar
       {
          int x;
       }
    }

    void main ()
    {
       printf ("%d\n", foo.bar.size);
    }

This prints 1, rather than 4!
Feb 27 2003
prev sibling next sibling parent reply Patrick Down <pat codemoon.com> writes:
"Walter" <walter digitalmars.com> wrote in news:b3fdlo$kp1$1
 digitaldaemon.com:

 Some long overdue features.
 
 www.digitalmars.com/d/changelog.html
 
The following program prints: 12,14 1244952,14 What's with the value of i in the nested fuction? void foo(void delegate() baz) { baz(); } void bar(int i) { int j = 14; printf("%d,%d\n",i,j); void fred() { printf("%d,%d\n",i,j); } foo(&fred); } int main(char[][] argv) { bar(12); return 0; }
Feb 27 2003
parent reply Patrick Down <pat codemoon.com> writes:
Patrick Down <pat codemoon.com> wrote in 
news:Xns932FF17C3FB85patcodemooncom 63.105.9.61:

 "Walter" <walter digitalmars.com> wrote in news:b3fdlo$kp1$1
  digitaldaemon.com:
 
 Some long overdue features.
 
 www.digitalmars.com/d/changelog.html
 
The following program prints: 12,14 1244952,14 What's with the value of i in the nested fuction? void foo(void delegate() baz) { baz(); } void bar(int i) { int j = 14; printf("%d,%d\n",i,j); void fred() { printf("%d,%d\n",i,j); } foo(&fred); } int main(char[][] argv) { bar(12); return 0; }
Similar example. i and j are messed up in this one. void frelled(void delegate() baz) { baz(); } class Foo { void bar(int i) { int j = 14; printf("%d,%d\n",i,j); void fred() { printf("%d,%d\n",i,j); } frelled(&fred); } } int main(char[][] argv) { Foo f = new Foo(); f.bar(12); return 0; }
Feb 27 2003
parent "Walter" <walter digitalmars.com> writes:
They're both compiler bugs and I'll fix them. -Walter
Feb 28 2003
prev sibling next sibling parent reply Burton Radons <loth users.sourceforge.net> writes:
Now with nested and inline functions:

    int foo ()
    {
       return 0x12345678;
    }

    void main ()
    {
       int nestedFunction () { return foo (); }

       printf ("%08X\n", foo ());
       printf ("%08X\n", nestedFunction ());
       printf ("%08X\n", delegate int () { return foo (); });
    }

This prints:

    12345678
    12345678
    0012FF1C

Replacing "delegate" with "function" prints "0040305C".
Feb 27 2003
parent Burton Radons <loth users.sourceforge.net> writes:
Burton Radons wrote:
       printf ("%08X\n", delegate int () { return foo (); });
Gah, I'm a stupidhead. Sorry.
Feb 27 2003
prev sibling next sibling parent reply Burton Radons <loth users.sourceforge.net> writes:
This requires multiple modules:

f.d:
    module foo.bar;
    import g;

g.d:
    import f;

Using "dmd f.d" complains that "g.d(1): module f is in multiple packages 
foo.bar".

Secondly, you say that you made "private" mean "static", but that 
doesn't work either:

f.d:
    import g;

    void main()
    {
       int x = foo;
    }

g.d:
    private int foo;

Using "dmd -c f.d" on this code compiles, even though it's an error.
Mar 02 2003
parent "Walter" <walter digitalmars.com> writes:
"Burton Radons" <loth users.sourceforge.net> wrote in message
news:b3skqh$2hb$1 digitaldaemon.com...
 This requires multiple modules:

 f.d:
     module foo.bar;
     import g;

 g.d:
     import f;

 Using "dmd f.d" complains that "g.d(1): module f is in multiple packages
 foo.bar".
Hmmm. Looks like a compiler bug.
 Secondly, you say that you made "private" mean "static", but that
 doesn't work either:

 f.d:
     import g;

     void main()
     {
        int x = foo;
     }

 g.d:
     private int foo;

 Using "dmd -c f.d" on this code compiles, even though it's an error.
I just fixed that one last night <g>.
Mar 02 2003
prev sibling next sibling parent Burton Radons <loth users.sourceforge.net> writes:
Here's a symbol bug:

    class A
    {
       class Child
       {
       }
    }

    class B
    {
       class Child
       {
          static int value;
       }
    }

    void main()
    {
       printf ("%d\n", B.Child.value);
    }

Compiling this with "dmd module.d", I get "module.d(18): no property 
'value' for type 'Child'".  A and B have nested classes with the same 
name, but B.Child resolves to A.Child.
Mar 02 2003
prev sibling parent Burton Radons <loth users.sourceforge.net> writes:
Assertions don't use the file name assigned through #line.  For example:

blat.d:
    #file 64 "foobar"
    void main()
    {
       assert(0);
    }

Compiling this with "dmd blat.d" and running it reports "Error: 
Assertion Failure blat.d(66)".
Mar 02 2003