D - Delegates
- "Walter" <walter digitalmars.com> Apr 02 2002
- "Pavel Minayev" <evilone omen.ru> Apr 02 2002
- "J. Daniel Smith" <j_daniel_smith HoTMaiL.com> Apr 03 2002
- "Richard Krehbiel" <rich kastle.com> Apr 03 2002
- "J. Daniel Smith" <j_daniel_smith HoTMaiL.com> Apr 03 2002
- Russ Lewis <spamhole-2001-07-16 deming-os.org> Apr 02 2002
- "OddesE" <OddesE_XYZ hotmail.com> Apr 02 2002
- "Pavel Minayev" <evilone omen.ru> Apr 02 2002
- "J. Daniel Smith" <j_daniel_smith HoTMaiL.com> Apr 04 2002
- roland <nancyetroland free.fr> Apr 04 2002
- Roland <rv ronetech.com> Apr 04 2002
- "Richard Krehbiel" <rich kastle.com> Apr 05 2002
- "Walter" <walter digitalmars.com> Apr 05 2002
- Russell Borogove <kaleja estarcion.com> Apr 05 2002
- "Pavel Minayev" <evilone omen.ru> Apr 05 2002
- Russell Borogove <kaleja estarcion.com> Apr 05 2002
- "Pavel Minayev" <evilone omen.ru> Apr 05 2002
- Russell Borogove <kaleja estarcion.com> Apr 05 2002
- "Walter" <walter digitalmars.com> Apr 05 2002
- "Pavel Minayev" <evilone omen.ru> Apr 06 2002
- "Walter" <walter digitalmars.com> Apr 06 2002
- "Pavel Minayev" <evilone omen.ru> Apr 06 2002
- "Pavel Minayev" <evilone omen.ru> Apr 05 2002
A first crack at a proposal.
----------------------------------
A delegate is conceptually a function pointer coupled with an object
reference. If the function is a non-member or a static function, the object
reference is null.
There are three things to do with delegates 1) declaring them
2) initializing them and 3) calling them.
1. Declaring Delegates
A delegate needs a return type and a parameter list. Introduce the keyword
'delegate' and declare mydelegate as:
int delegate(int x, int y) mydelegate;
An array of delegates would be:
float delegate(int *p)[] foo; // foo is array of delegates
Delegates can be typedef'd:
typedef int delegate(int x, int y) bar;
bar x; // x is a delegate
2. Initializing Delegates
Delegates are initialized with an object and a function signature.
They are initialized with a DelegateExpression:
class Abc
{
int func(int,int);
}
Abc a = new Abc();
int delegate(int, int) x;
x = delegate(a, func(int,int));
The first argument to delegate(object, function signature) is the object
reference.
A delegate to a non-member or static function can be initialized
by using null as the object:
int xyzzy(int, int);
x = delegate(null, xyzzy(int, int));
3. Calling Delegates
Delegates are called as if they are normal functions:
x(3,4); // call delegate x
Apr 02 2002
"Walter" <walter digitalmars.com> wrote in message news:a8d501$2far$1 digitaldaemon.com...A first crack at a proposal. ---------------------------------- A delegate is conceptually a function pointer coupled with an object reference. If the function is a non-member or a static function, the
reference is null.
Seems like the best solution.There are three things to do with delegates 1) declaring them 2) initializing them and 3) calling them. 1. Declaring Delegates A delegate needs a return type and a parameter list. Introduce the keyword 'delegate' and declare mydelegate as: int delegate(int x, int y) mydelegate;
Pretty fine. Looks more like variable declaration, and is much better than C function pointers;An array of delegates would be: float delegate(int *p)[] foo; // foo is array of delegates
Consistent.Delegates can be typedef'd: typedef int delegate(int x, int y) bar; bar x; // x is a delegate
As well.2. Initializing Delegates Delegates are initialized with an object and a function signature. They are initialized with a DelegateExpression: class Abc { int func(int,int); } Abc a = new Abc(); int delegate(int, int) x; x = delegate(a, func(int,int)); The first argument to delegate(object, function signature) is the object reference.
Just a suggestion: if object is omitted, assume "this" where applicable: class Form { Button OK; void OK_Click(int x, int y) { ... } this() { OK.onClick = delegate(OK_Click(int, int)); } } Pointers to methods of "this" are 90% of all, anyhow.A delegate to a non-member or static function can be initialized by using null as the object: int xyzzy(int, int); x = delegate(null, xyzzy(int, int));
Why not just function pointers? x = &xyzzy(int, int); Or, allow to omit Object, assuming null when outside class.3. Calling Delegates Delegates are called as if they are normal functions: x(3,4); // call delegate x
Yep.
Apr 02 2002
[ moved to this thread from the "new D site" thread ] I would agree. In C#, I loooks the "delegate" keyword actually causes the compiler to do a "typedef" of "System.MulticastDelegate"; then it looks like there is some additional checking to be sure that new "delegate" type is only used with the "event" keyword to declare a variable: public delegate void Foo(int); // typedef System.MulticastDelegate Foo; public event Foo ptr; // Foo ptr; Of course, things are a bit more complicated than that since all the type-checking has to be done. In C#, the argument list is an array of Objects. Microsoft has released the source code for the SDK version of .NET; see http://msdn.microsoft.com/library/en-us/Dndotnet/html/mssharsourcecli.asp. Looking through the code in "delegate.cs" is interesting. Dan [ edited delegate.cs ] "Pavel Minayev" <evilone omen.ru> wrote in message news:a8evkh$5tf$1 digitaldaemon.com..."Walter" <walter digitalmars.com> wrote in message news:a8eie6$40d$1 digitaldaemon.com...The C# syntax I find very confusing. The delegate declaration looks like
storage class, but it isn't, it's a type component. It doesn't seem
in C#, because of the way declarations work, to create an array of
or a pointer to a delegate or a function returning a delegate.
It wasn't actually C# syntax. In C#, "delegate" is actually a keyword which declares type, and not variable: delegate void Foo(int); // Foo is a new type Foo ptr; // declare a pointer of that type So, you can actually have arrays: Foo[] ptr; Still, I like your syntax more. It is more distinct from normal function declaration.The static/virtual delegate call shouldn't cause a slowdown in D, for
happy coincidence that the 'this' pointer is passed in EAX. Hence, just stuff the object reference in EAX after pushing the parameters. If the function doesn't take a this pointer, it ignores EAX with no adverse consequences.
It's implementation detail, I guess. As long as it works, great, and no matter how it is done. I wouldn't mind if it were slower than normal ptr call, but if you can make it the same, well, it's great! By the way, I guess functions with non-D calling conventions cannot be delegated?
Apr 03 2002
Um - The paranoid part of me thinks, Walter, that you should delete that post, since it contains Microsoft copyrighted code. I say this without knowing if it's actually illegal to have posted a copy, but rather from extreme caution. MS might come in later and say that, having read this source you have agreed to the source license, and the source license states that everything you gain from reading the source belongs to MS. Anyway, if you want to learn about C# by looking at source code, there's the Mono project (www.go-mono.com) which is "libre" open source. "J. Daniel Smith" <j_daniel_smith HoTMaiL.com> wrote in message news:a8f65e$bal$1 digitaldaemon.com...Microsoft has released the source code for the SDK version of .NET; see http://msdn.microsoft.com/library/en-us/Dndotnet/html/mssharsourcecli.asp. Looking through the code in "delegate.cs" is interesting. Dan
Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 comcast.net (personal)
Apr 03 2002
I think the provision "You may use any information in intangible form that you remember after accessing the Software." covers the D effort with regards to this. I removed most of the code that actually does anything from my post since that didn't seem very relevent to the discussion; thus the code I posted won't compile, and even it it does, it won't do anything useful. Unless the D compiler morphs into something that can compile C# code, the code snipet would seem to fall under the "academic research" category for use of "the Software". Dan "Richard Krehbiel" <rich kastle.com> wrote in message news:a8fg3e$289$1 digitaldaemon.com...Um - The paranoid part of me thinks, Walter, that you should delete that post, since it contains Microsoft copyrighted code. I say this without knowing if it's actually illegal to have posted a copy, but rather from extreme caution. MS might come in later and say that, having read this source you have agreed to the source license, and the source license
that everything you gain from reading the source belongs to MS. Anyway, if you want to learn about C# by looking at source code, there's
Mono project (www.go-mono.com) which is "libre" open source. "J. Daniel Smith" <j_daniel_smith HoTMaiL.com> wrote in message news:a8f65e$bal$1 digitaldaemon.com...Microsoft has released the source code for the SDK version of .NET; see
Looking through the code in "delegate.cs" is interesting. Dan [ edited delegate.cs ] // ==++== // // // Copyright (c) 2002 Microsoft Corporation. All rights reserved. // // The use and distribution terms for this software are contained in
file // named license.txt, which can be found in the root of this distribution. // By using this software in any fashion, you are agreeing to be
bythe // terms of this license. // // You must not remove this notice, or any other, from this software.
-- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 comcast.net (personal)
Apr 03 2002
Looks really good! -- The Villagers are Online! 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))) ]
Apr 02 2002
"Walter" <walter digitalmars.com> wrote in message news:a8d501$2far$1 digitaldaemon.com...A first crack at a proposal. ---------------------------------- A delegate is conceptually a function pointer coupled with an object reference. If the function is a non-member or a static function, the
reference is null. There are three things to do with delegates 1) declaring them 2) initializing them and 3) calling them. 1. Declaring Delegates A delegate needs a return type and a parameter list. Introduce the keyword 'delegate' and declare mydelegate as: int delegate(int x, int y) mydelegate; An array of delegates would be: float delegate(int *p)[] foo; // foo is array of delegates Delegates can be typedef'd: typedef int delegate(int x, int y) bar; bar x; // x is a delegate 2. Initializing Delegates Delegates are initialized with an object and a function signature. They are initialized with a DelegateExpression: class Abc { int func(int,int); } Abc a = new Abc(); int delegate(int, int) x; x = delegate(a, func(int,int)); The first argument to delegate(object, function signature) is the object reference. A delegate to a non-member or static function can be initialized by using null as the object: int xyzzy(int, int); x = delegate(null, xyzzy(int, int)); 3. Calling Delegates Delegates are called as if they are normal functions: x(3,4); // call delegate x
Oh oh, I sense another rewrite of Pavel's WinD module coming up... :) But I guess you won't mind at all eh Pavel, this is pretty much what you want isn't it? -- Stijn OddesE_XYZ hotmail.com http://OddesE.cjb.net _________________________________________________ Remove _XYZ from my address when replying by mail
Apr 02 2002
"OddesE" <OddesE_XYZ hotmail.com> wrote in message news:a8ddi3$ret$1 digitaldaemon.com...Oh oh, I sense another rewrite of Pavel's WinD module coming up... :) But I guess you won't mind at all eh Pavel, this is pretty much what you want isn't it?
Well, yes =)
Apr 02 2002
The way C# goes about implementing delegates is interesting: the compiler *requires* that certain classes (in this case System.Delegate and friends) exist at run-time. This seems to harken back to languages like Pascal where writeln() was part of the the language, but it was implemented in a run-time library; it is a different approach from C/C++ (and D) where printf() is "only" a library routine. Might the C# way of doing things have some value in D? For this new "delegate" feature, not only does the compiler have to support the new syntax, but then it also has to generate a bunch of code to make the syntax work. By moving the actual implementing into a class, there is much less work for the compiler to do: when it sees the "delegate" keyword is knows to use the System.Delegate class in a certain manner. Of course, this approach opens might open a whole can of worms with regards to issues that have been hashed over to some length already such as operator overloading, since you now have to be able to write a "delegate", "string", or "complex" class in D itself - the compiler can't do as much "black magic" to make such things work. Putting the bulk of the "real work" in a class would also seem to make it easier to port D to other platforms since the compiler itself would now be simplier. Dan "Walter" <walter digitalmars.com> wrote in message news:a8d501$2far$1 digitaldaemon.com...A first crack at a proposal. ---------------------------------- A delegate is conceptually a function pointer coupled with an object reference. If the function is a non-member or a static function, the
reference is null. There are three things to do with delegates 1) declaring them 2) initializing them and 3) calling them. [...]
Apr 04 2002
Walter a écrit :A first crack at a proposal.
beautiful !x = delegate(a, func(int,int));
i don't know why, but i feel delegate initialisation can be nicer: x = delegate(a.func(int,int)); //? or if "a" is *this: x = delegate(func(int,int)) //? or even if there is only one methode called func: x = delegate(a.func); //? roland
Apr 04 2002
roland a écrit :i don't know why, but i feel delegate initialisation can be nicer:
.or even if there is only one methode called func:
rectification: as function args are declared with delegate, there is no ambiguity about witch methode is to be delegated. so, delegate initialisation could, in theory, always be this format.x = delegate(a.func); //?
roland
Apr 04 2002
"Roland" <rv ronetech.com> wrote in message news:3CAD5197.5CC2DA84 ronetech.com...rectification: as function args are declared with delegate, there is no ambiguity about witch methode is to be delegated. so, delegate initialisation could, in theory, always be this format.x = delegate(a.func); //?
Type information (typically) does not flow left-to-right across assignment expressions; in other words, the "delegate" operation can't peek at the "x" across the "=" to find anything out. But actually, having said that, I already know there's an exception in D. String literals become char literals and wide strings based on their assignment context, so maybe delegates can do similar magic. -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 comcast.net (personal)
Apr 05 2002
"Richard Krehbiel" <rich kastle.com> wrote in message news:a8k6de$5na$1 digitaldaemon.com...But actually, having said that, I already know there's an exception in D. String literals become char literals and wide strings based on their assignment context, so maybe delegates can do similar magic.
I had the same thought, but I still haven't figured out what to do in ambiguous cases like: void foo(char[]); void foo(wchar[]); ... foo("hello"); Which gets called? Should it be an error? In any case, I'm leaning towards initializing a delegate with the syntax: x = &o.func; and then using the context to figure out which overloaded func it should be. This does add some complexity to the compiler I don't like.
Apr 05 2002
Walter wrote:I had the same thought, but I still haven't figured out what to do in ambiguous cases like: void foo(char[]); void foo(wchar[]); ... foo("hello"); Which gets called? Should it be an error?
Hey, I'm not following the discussion of delegates too closely, but I've got an opinion on this one. I'd want a warning on that so as to avoid consequences of calling the wrong one; since you don't believe in warnings, it should be an error. -RB
Apr 05 2002
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3CADE8E0.1070307 estarcion.com...I'd want a warning on that so as to avoid consequences of calling the wrong one; since you don't believe in warnings, it should be an error.
Imagine: class Stream { void write(char[] s) { ... } void write(wchar[] s) { ... } } That's right, two versions, because you might want to feed char[] or wchar[] variable to it. Now, you write: stdout.write("Hello, world!"); And get the compiler error, 'cause you must do: stdout.write(cast(char[]) "Hello, world!"); You like it?
Apr 05 2002
Pavel Minayev wrote:"Russell Borogove" <kaleja estarcion.com> wrote in message news:3CADE8E0.1070307 estarcion.com...I'd want a warning on that so as to avoid consequences of calling the wrong one; since you don't believe in warnings, it should be an error.
Imagine: class Stream { void write(char[] s) { ... } void write(wchar[] s) { ... } } That's right, two versions, because you might want to feed char[] or wchar[] variable to it. Now, you write: stdout.write("Hello, world!"); And get the compiler error, 'cause you must do: stdout.write(cast(char[]) "Hello, world!"); You like it?
This language design thing is hard. :) Like you, I'd have to lean towards differentiating char and wchar literals, or default to char unless there's a \uXXXX in there somewhere. The latter might give rise to the (ugly) idiom: "Hello world!\u0000" to force wide char literal strings. Sidethread, you complain about the L"literal" syntax as ugly, but it's far less ugly than the cast. -R
Apr 05 2002
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3CADFE2F.4070502 estarcion.com...This language design thing is hard. :) Like you, I'd have to lean towards differentiating char and wchar literals, or default to char unless there's a \uXXXX in there somewhere. The latter might give rise to the (ugly) idiom: "Hello world!\u0000" to force wide char literal strings.
It isn't proper way since D strings are not 0-terminated, so if you print it, the null char will be printed as well, I guess. But still the idea is interesting. The compiler should be able to determine whether string is char or wchar on his own. Also, if you have function overloaded for both, then it's not very likely that you have to force wchar literals, since char version would do exactly the same (e.g. print the string).Sidethread, you complain about the L"literal" syntax as ugly, but it's far less ugly than the cast.
Yep, right. But still, L is hard to parse and to distinguish. I think that suffix would be better, "w" or something: "Hello, world!"W
Apr 05 2002
Pavel Minayev wrote:"Russell Borogove" <kaleja estarcion.com> wrote in message news:3CADFE2F.4070502 estarcion.com...This language design thing is hard. :) Like you, I'd have to lean towards differentiating char and wchar literals, or default to char unless there's a \uXXXX in there somewhere. The latter might give rise to the (ugly) idiom: "Hello world!\u0000" to force wide char literal strings.
It isn't proper way since D strings are not 0-terminated, so if you print it, the null char will be printed as well, I guess.
Ohhh, crap. Well, I lobbied for padding (at least char and wchar) arrays with an extra zero-valued element to make conversion to C-strings easier way back when, but noooooooo....But still the idea is interesting. The compiler should be able to determine whether string is char or wchar on his own. Also, if you have function overloaded for both, then it's not very likely that you have to force wchar literals, since char version would do exactly the same (e.g. print the string).
I can contrive cases where the char and wchar versions do sufficiently different things (e.g. render from a 100KB TrueType font versus render from a 20MB TrueType font) that the impact would be significant, but even such cases aren't catastrophic. As you point out, the numeric promotions and conversions are probably more troublesome. -RB
Apr 05 2002
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3CAE8210.4020908 estarcion.com...Ohhh, crap. Well, I lobbied for padding (at least char and wchar) arrays with an extra zero-valued element to make conversion to C-strings easier way back when, but noooooooo....
Actually, D does 0 terminate them when it can, for just that reason. But if you slice an array out of another char[], it won't be 0 terminated.
Apr 05 2002
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3CAE8210.4020908 estarcion.com...Ohhh, crap. Well, I lobbied for padding (at least char and wchar) arrays with an extra zero-valued element to make conversion to C-strings easier way back when, but noooooooo....
Literals are terminated with 0 in memory. However, 0 is not considered element of the array: "foo" -> 'f', 'o', 'o', 0 "foo".length == 3;
Apr 06 2002
"Pavel Minayev" <evilone omen.ru> wrote in message news:a8mk4r$n0q$1 digitaldaemon.com..."Russell Borogove" <kaleja estarcion.com> wrote in message news:3CAE8210.4020908 estarcion.com...Ohhh, crap. Well, I lobbied for padding (at least char and wchar) arrays with an extra zero-valued element to make conversion to C-strings easier way back when, but noooooooo....
Literals are terminated with 0 in memory. However, 0 is not considered element of the array: "foo" -> 'f', 'o', 'o', 0 "foo".length == 3;
That's right. It's a bit of a hack, but a hack that works for the most common cases, like passing a string literal to printf!
Apr 06 2002
"Walter" <walter digitalmars.com> wrote in message news:a8nalt$1fsi$1 digitaldaemon.com...Literals are terminated with 0 in memory. However, 0 is not considered element of the array: "foo" -> 'f', 'o', 'o', 0 "foo".length == 3;
That's right. It's a bit of a hack, but a hack that works for the most common cases, like passing a string literal to printf!
It's also great when interfacing with APIs and such. Well, it just works, and variables can always be converted using toStringz().
Apr 06 2002
"Walter" <walter digitalmars.com> wrote in message news:a8kn36$2hic$1 digitaldaemon.com...I had the same thought, but I still haven't figured out what to do in ambiguous cases like: void foo(char[]); void foo(wchar[]); ... foo("hello"); Which gets called? Should it be an error?
I guess it shouldn't. The reason is, you will probably define a wchar version for each string-handling function, and if it was considered an error, you wouldn't be able to call those functions with literals as arguments - which is convenient sometimes. I'd personally suggest to make some way to differentiate between char and wchar literals (but not that ugly L"..."!).In any case, I'm leaning towards initializing a delegate with the syntax: x = &o.func; and then using the context to figure out which overloaded func it should
This does add some complexity to the compiler I don't like.
Well if function is NOT overloaded (which will most likely be the case), what's the sense of specifying parameters explicitly? Also, even for overloaded functions, I think the & syntax is better: x = &o.func(int, int);
Apr 05 2002









"J. Daniel Smith" <j_daniel_smith HoTMaiL.com> 