digitalmars.D - pointers-to-members, (custom) array implementation
- Wolfgang Draxinger (95/95) Feb 07 2007 I'm currently in a discussion D vs. C++ and in some points I must
- Jarrett Billingsley (38/49) Feb 07 2007 It's not quite as elegant as pointers-to-members, but it's something:
- Wolfgang Draxinger (60/63) Feb 08 2007 I didn't neglegt the possibility of some hack to get the very
- BCS (17/37) Feb 07 2007 I'd have to check but I think this works
- Jarrett Billingsley (9/23) Feb 07 2007 Nope. Not only can you not use alias parameters in that way (they have ...
- Frits van Bommel (19/25) Feb 08 2007 Try these (off the top of my head):
- Jarrett Billingsley (5/18) Feb 08 2007 This one works just fine :)
- Frits van Bommel (5/15) Feb 08 2007 [snip second]
- Jarrett Billingsley (3/5) Feb 08 2007 You know, I wasn't trying to be a dick.
- Wolfgang Draxinger (6/26) Feb 08 2007 Works but is IMHO not very elegant. Make PtM a language feature
- Bill Baxter (6/31) Feb 08 2007 No, it does not work. &Pt2Mem!(one) gives a 'what's "one"?' error.
- Wolfgang Draxinger (6/11) Feb 08 2007 I buy a "If it" before the "Works"... I've hit the submit button
- Sean Kelly (4/25) Feb 08 2007 Huh. I had no idea that free functions could be called this way with a
- Frits van Bommel (2/27) Feb 08 2007 Either you're being sarcastic or you didn't even _try_ to compile that.....
- Sean Kelly (3/31) Feb 08 2007 The latter :-)
I'm currently in a discussion D vs. C++ and in some points I must admit, that the other side has some point, I must admit, too: Pointers to members are a feature that D currently lacks, but sometimes they are quite usefull and can't be replaced by delegates. E.g. say you got a class "foo" which has several member functions of the same prototype and several member variables. Now you want to write some function that performs some action on the class, but is not fixed on certain members. That function would accept the instance of a class, and pointers-to-members as parameters. The whole thing could be used in a foreach loop. For the member variables one could use the .offset property to supply their offset address relative to the class instance address, but for member functions emulating such functionality would be quite a hack. I think that pointers-to-members are as important as delegates. Another point they claim is, that having the full implementation for dynamic and associative arrays within the _language itself_ is not clean. Instead the language should define a universal interface for dynamic array classes. I'm thinking of the following ways, how to specify a custom array class implementation: type[] foo = new!(My_Array) type[]; i.e. new is a template creating a instance of My_Array, calling that's constructor with the apropriate values (I come to that later). Normally new defaults to the builtin class Array (just like Object is a builtin class). I don't have a clear idea yet how this should interface with class allocators, but one solution would be, that a custom array class should use that allocator for memory allocation instead of the array class default's. But an array class should be allowed to override that request. Since pragmatic programmers are lazy programmers it should also be possible to define a array class for a whole scope. A pragma that affects the current scope and all subscope would be fine, e.g. pragma([], My_Array); if a custom array class is desired only for specific types pragma(type[], My_TypeArray); And of course multiple pragmas should be possible, as long the override is not ambigous. However within one scope only one pragma per Type is allowed, but a subscope may override again. This is a point where pointers-to-members would come in handy: Since a resizing of the array possibly requires constructors to be called the C++ approach on dynamic arrays is templates. But actually managing an array one requires the size of each element, stride, length and amount of allocated memory. Only constructor and destructor calling is a type specific. But here can pointers-to-members help. For each class a pointer-to-member to the constructor function is created. A Array class then can use that pointer to member to call the constructor for newly allocated classes. Of course only the (eventually not present) default constructor would be called, after the elements contents would have been initialized. A custom Array class constructor must accept the following parameters then: The beginning length of the array, the total amount of memory to allocate (this is to allow the compiler to tell the Array class, that more memory is needed for elements appended in the following code), a pointer to TypeInfo, a pointer to ClassInfo; the ClassInfo has the pointer-to-member of the constructor and the initializer data, the TypeInfo contains information about size and alignment for one element. To designate pointer-to-members the following might be apropriate: class foo { int bar; char*[] spam; void eggs(int); }; foo.*int a; // a is a pointer to a int member of foo foo.*char*[] b; // b is a pointer to an array of pointers to char member of foo foo.*void function(int) c; // c is a pointer to a member function taking an int To get a pointer-to-member the following syntax might be usable a = foo.&bar; b = foo.&spam; c = foo.&eggs; Using the pointers-to-members is consistent with normal pointer syntax: Normal pointers are designated by '*' and dereferenced by '*', too. The address is retrieved by '&'. By prepending the member operator '.' ".*" can be read right to left (which is the way types get defined) as "pointer (to) member", and also as "dereference member". Similairily ".&" can be read as "get address of member". So dereferencing would be written as: foo TheFoo = new foo; TheFoo.*a = 5; printf(TheFoo.*b[3]); TheFoo.*c(10); which is consistent with C++ syntax. Wolfgang Draxinger -- E-Mail address works, Jabber: hexarith jabber.org, ICQ: 134682867
Feb 07 2007
"Wolfgang Draxinger" <wdraxinger darkstargames.de> wrote in message news:uoaq94-f0c.ln1 darkstargames.dnsalias.net...I'm currently in a discussion D vs. C++ and in some points I must admit, that the other side has some point, I must admit, too: Pointers to members are a feature that D currently lacks, but sometimes they are quite usefull and can't be replaced by delegates. E.g. say you got a class "foo" which has several member functions of the same prototype and several member variables. Now you want to write some function that performs some action on the class, but is not fixed on certain members. That function would accept the instance of a class, and pointers-to-members as parameters. The whole thing could be used in a foreach loop.It's not quite as elegant as pointers-to-members, but it's something: class A { static A members; static this() { members = new A(); } int fork() { return 1; } int knife() { return 2; } } void func(A a, int delegate()[] members...) { foreach(member; members) { member.ptr = a; writefln(member()); } } void main() { A a = new A(); func(a, &A.members.fork, &A.members.knife); } The ugly parts are (1) having to create an instance of A in order to get the offsets of the member functions (the static 'members' variable) and (2) having to set the delegate .ptr before calling it, rather than just calling something like "a.*member()". I think pointers-to-members have a bad reputation but I agree that they can be really useful in some cases.
Feb 07 2007
Jarrett Billingsley wrote:It's not quite as elegant as pointers-to-members, but it's something: [some hack]I didn't neglegt the possibility of some hack to get the very same behaviour. The most ugly variant is possibly the following (and that works only in some ABI): class Foo { int bar(char[]); }; int function(Foo*, char[]) spam; spam = cast(int function(Foo*, char[])cast(void*)&Foo.bar; void eggs() { Foo foobar = new Foo; spam(&foobar, "spam'n'eggs"); } In some ABIs this actually works, and it't e.g. the way one uses DirectX from languages, that don't have interfaces/classes. But it's ugly and D is all about elegance IMHO. So I think as of one the next versions D should pointer to members. Those don't break anything, the language remains orthogonal (since PtM fill a gap, that one currently has to fill with a hack). There are also other things _I_ miss and that woudn't really hurt, to have in D. For example bitfields. Currently the best way to emulate them is a struct having some static array of required length and properties to get/set the values. Eventually a new stucture type "bitfield" may be introduced with some special rules. E.g. within a bitfield there can be declared no variables by basic types. One can only specify if a certain variable is to be treated signed or unsigned and the amount of bits it consumes. And there should be some way to define padding. Bitfields should align and the gap to the next alignment boundary should be consumed, too. And bitfields cannot stand for themself and must always be embedded into a struct or union. e.g. struct bar { bitfield { unsigned flags: 5; signed offset: 4; void: 5; // pad 5 bits. unsigned count: 15; }; // assume a 4 byte aligning, the bitfield // will consume another 3 bits to fill up }; Since nesting rules apply the members of the annonymous nested bitfield can be accessed like bar.flags = 1 | 2 | 8; bar.offset = -10; bar.count = 10000; There are some libraries, e.g. SDL, that use bitfields extensivly. Having them in the language would be very, very nice. I'm not about featureitis, but elegance. As soon as a language requires me to use some hack, to achieve my goal it doesn't seem elegant to me. Wolfgang Draxinger -- E-Mail address works, Jabber: hexarith jabber.org, ICQ: 134682867
Feb 08 2007
Wolfgang Draxinger wrote:I'm currently in a discussion D vs. C++ and in some points I must admit, that the other side has some point, I must admit, too: Pointers to members are a feature that D currently lacks, but sometimes they are quite usefull and can't be replaced by delegates. E.g. say you got a class "foo" which has several member functions of the same prototype and several member variables. Now you want to write some function that performs some action on the class, but is not fixed on certain members. That function would accept the instance of a class, and pointers-to-members as parameters. The whole thing could be used in a foreach loop. For the member variables one could use the .offset property to supply their offset address relative to the class instance address, but for member functions emulating such functionality would be quite a hack. I think that pointers-to-members are as important as delegates.I'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1); The tail recursion should get optimized away and maybe even the first call in some cases.
Feb 07 2007
"BCS" <BCS pathlink.com> wrote in message news:eqe3gf$159e$4 digitaldaemon.com...I'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1);Nope. Not only can you not use alias parameters in that way (they have to be a declared symbol, not just an arbitrary identifier), but you also can't call "obj.anything()" like "c.fn(1)". I was hoping it might be possible to use mixin() to create an arbitrary identifier, but unfortunately: c.mixin("one")(i); doesn't compile.
Feb 07 2007
Jarrett Billingsley wrote:I was hoping it might be possible to use mixin() to create an arbitrary identifier, but unfortunately: c.mixin("one")(i); doesn't compile.Try these (off the top of my head): --- int Pt2Mem!(char[] go)(C c, int i) { return mixin("c." ~ go ~ "(i)"); } --- or: --- int Pt2Mem!(char[] go)(C c, int i) { mixin("return c." ~ go ~ "(i)"); } --- IIRC you can only mixin complete expressions, statements or declarations[1]. Declarations aren't really useful here, but expressions and statements should work... [1]: Well, and templates, but that doesn't work with strings.
Feb 08 2007
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message news:eqess1$2ito$1 digitaldaemon.com...Try these (off the top of my head): --- int Pt2Mem!(char[] go)(C c, int i) { return mixin("c." ~ go ~ "(i)"); }This one works just fine :)or: --- int Pt2Mem!(char[] go)(C c, int i) { mixin("return c." ~ go ~ "(i)"); } ---This one has to have a semicolon at the end of the string, since the mixin statement strings have to be complete statements. But this works too.
Feb 08 2007
Jarrett Billingsley wrote:"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message news:eqess1$2ito$1 digitaldaemon.com...[snip first]Try these (off the top of my head):This one works just fine :)[snip second]or:This one has to have a semicolon at the end of the string, since the mixin statement strings have to be complete statements. But this works too.You read that first sentence, right? (especially the parenthesized part) That was a warning I didn't actually compile these :P.
Feb 08 2007
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message news:eqfj04$e65$1 digitaldaemon.com...You read that first sentence, right? (especially the parenthesized part) That was a warning I didn't actually compile these :P.You know, I wasn't trying to be a dick.
Feb 08 2007
BCS wrote:I'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1);Works but is IMHO not very elegant. Make PtM a language feature and it's get a lot more readable. I don't like it. Wolfgang Draxinger -- E-Mail address works, Jabber: hexarith jabber.org, ICQ: 134682867
Feb 08 2007
Wolfgang Draxinger wrote:BCS wrote:No, it does not work. &Pt2Mem!(one) gives a 'what's "one"?' error. And the c.fn part gives a 'no such member "fn"' error. But if it did work I think it would be a pretty reasonably elegant way to do it. :-) --bbI'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1);Works but is IMHO not very elegant. Make PtM a language feature and it's get a lot more readable. I don't like it.
Feb 08 2007
Bill Baxter wrote:I buy a "If it" before the "Works"... I've hit the submit button a bit too early. Wolfgang Draxinger -- E-Mail address works, Jabber: hexarith jabber.org, ICQ: 134682867Works but is IMHO not very elegant. Make PtM a language feature and it's get a lot more readable. I don't like it.No, it does not work. &Pt2Mem!(one) gives a 'what's "one"?' error. And the c.fn part gives a 'no such member "fn"' error.
Feb 08 2007
BCS wrote:I'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1);Huh. I had no idea that free functions could be called this way with a class as the first parameter. I thought it only worked for arrays. Sean
Feb 08 2007
Sean Kelly wrote:BCS wrote:Either you're being sarcastic or you didn't even _try_ to compile that...I'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1);Huh. I had no idea that free functions could be called this way with a class as the first parameter. I thought it only worked for arrays.
Feb 08 2007
Frits van Bommel wrote:Sean Kelly wrote:The latter :-) SeanBCS wrote:Either you're being sarcastic or you didn't even _try_ to compile that...I'd have to check but I think this works class C { int one(int i){...} int two(int i){...} int three(int i){...} } int Pt2Mem!(alias go)(C c, int i) { return c.go(i); } auto fn = &Pt2Mem!(one); C c = new C; c.fn(1);Huh. I had no idea that free functions could be called this way with a class as the first parameter. I thought it only worked for arrays.
Feb 08 2007