digitalmars.D - division of objects into classes and structures is bad
- Weed (144/144) Dec 28 2008 (Forgive, again I will mention the patient for me a theme)
- Denis Koroskin (5/149) Dec 28 2008 If that's your use case, then your should seriosly reconsider using stru...
- Weed (28/62) Dec 29 2008 Classes always give such overhead if them to use in such quality. For
- Don (4/78) Dec 29 2008 Use classes if you want polymorphism. Otherwise, use structs. It's a
- Weed (7/86) Dec 30 2008 And if polymorphism is necessary and such calculations are necessary as
- Weed (3/85) Dec 30 2008 To solve a problem it is possible having allowed to transfer classes on
- Don (51/133) Dec 30 2008 I agree with you that there's a problem, but I think you're wrong about
- Weed (24/171) Dec 30 2008 Nothing can be done with it in any case.
- Christopher Wright (9/12) Dec 30 2008 The easiest way is to add an intermediate struct. This takes a fair bit
- Don (5/19) Dec 30 2008 That particular case is the easiest possible one. The case x = y - x,
- Andrei Alexandrescu (5/28) Dec 30 2008 Don't forget that the case you are solving is not general enough because...
- Don (4/32) Dec 30 2008 Yes. That's the classic problem for matrices, but I'm still trying to
- Andrei Alexandrescu (8/42) Dec 30 2008 I think the matrices case is important enough to make it its own class
- Bill Baxter (11/54) Dec 30 2008 Graph algorithms can often be thought of as matrices too.
- Andrei Alexandrescu (4/49) Dec 30 2008 Any graph algorithm that uses e.g. the adjacency matrix... well, uses a
- Don (9/51) Dec 31 2008 Yes, bitmap processing almost always uses the adjacent pixels, which
- Andrei Alexandrescu (6/88) Dec 30 2008 There is a niche of cases where using the C++-style duality of classes
- Weed (13/105) Dec 30 2008 It is very a pity.
- Andrei Alexandrescu (12/24) Dec 30 2008 It's attractive to deal in absolutes, but also dangerous. When C came
- bearophile (4/7) Dec 30 2008 But probably C compilers (and JavaVirtualMachines) have improved from th...
- Walter Bright (2/6) Jan 01 2009 Not that much smaller.
- Weed (14/40) Dec 30 2008 Can in C# (it uses as far as I know too such sharing) such approach and
- Weed (3/53) Dec 30 2008 For example prohibit assigning on value to the types, not being base or
- Weed (3/46) Jan 04 2009 Who agrees with me? There are still ideas as it is possible to solve
- Weed (2/48) Jan 05 2009 And against arguments are still necessary
- Christopher Wright (16/18) Jan 05 2009 When you reply to your reply to your reply to your post and nobody else
- Weed (13/35) Jan 05 2009 D2.0 not released, it changes supplemented. I seriously consider at it
- Bill Baxter (25/44) Jan 05 2009 My problem is more that I just can't understand the guy so I don't
- Weed (20/20) Jan 06 2009 (Here I generalise my sentence with supplement)
- Weed (2/28) Jan 07 2009
- Weed (7/37) Jan 09 2009 Tell, what it is necessary to make that discussion of this question has
- Denis Koroskin (34/74) Jan 09 2009 I'll explain here what *I* think about.
- Weed (22/56) Jan 10 2009 This way does not approach because scope value is impossible to return
- Weed (5/7) Jan 10 2009 The extra-short formulation of my idea:
- Christopher Wright (13/23) Jan 10 2009 The reference versus value type difference is just a matter of defaults.
- Weed (8/35) Jan 10 2009 Problem not only with constructor calling.
- Bill Baxter (13/37) Jan 10 2009 I don't think that does what you think it does.
- Bill Baxter (58/72) Jan 10 2009 No it's not. scope MyClass does not make a MyClass that works like a
- Weed (5/11) Jan 10 2009 It is not always a good thing.
- Bill Baxter (22/32) Jan 10 2009 Yeh, I just mean there is some merit in disabling value copies. But I
- Weed (33/70) Jan 10 2009 It can lead to a difficult and non-reproduceable errors than old
- Denis Koroskin (6/78) Jan 10 2009 Having the same syntax for both classes and struct is a nice goal, I agr...
- Weed (27/123) Jan 11 2009 (I have incorrectly expressed)
- Weed (16/27) Jan 11 2009 I guess allocation in Java occurs fast because of usage of the its own
- Andrei Alexandrescu (5/32) Jan 11 2009 Meh, that should be taken with a grain of salt. An allocator that only
- Brad Roberts (8/42) Jan 11 2009 Take it as nicely seasoned. The current jvm gc and memory subsystem is
- Andrei Alexandrescu (10/49) Jan 12 2009 I understand. My point is that a 10-cycles-per-allocation allocator will...
- Weed (5/57) Jan 12 2009 In any case, we cannot add such memory manager in D. And such resource
- Bill Baxter (24/81) Jan 12 2009 n
- Andrei Alexandrescu (6/14) Jan 12 2009 Interesting. (Link?) Structs in D are supposed to be location
- Denis Koroskin (2/16) Jan 12 2009 If the compiler can show the address of a struct is not taken, it should...
- Bill Baxter (16/31) Jan 12 2009 The message doesn't appear to have come up on the list archive yet,
- John Reimer (14/108) Jan 12 2009 Recently, I started looking into garbage collection theory. Of course, ...
- Brad Roberts (7/26) Jan 12 2009 And wouldn't ya know it.. I spent parts of saturday pondering on exactly...
- Benji Smith (11/45) Jan 12 2009 Actually, memory allocated in the JVM is very cache-friendly, since two
- Andrei Alexandrescu (13/17) Jan 12 2009 Well the problem is that the allocation size grows quickly. Allocate and...
- Benji Smith (11/33) Jan 12 2009 Good point. I remember five years ago when people were buzzing about the...
- Daniel Keep (24/30) Jan 12 2009 import javax.actions.aquatic.jumper.*;
- Daniel de Kok (5/8) Jan 14 2009 On Tue, Jan 13, 2009 at 7:30 AM, Daniel Keep
- Weed (2/70) Jan 15 2009 And any remark on the sentence?..
- Bill Baxter (5/25) Jan 09 2009 Your English is really hard to make sense of.
- Weed (3/9) Jan 10 2009 All is absolutely poor? If not everything, can you select that demands
- downs (2/11) Jan 12 2009 Translation: Is it all bad? Otherwise, can you say what you want clarifi...
- noobie (2/3) Jan 13 2009 http://sourceforge.net/mailarchive/forum.php?thread_name=e8fc97ba0901111...
(Forgive, again I will mention the patient for me a theme) About why I consider that division of objects into classes and structures is bad. If the object is a class that there will be additional overhead charge at calculation of expressions with this class because it is impossible to allocate a class instance on a stack and transfer it as result to next function. Example with usage of the overloaded function opAdd: //=================== import std.stdio; class C { int i; C opAdd( C src ) { auto ret = new C; ret.i = i + src.i; return ret; } } void main() { auto c1 = new C; c1.i = 1; auto c2 = c1 + c1 + c1; writeln( c2.i ); } //=================== auto c2 = c1 + c1 + c1; // calculated as: auto c2 = c1.opAdd( c1 ).opAdd( c1 ); The temporary result of opAdd in this expression is located in heap (i.e. with overhead), and only then the reference to it is transferred in the second function opAdd: assume CS:_D4test1C5opAddMFC4test1CZC4test1C L0: push EAX push EBX push offset FLAT:_D4test1C7__ClassZ call near ptr __d_newclass mov EBX,EAX mov EAX,8[ESP] mov ECX,8[EAX] mov EDX,010h[ESP] add ECX,8[EDX] mov 8[EBX],ECX add ESP,4 mov EAX,EBX pop EBX pop ECX ret 4 _D4test1C5opAddMFC4test1CZC4test1C ends __Dmain comdat assume CS:__Dmain L0: push EBX push offset FLAT:_D4test1C7__ClassZ call near ptr __d_newclass mov EBX,EAX mov dword ptr 8[EBX],1 add ESP,4 push EBX push EBX mov EAX,EBX mov ECX,[EBX] call dword ptr 014h[ECX] mov EDX,[EAX] call dword ptr 014h[EDX] mov EAX,8[EAX] pop EBX ret __Dmain ends opAdd is called two times (call dword ptr 014h[ECX] and call dword ptr 014h[EDX]). Objects created in heap (call near ptr __d_newclass). There is created two objects and the first of them is temporary. Now we will consider the same example with usage of the object of structure which allows allocation on a stack: //=================== struct C { int i; int[100] j; // to prevent returning this struct in registers C opAdd( C src ) { C ret; ret.i = i + src.i; return ret; } } int main() { C c1; // initialise i by "random" value to prevent compile-time calculation c1.i = cast(int)&c1; auto c2 = c1 + c1 + c1; return c2.i; } //=================== In this case the compiler easily detects that returned value is allocated in a stack and to transfer it in the following function of anything it is not necessary to do - enough to leave it in a stack (linux objdump output): struct C { int i; int[100] j; // to prevent returning this struct in register C opAdd( C src ) { ... C ret; 8049075: b9 65 00 00 00 mov $0x65,%ecx 804907a: 31 c0 xor %eax,%eax 804907c: 8b 7d 08 mov 0x8(%ebp),%edi 804907f: f3 ab rep stos %eax,%es:(%edi) ret.i = i + src.i; 8049081: 8b 8d 5c fe ff ff mov -0x1a4(%ebp),%ecx 8049087: 8b 11 mov (%ecx),%edx 8049089: 03 55 0c add 0xc(%ebp),%edx 804908c: 8b 5d 08 mov 0x8(%ebp),%ebx 804908f: 89 13 mov %edx,(%ebx) 8049091: 8b 45 08 mov 0x8(%ebp),%eax 8049094: 5f pop %edi 8049095: 5b pop %ebx 8049096: c9 leave 8049097: c2 98 01 ret $0x198 804909a: 90 nop 804909b: 90 nop } } int main() { ... auto c2 = c1 + c1 + c1; 80490c3: 8d 9d bc fc ff ff lea -0x344(%ebp),%ebx 80490c9: b9 65 00 00 00 mov $0x65,%ecx 80490ce: ff 33 pushl (%ebx) 80490d0: 83 eb 04 sub $0x4,%ebx 80490d3: e2 f9 loop 80490ce <_Dmain+0x32> 80490d5: 8d 95 cc fc ff ff lea -0x334(%ebp),%edx 80490db: 52 push %edx 80490dc: 8d b5 bc fc ff ff lea -0x344(%ebp),%esi 80490e2: b1 65 mov $0x65,%cl 80490e4: ff 36 pushl (%esi) 80490e6: 83 ee 04 sub $0x4,%esi 80490e9: e2 f9 loop 80490e4 <_Dmain+0x48> 80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn out
Dec 28 2008
On Mon, 29 Dec 2008 01:05:15 +0300, Weed <resume755 mail.ru> wrote:(Forgive, again I will mention the patient for me a theme) About why I consider that division of objects into classes and structures is bad. If the object is a class that there will be additional overhead charge at calculation of expressions with this class because it is impossible to allocate a class instance on a stack and transfer it as result to next function. Example with usage of the overloaded function opAdd: //=================== import std.stdio; class C { int i; C opAdd( C src ) { auto ret = new C; ret.i = i + src.i; return ret; } } void main() { auto c1 = new C; c1.i = 1; auto c2 = c1 + c1 + c1; writeln( c2.i ); } //=================== auto c2 = c1 + c1 + c1; // calculated as: auto c2 = c1.opAdd( c1 ).opAdd( c1 ); The temporary result of opAdd in this expression is located in heap (i.e. with overhead), and only then the reference to it is transferred in the second function opAdd: assume CS:_D4test1C5opAddMFC4test1CZC4test1C L0: push EAX push EBX push offset FLAT:_D4test1C7__ClassZ call near ptr __d_newclass mov EBX,EAX mov EAX,8[ESP] mov ECX,8[EAX] mov EDX,010h[ESP] add ECX,8[EDX] mov 8[EBX],ECX add ESP,4 mov EAX,EBX pop EBX pop ECX ret 4 _D4test1C5opAddMFC4test1CZC4test1C ends __Dmain comdat assume CS:__Dmain L0: push EBX push offset FLAT:_D4test1C7__ClassZ call near ptr __d_newclass mov EBX,EAX mov dword ptr 8[EBX],1 add ESP,4 push EBX push EBX mov EAX,EBX mov ECX,[EBX] call dword ptr 014h[ECX] mov EDX,[EAX] call dword ptr 014h[EDX] mov EAX,8[EAX] pop EBX ret __Dmain ends opAdd is called two times (call dword ptr 014h[ECX] and call dword ptr 014h[EDX]). Objects created in heap (call near ptr __d_newclass). There is created two objects and the first of them is temporary. Now we will consider the same example with usage of the object of structure which allows allocation on a stack: //=================== struct C { int i; int[100] j; // to prevent returning this struct in registers C opAdd( C src ) { C ret; ret.i = i + src.i; return ret; } } int main() { C c1; // initialise i by "random" value to prevent compile-time calculation c1.i = cast(int)&c1; auto c2 = c1 + c1 + c1; return c2.i; } //=================== In this case the compiler easily detects that returned value is allocated in a stack and to transfer it in the following function of anything it is not necessary to do - enough to leave it in a stack (linux objdump output): struct C { int i; int[100] j; // to prevent returning this struct in register C opAdd( C src ) { ... C ret; 8049075: b9 65 00 00 00 mov $0x65,%ecx 804907a: 31 c0 xor %eax,%eax 804907c: 8b 7d 08 mov 0x8(%ebp),%edi 804907f: f3 ab rep stos %eax,%es:(%edi) ret.i = i + src.i; 8049081: 8b 8d 5c fe ff ff mov -0x1a4(%ebp),%ecx 8049087: 8b 11 mov (%ecx),%edx 8049089: 03 55 0c add 0xc(%ebp),%edx 804908c: 8b 5d 08 mov 0x8(%ebp),%ebx 804908f: 89 13 mov %edx,(%ebx) 8049091: 8b 45 08 mov 0x8(%ebp),%eax 8049094: 5f pop %edi 8049095: 5b pop %ebx 8049096: c9 leave 8049097: c2 98 01 ret $0x198 804909a: 90 nop 804909b: 90 nop } } int main() { ... auto c2 = c1 + c1 + c1; 80490c3: 8d 9d bc fc ff ff lea -0x344(%ebp),%ebx 80490c9: b9 65 00 00 00 mov $0x65,%ecx 80490ce: ff 33 pushl (%ebx) 80490d0: 83 eb 04 sub $0x4,%ebx 80490d3: e2 f9 loop 80490ce <_Dmain+0x32> 80490d5: 8d 95 cc fc ff ff lea -0x334(%ebp),%edx 80490db: 52 push %edx 80490dc: 8d b5 bc fc ff ff lea -0x344(%ebp),%esi 80490e2: b1 65 mov $0x65,%cl 80490e4: ff 36 pushl (%esi) 80490e6: 83 ee 04 sub $0x4,%esi 80490e9: e2 f9 loop 80490e4 <_Dmain+0x48> 80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects. Alternatively, you can use += instead. Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations. Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right. Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.
Dec 28 2008
Denis Koroskin ÐÉÛÅÔ:Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 29 2008
Weed wrote:Denis Koroskin ÐÉÛÅÔ:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 29 2008
Don ÐÉÛÅÔ:Weed wrote:And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses? I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).Denis Koroskin ÐÉÛÅÔ:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 30 2008
Weed ÐÉÛÅÔ:Don ÐÉÛÅÔ:To solve a problem it is possible having allowed to transfer classes on value (checking during compilation that has not occurred slicing)Weed wrote:And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses? I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).Denis Koroskin ÐÉÛÅÔ:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 30 2008
Weed wrote:Don ÐÉÛÅÔ:I agree with you that there's a problem, but I think you're wrong about the solution. C++ suffers from severe problems with creation of temporaries in expressions. The problem occurs whenever you have heap allocations inside an object which does operator overloading. Sure, in the simple case you mentioned, using a struct works because the size of the data is small. But it general, it's not possible to avoid the heap allocation, and so in C++ you'll still have a problem. The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago: http://d.puremagic.com/issues/show_bug.cgi?id=124 c2 = c1 + c1 + c1; would be transformed into t1 = c1 + c1; t1.opAddAssign(c1); c2 = t1; which gets rid of the temporary heap allocation. I don't think you could ever get rid of the heap allocation for c2 since (a) c2 might be null, initially; and (b) c2 might be pointing to the same place as c1. Nonetheless, I'd like to do better than this. Consider: C c1, c2, c3; c3 = c1*5 + c2/6; The optimal solution depends on whether in-place operations are possible or not. Interestingly, X+=Y is more efficient than X=X+Y only if in-place operations are possible; there's no point in defining it if in-place is impossible. Case 1: in-place operations are possible, += exists. All operators include destination. Convert to t1 = c2/6; c3 = c1*5; c3+=t1; --- LocalHeap h; t1 = h.new(C); // create on LocalHeap h t1.operatorWithDestination("/")(c2, 6); C t2 = new C; // create on heap t2.operatorWithDestination!("*")(c1, 5); c3 = t2.operatorAssign!("+")(t1); // in-place += operation on heap h.releaseAll; --- Case 2: in-place operations are impossible, += doesn't exist. --- LocalHeap h; t1 = c1.operatorTemporary!("*")(5, h); // create on local heap t2 = c2.operatorTemporary!("/")(6, h); // create on local heap c3 = t1.operator!("+")(t2); // create on heap h.releaseAll; --- It's far too complicated at present to be workable, but that's the basic idea.Weed wrote:And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses? I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).Denis Koroskin ÐÉÛÅÔ:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 30 2008
Don ÐÉÛÅÔ:Weed wrote:Nothing can be done with it in any case. If the class uses in itself dynamic allocation through "new" that this memory will be allocated in a heap. But time in a class is used such way of allocation that for this purpose there are reasons.Don ÐÉÛÅÔ:I agree with you that there's a problem, but I think you're wrong about the solution. C++ suffers from severe problems with creation of temporaries in expressions. The problem occurs whenever you have heap allocations inside an object which does operator overloading.Weed wrote:And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses? I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).Denis Koroskin ÐÉÛÅÔ:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.Sure, in the simple case you mentioned, using a struct works because the size of the data is small.No. Structure used only because it is the type transferred on value in D.But it general, it's not possible to avoid the heap allocation, and so in C++ you'll still have a problem. The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago: http://d.puremagic.com/issues/show_bug.cgi?id=124 c2 = c1 + c1 + c1; would be transformed into t1 = c1 + c1; t1.opAddAssign(c1); c2 = t1; which gets rid of the temporary heap allocation. I don't think you could ever get rid of the heap allocation for c2 since (a) c2 might be null, initially;In this case opAdd returns the result object to which the name c2 will be assigned.and (b) c2 might be pointing to the same place as c1.There will be the same as (a). If it is necessary to equate to the existing object (for example that it did not change the position in memory) it is possible to overload that the operator [] = and to make so: c2 [] = c1 + c1 + c1;Nonetheless, I'd like to do better than this. Consider: C c1, c2, c3; c3 = c1*5 + c2/6; The optimal solution depends on whether in-place operations are possible or not. Interestingly, X+=Y is more efficient than X=X+Y only if in-place operations are possible; there's no point in defining it if in-place is impossible.There can be I something do not understand, but the decision should be more the general than optimization of an overload of operators. Eventually, the overload of operators is simply syntactic sugar. I used them simply as an example. It is possible to think up other example where there is no overload: space_ship_1.calculatePathTo("Moon").getCheckpoint(3).getCoords; In this example we create a temporary class "path", create temporary class "checkpoint" and we take coords of checkpoint of this path. It is not expedient to us to store all this path and checkpoint because it is vary.Case 1: in-place operations are possible, += exists. All operators include destination. Convert to t1 = c2/6; c3 = c1*5; c3+=t1; --- LocalHeap h; t1 = h.new(C); // create on LocalHeap h t1.operatorWithDestination("/")(c2, 6); C t2 = new C; // create on heap t2.operatorWithDestination!("*")(c1, 5); c3 = t2.operatorAssign!("+")(t1); // in-place += operation on heap h.releaseAll; --- Case 2: in-place operations are impossible, += doesn't exist. --- LocalHeap h; t1 = c1.operatorTemporary!("*")(5, h); // create on local heap t2 = c2.operatorTemporary!("/")(6, h); // create on local heap c3 = t1.operator!("+")(t2); // create on heap h.releaseAll; --- It's far too complicated at present to be workable, but that's the basic idea.Whether tells word introduction "scope" and such attempts of optimization about that that the design of objects in D is wrong? ]:)
Dec 30 2008
Don wrote:The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto. Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.
Dec 30 2008
Christopher Wright wrote:Don wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.
Dec 30 2008
Don wrote:Christopher Wright wrote:Don't forget that the case you are solving is not general enough because you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion. AndreiDon wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.
Dec 30 2008
Andrei Alexandrescu wrote:Don wrote:Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.Christopher Wright wrote:Don't forget that the case you are solving is not general enough because you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.Don wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.
Dec 30 2008
Don wrote:Andrei Alexandrescu wrote:I think the matrices case is important enough to make it its own class of problems. For example, bitmap processing is another instance of matrix usefulness, just one that doesn't usually jump to mind when thinking of matrices. Then how about BigInt and arbitrary precision numbers? Wouldn't fusing some operations together be useful? AndreiDon wrote:Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.Christopher Wright wrote:Don't forget that the case you are solving is not general enough because you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.Don wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.
Dec 30 2008
On Wed, Dec 31, 2008 at 4:32 AM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Don wrote:Graph algorithms can often be thought of as matrices too. I recall some shortest path algorithms where you write edge weight between node i & j in the i,j entry. Then you do a multiply on the matrices, but instead of using the regular vector inner product for each <row, column>, you use max(). I forget which algo it is. I'm thinking Floyd-Warshall. Also there was some algorithm I recall that can be done with a boolean matrix. Probably some kind of connected components algo? --bbAndrei Alexandrescu wrote:I think the matrices case is important enough to make it its own class of problems. For example, bitmap processing is another instance of matrix usefulness, just one that doesn't usually jump to mind when thinking of matrices.Don wrote:Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.Christopher Wright wrote:Don't forget that the case you are solving is not general enough because you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.Don wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.
Dec 30 2008
Bill Baxter wrote:On Wed, Dec 31, 2008 at 4:32 AM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Any graph algorithm that uses e.g. the adjacency matrix... well, uses a matrix :o). AndreiDon wrote:Graph algorithms can often be thought of as matrices too. I recall some shortest path algorithms where you write edge weight between node i & j in the i,j entry. Then you do a multiply on the matrices, but instead of using the regular vector inner product for each <row, column>, you use max(). I forget which algo it is. I'm thinking Floyd-Warshall. Also there was some algorithm I recall that can be done with a boolean matrix. Probably some kind of connected components algo? --bbAndrei Alexandrescu wrote:I think the matrices case is important enough to make it its own class of problems. For example, bitmap processing is another instance of matrix usefulness, just one that doesn't usually jump to mind when thinking of matrices.Don wrote:Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.Christopher Wright wrote:Don't forget that the case you are solving is not general enough because you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.Don wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.
Dec 30 2008
Andrei Alexandrescu wrote:Don wrote:Yes, bitmap processing almost always uses the adjacent pixels, which doesn't translate naturally to BLAS operations. The disturbing thing about both these use cases is that you normally want to involve other operations, such as dot product, which aren't operators. So an optimal solution is pretty elusive.Andrei Alexandrescu wrote:I think the matrices case is important enough to make it its own class of problems. For example, bitmap processing is another instance of matrix usefulness, just one that doesn't usually jump to mind when thinking of matrices.Don wrote:Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.Christopher Wright wrote:Don't forget that the case you are solving is not general enough because you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.Don wrote:That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass. I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.I'm talking about a language solution. I want to solve this for the general case.Then how about BigInt and arbitrary precision numbers? Wouldn't fusing some operations together be useful?Not really, since they are rarely cache-limited. Combining slicing operations with arithmetic might be interesting, but it's pretty obscure I think.
Dec 31 2008
Weed wrote:Don пишет:There is a niche of cases where using the C++-style duality of classes and structs is useful. I think those cases are marginal, and that the conceptual division fostered by D is the better way to go because it's clean and avoids a lot of the inherent problems of duality. AndreiWeed wrote:And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses? I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).Denis Koroskin пишет:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 30 2008
Andrei Alexandrescu ÐÉÛÅÔ:Weed wrote:It is very a pity. My small opinion: it is impossible to reduce performance for struggle against potential errors - such languages already are, it more high-level. It how to refuse pointers because they are dangerous, difficult for beginners and without them it is possible to make any algorithm. What is D? D is a general purpose systems and applications programming language. It is a higher level language than C++, but *retains* the ability to write high performance code and interface directly with the operating system API's and with hardware. http://www.digitalmars.com/d/2.0/overview.htmlDon ÐÉÛÅÔ:There is a niche of cases where using the C++-style duality of classes and structs is useful. I think those cases are marginal, and that the conceptual division fostered by D is the better way to go because it's clean and avoids a lot of the inherent problems of duality.Weed wrote:And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses? I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).Denis Koroskin ÐÉÛÅÔ:Use classes if you want polymorphism. Otherwise, use structs. It's a clear distinction, which is not at all arbitrary -- there are significant implications for the generated code.Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.80490eb: 8d 85 6c fe ff ff lea -0x194(%ebp),%eax 80490f1: 50 push %eax 80490f2: 8d 85 2c fb ff ff lea -0x4d4(%ebp),%eax 80490f8: e8 67 ff ff ff *call 8049064* 80490fd: e8 62 ff ff ff *call 8049064* return c2.i; 8049102: 8b 85 cc fc ff ff mov -0x334(%ebp),%eax ... (in 80490f8 and 80490fd simply two calls successively) If structures and classes were same that excellent optimization in any case would turn outIf that's your use case, then your should seriosly reconsider using struct instead of class for your objects.Alternatively, you can use += instead.Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.Other than that, this is not a convincing argument. Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.I do not accept such argument:)Some languages lack structs support at all (e.g. Java), but structs are too useful for optimization and language interoperation to drop them in a systems programming language. Some lack classes and try doing everything with structs (C). D takes the best of both worlds.Probably I have not understood something, but I do not suggest to refuse structures in general. I suggest to allow to create classes on a stack as it is made in C++. That is actually to make structures and classes same, than they and are, for example, in C++. In the initial message I have shown that for perfomance important that the class could be transferred and on value. And it not artful premature optimisation - objects on value always so are transferred, all programmers know it and use when do not wish to allocate a place in a heap, that is usually always when the object will live in {}. Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it. Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
Dec 30 2008
Weed wrote: [about structs vs. classes]It is very a pity. My small opinion: it is impossible to reduce performance for struggle against potential errors - such languages already are, it more high-level. It how to refuse pointers because they are dangerous, difficult for beginners and without them it is possible to make any algorithm.It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.What is D? D is a general purpose systems and applications programming language. It is a higher level language than C++, but *retains* the ability to write high performance code and interface directly with the operating system API's and with hardware. http://www.digitalmars.com/d/2.0/overview.htmlProbably the worst thing that could happen to that description is it Kafka-esquely morphing into a dogma. Andrei
Dec 30 2008
Andrei Alexandrescu:What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.But probably C compilers (and JavaVirtualMachines) have improved from the first ones, so the performance difference is now smaller. And in GCC if you use C you find lot of intrinsics (for example one for each new SIMD instruction) that mitigates the problem even more. Bye, bearophile
Dec 30 2008
bearophile wrote:But probably C compilers (and JavaVirtualMachines) have improved from the first ones, so the performance difference is now smaller. And in GCC if you use C you find lot of intrinsics (for example one for each new SIMD instruction) that mitigates the problem even more.Not that much smaller.
Jan 01 2009
Andrei Alexandrescu ÐÉÛÅÔ:Weed wrote: [about structs vs. classes]it is justified - microsoft accelerates replacement of hardware for new After all this problem can be solved, IMHO. I suggest to make so: 1. To leave structures in that kind in which they is (POD) 2. To permit classes declaration such what they in C++ 3. To permit transfer the classes on value (for compulsory pass by reference and for declaration through "new" now we have "ref" keyword) 3. To check slicing during compilation. It is possible? 4. "scope" for classes to deprecate as superfluous In that case there will be problems?It is very a pity. My small opinion: it is impossible to reduce performance for struggle against potential errors - such languages already are, it more high-level. It how to refuse pointers because they are dangerous, difficult for beginners and without them it is possible to make any algorithm.It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.Seriously, I trusted itWhat is D? D is a general purpose systems and applications programming language. It is a higher level language than C++, but *retains* the ability to write high performance code and interface directly with the operating system API's and with hardware. http://www.digitalmars.com/d/2.0/overview.htmlProbably the worst thing that could happen to that description is it Kafka-esquely morphing into a dogma.
Dec 30 2008
Weed ÐÉÛÅÔ:Andrei Alexandrescu ÐÉÛÅÔ:For example prohibit assigning on value to the types, not being base or this typeWeed wrote: [about structs vs. classes]it is justified - microsoft accelerates replacement of hardware for new After all this problem can be solved, IMHO. I suggest to make so: 1. To leave structures in that kind in which they is (POD) 2. To permit classes declaration such what they in C++ 3. To permit transfer the classes on value (for compulsory pass by reference and for declaration through "new" now we have "ref" keyword) 3. To check slicing during compilation. It is possible?It is very a pity. My small opinion: it is impossible to reduce performance for struggle against potential errors - such languages already are, it more high-level. It how to refuse pointers because they are dangerous, difficult for beginners and without them it is possible to make any algorithm.It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.4. "scope" for classes to deprecate as superfluous In that case there will be problems?Seriously, I trusted itWhat is D? D is a general purpose systems and applications programming language. It is a higher level language than C++, but *retains* the ability to write high performance code and interface directly with the operating system API's and with hardware. http://www.digitalmars.com/d/2.0/overview.htmlProbably the worst thing that could happen to that description is it Kafka-esquely morphing into a dogma.
Dec 30 2008
Weed ÐÉÛÅÔ:Weed ÐÉÛÅÔ:Who agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?Andrei Alexandrescu ÐÉÛÅÔ:For example prohibit assigning on value to the types, not being base or this typeWeed wrote: [about structs vs. classes]it is justified - microsoft accelerates replacement of hardware for new After all this problem can be solved, IMHO. I suggest to make so: 1. To leave structures in that kind in which they is (POD) 2. To permit classes declaration such what they in C++ 3. To permit transfer the classes on value (for compulsory pass by reference and for declaration through "new" now we have "ref" keyword) 3. To check slicing during compilation. It is possible?It is very a pity. My small opinion: it is impossible to reduce performance for struggle against potential errors - such languages already are, it more high-level. It how to refuse pointers because they are dangerous, difficult for beginners and without them it is possible to make any algorithm.It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.4. "scope" for classes to deprecate as superfluous In that case there will be problems?
Jan 04 2009
Weed ÐÉÛÅÔ:Weed ÐÉÛÅÔ:And against arguments are still necessaryWeed ÐÉÛÅÔ:Who agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?Andrei Alexandrescu ÐÉÛÅÔ:For example prohibit assigning on value to the types, not being base or this typeWeed wrote: [about structs vs. classes]it is justified - microsoft accelerates replacement of hardware for new After all this problem can be solved, IMHO. I suggest to make so: 1. To leave structures in that kind in which they is (POD) 2. To permit classes declaration such what they in C++ 3. To permit transfer the classes on value (for compulsory pass by reference and for declaration through "new" now we have "ref" keyword) 3. To check slicing during compilation. It is possible?It is very a pity. My small opinion: it is impossible to reduce performance for struggle against potential errors - such languages already are, it more high-level. It how to refuse pointers because they are dangerous, difficult for beginners and without them it is possible to make any algorithm.It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.4. "scope" for classes to deprecate as superfluous In that case there will be problems?
Jan 05 2009
Weed wrote:Who agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?When you reply to your reply to your reply to your post and nobody else replies to any of your posts, you might start thinking that nobody agrees with you, or cares enough to respond. As to your suggestion that there be compile-time checks for object slicing... well, you'd end up with almost everything with any polymorphism being done by reference for safety. In the remaining situations, scope will usually suffice. I don't think anyone sees sufficient reason to give Walter as much work as you suggest. When would you use this? - In place of the current scope keyword. - For more efficiency with object composition (though scope could be used for this, potentially). - Implementing value semantics with runtime polymorphism. The only interesting thing there is value semantics with polymorphism. If you really care, you can implement polymorphism with structs.
Jan 05 2009
Christopher Wright ÐÉÛÅÔ:Weed wrote:I consoled myself that the letter has got lost in the big threadWho agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?When you reply to your reply to your reply to your post and nobody else replies to any of your posts, you might start thinking that nobody agrees with you, or cares enough to respond.As to your suggestion that there be compile-time checks for object slicing... well, you'd end up with almost everything with any polymorphism being done by reference for safety. In the remaining situations, scope will usually suffice. I don't think anyone sees sufficient reason to give Walter as much work as you suggest.D2.0 not released, it changes supplemented. I seriously consider at it there is a chance to become the most good language, a "silver bullet". :) This discussion - my small contribution.When would you use this? - In place of the current scope keyword.I consider that "scope" is attempt to fix bad design. Have come to that that on a stack all the same it is necessary to place classes and have added a word, but it does not solve all problems.- For more efficiency with object composition (though scope could be used for this, potentially). - Implementing value semantics with runtime polymorphism.And, probably, in the future it will help to add other possibilities. For example compile-time initialization of classes about which I here spoke too (not in this thread)The only interesting thing there is value semantics with polymorphism. If you really care, you can implement polymorphism with structs.Excellent templates, unit tests, closures, delegates, threads... And after all it is offered to the programmer most implement OOP by hands?
Jan 05 2009
On Tue, Jan 6, 2009 at 1:41 PM, Christopher Wright <dhasenan gmail.com> wrote:Weed wrote:My problem is more that I just can't understand the guy so I don't know if I agree with him or not. I think the choice between just value semantics / POD / no polymorphism / heap or stack and reference semantics / non-POD / polymorphism / heap only Are not quite sufficent. I find myself often wanting things that are mixes of these two attribute sets, and it's often difficult for me to decide up front which is more appropriate for a given case. For instance reference-semantics POD. And other times it's out of my hands writing a library -- the more appropriate one depends on the person using the library not me. So I've played around with things like implementing the guts of something entirely as a mixin that gets mixed in to both a struct and a class shell. It sorta works but it's a lot more work than the unified model in C++ where I just write one class and the user decides how to use it. And scope has a lot of holes. You can't create a scope member of a class. I don't think you can create an array of scope objects, either. So I'm not really convinced that D got the distinction right. It's never really felt right to me and it still doesn't today. But I don't have any better suggestions at the moment. It just feels very un-orthogonal to me. Different unrelated choices are all bundled under the same big toggle switch rather than being able to toggle the different attributes the way I want them. --bbWho agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?When you reply to your reply to your reply to your post and nobody else replies to any of your posts, you might start thinking that nobody agrees with you, or cares enough to respond. As to your suggestion that there be compile-time checks for object slicing... well, you'd end up with almost everything with any polymorphism being done by reference for safety. In the remaining situations, scope will usually suffice. I don't think anyone sees sufficient reason to give Walter as much work as you suggest. When would you use this? - In place of the current scope keyword. - For more efficiency with object composition (though scope could be used for this, potentially). - Implementing value semantics with runtime polymorphism. The only interesting thing there is value semantics with polymorphism. If you really care, you can implement polymorphism with structs.
Jan 05 2009
Bill Baxter ÐÉÛÅÔ:On Tue, Jan 6, 2009 at 1:41 PM, Christopher Wright <dhasenan gmail.com> wrote:No, for classes I suggest to choose between: reference semantics / non-POD / polymorphism / heap only (current state) and value or reference semantics / non-POD / polymorphism / heap or stack As a matter of fact how it was in C++, but with check slicing or simply prohibition of assignment to other types by value. Syntax will demand attention before change - it is necessary to make so that there was no mixing of names of references and classes on value.Weed wrote:My problem is more that I just can't understand the guy so I don't know if I agree with him or not. I think the choice between just value semantics / POD / no polymorphism / heap or stack and reference semantics / non-POD / polymorphism / heap onlyWho agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?When you reply to your reply to your reply to your post and nobody else replies to any of your posts, you might start thinking that nobody agrees with you, or cares enough to respond. As to your suggestion that there be compile-time checks for object slicing... well, you'd end up with almost everything with any polymorphism being done by reference for safety. In the remaining situations, scope will usually suffice. I don't think anyone sees sufficient reason to give Walter as much work as you suggest. When would you use this? - In place of the current scope keyword. - For more efficiency with object composition (though scope could be used for this, potentially). - Implementing value semantics with runtime polymorphism. The only interesting thing there is value semantics with polymorphism. If you really care, you can implement polymorphism with structs.
Jan 05 2009
Weed ÐÉÛÅÔ:Bill Baxter ÐÉÛÅÔ:====On Tue, Jan 6, 2009 at 1:41 PM, Christopher Wright <dhasenan gmail.com> wrote:No, for classes I suggest to choose between: reference semantics / non-POD / polymorphism / heap only (current state) and value or reference semantics / non-POD / polymorphism / heap or stack As a matter of fact how it was in C++, but with check slicing or simply prohibition of assignment to other types by value.Weed wrote:My problem is more that I just can't understand the guy so I don't know if I agree with him or not. I think the choice between just value semantics / POD / no polymorphism / heap or stack and reference semantics / non-POD / polymorphism / heap onlyWho agrees with me? There are still ideas as it is possible to solve this problem and not to destroy language?When you reply to your reply to your reply to your post and nobody else replies to any of your posts, you might start thinking that nobody agrees with you, or cares enough to respond. As to your suggestion that there be compile-time checks for object slicing... well, you'd end up with almost everything with any polymorphism being done by reference for safety. In the remaining situations, scope will usually suffice. I don't think anyone sees sufficient reason to give Walter as much work as you suggest. When would you use this? - In place of the current scope keyword. - For more efficiency with object composition (though scope could be used for this, potentially). - Implementing value semantics with runtime polymorphism. The only interesting thing there is value semantics with polymorphism. If you really care, you can implement polymorphism with structs.Syntax will demand attention before change - it is necessary to make so that there was no mixing of names of references and classes on value.==== ^^^^^^^^ Here the nonsense is written, it is not necessary to be afraid of mixing. I should sleep more:)
Jan 05 2009
(Here I generalise my sentence with supplement) The POD data and the data supporting polymorphism are necessary to us. POD the data is stored in structs and polymorphic objects is classes. Both types (class and struct) can be instanced in a heap or on a stack. (And in invariant ROM too, but there it is not important) Classes and structures support inheritance. But structures do not support polymorphism (as are POD type without vptr) - at attempt to implement virtual function in structure the compiler will give out an error: "struct StructName is POD type, it is not support polymorphism, use class instead of". (And certainly structures are not inherited from classes, including from super class Object) Thus, the programmer always knows the object is POD-data or not. The problem of simple alteration of structure to a class and vice versa when necessary also solved. For an exception of splitting of objects it is necessary to check during compilation: or to forbid assignment on value for types not being to the data (how now it works for the structs objects on value) or to forbid the access to the fields added at descending inheritance (its more difficult but desirable) Please, state critical remarks
Jan 06 2009
Weed ÐÉÛÅÔ:(Here I generalise my sentence with supplement) The POD data and the data supporting polymorphism are necessary to us. POD the data is stored in structs and polymorphic objects is classes. Both types (class and struct) can be instanced in a heap or on a stack. (And in invariant ROM too, but there it is not important) Classes and structures support inheritance. But structures do not support polymorphism (as are POD type without vptr) - at attempt to implement virtual function in structure the compiler will give out an error: "struct StructName is POD type, it is not support polymorphism, use class instead of". (And certainly structures are not inherited from classes, including from super class Object) Thus, the programmer always knows the object is POD-data or not. The problem of simple alteration of structure to a class and vice versa when necessary also solved. For an exception of splitting of objects it is necessary to check during compilation: or to forbid assignment on value for types not being to the data (how now it works for the structs objects on value) or to forbid the access to the fields added at descending inheritance (its more difficult but desirable)And similar it will not break an existing codePlease, state critical remarks
Jan 07 2009
Weed ÐÉÛÅÔ:Weed ÐÉÛÅÔ:(If for a while to keep support "scope")(Here I generalise my sentence with supplement) The POD data and the data supporting polymorphism are necessary to us. POD the data is stored in structs and polymorphic objects is classes. Both types (class and struct) can be instanced in a heap or on a stack. (And in invariant ROM too, but there it is not important) Classes and structures support inheritance. But structures do not support polymorphism (as are POD type without vptr) - at attempt to implement virtual function in structure the compiler will give out an error: "struct StructName is POD type, it is not support polymorphism, use class instead of". (And certainly structures are not inherited from classes, including from super class Object) Thus, the programmer always knows the object is POD-data or not. The problem of simple alteration of structure to a class and vice versa when necessary also solved. For an exception of splitting of objects it is necessary to check during compilation: or to forbid assignment on value for types not being to the data (how now it works for the structs objects on value) or to forbid the access to the fields added at descending inheritance (its more difficult but desirable)And similar it will not break an existing codeTell, what it is necessary to make that discussion of this question has taken place? I in despair. I even think to wait supports 2.0 in open source compiler using LLVM and to add there this functionality (I hope, my skills will just grow for such operation.)Please, state critical remarks
Jan 09 2009
On Sat, 10 Jan 2009 04:02:59 +0300, Weed <resume755 mail.ru> wrote:Weed пишет:I'll explain here what *I* think about. There are a lot of topics concurrently discussed in D newsgroups. I am interested in some of them, others I skip. I usually skip your posts because they are a pain to read and have little of interesting ideas. Perhaps I am wrong and didn't fully understand your idea, but I don't think we reconsider class/structs design. I believe the design is sound and I don't think anyone (expect you) would like to have these basic language principles changed. As such, the whole idea is pretty much a "dead horse" and I don't want to shoot it by contributing to it. If it was a forum and I were a moderator I'd just close the topic to stop spreading confusion, but that's just me. Back to topic, C++ doesn't have any meaningful separation between classes and structs. D does - (one of it is that) classes are heap allocated by default whereas structs are stack allocated by default. You can override either behavior: class C {} struct S {} C c = new C(); // heap-allocated (default) S s = S(); // stack-allocated (default) scope C c = new C(); // stack-allocated S* s = new S(); // heap allocated One problem I see with it is that the syntax is so much different, but that's another topic. Other one is that the following works for local variables exclusively, i.e. you can't have class instance aggregated inside another class by value. Yes, I think there is a room for improvement but it is of little priority for me. You don't provide use cases nor examples of possible syntax, but they are crucial for understanding. What else? Struct inheritance - yes it is nice to have, even without polymorphism. It was proposed many times but with no success. Someone suggested to use aggregation and opDot instead and allow implicit cast of pointer to struct to pointer to struct's first element to emulate inheritance: struct Foo { void fooMethod() {} } struct Bar { Foo foo; Foo* opDot() { return &foo; } float f; } Bar* bar = new Bar(); bar.fooMethod(); Foo* foo = bar; But it didn't have Walter's support either (and I understand why). I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts). You could also ask someone to check your post before submitting - this will increase the probability of your message to be read and understood. P.S. Ðе унывай! :)Weed пишет:(If for a while to keep support "scope")(Here I generalise my sentence with supplement) The POD data and the data supporting polymorphism are necessary to us. POD the data is stored in structs and polymorphic objects is classes. Both types (class and struct) can be instanced in a heap or on a stack. (And in invariant ROM too, but there it is not important) Classes and structures support inheritance. But structures do not support polymorphism (as are POD type without vptr) - at attempt to implement virtual function in structure the compiler will give out an error: "struct StructName is POD type, it is not support polymorphism, use class instead of". (And certainly structures are not inherited from classes, including from super class Object) Thus, the programmer always knows the object is POD-data or not. The problem of simple alteration of structure to a class and vice versa when necessary also solved. For an exception of splitting of objects it is necessary to check during compilation: or to forbid assignment on value for types not being to the data (how now it works for the structs objects on value) or to forbid the access to the fields added at descending inheritance (its more difficult but desirable)And similar it will not break an existing codeTell, what it is necessary to make that discussion of this question has taken place? I in despair. I even think to wait supports 2.0 in open source compiler using LLVM and to add there this functionality (I hope, my skills will just grow for such operation.)Please, state critical remarks
Jan 09 2009
Denis Koroskin ÐÉÛÅÔ:Back to topic, C++ doesn't have any meaningful separation between classes and structs. D does - (one of it is that) classes are heap allocated by default whereas structs are stack allocated by default. You can override either behavior: class C {} struct S {} C c = new C(); // heap-allocated (default) S s = S(); // stack-allocated (default) scope C c = new C(); // stack-allocatedThis way does not approach because scope value is impossible to return from function.S* s = new S(); // heap allocated One problem I see with it is that the syntax is so much different, but that's another topic. Other one is that the following works for local variables exclusively, i.e. you can't have class instance aggregated inside another class by value.I am not understand what here a problem with class inside other class.Yes, I think there is a room for improvement but it is of little priority for me. You don't provide use cases nor examples of possible syntax, but they are crucial for understanding.I still was not sure what syntax could. While I operate with the such - probably, it don't break an existing code: class C {} struct S {} C c = new C(); // heap-allocated S s; // stack-allocated S s = S(); // stack-allocated S* s = new S(); // heap allocated C c(); // stack-allocated (added by me) Brackets () do not allow to mix object with the reference. Also, they may contain constructor parameters. Further objects are used as usually.What else? Struct inheritance - yes it is nice to have, even without polymorphism. It was proposed many times but with no success. Someone suggested to use aggregation and opDot instead and allow implicit cast of pointer to struct to pointer to struct's first element to emulate inheritance:Inheriting of structures is necessary for convenience of replacement "struct" to "class" and vice versa. Therefore possibility of replacement of struct inheritance on other constructions it is not essential.I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts). You could also ask someone to check your post before submitting - this will increase the probability of your message to be read and understood.I agree, but the changes offered by me separately look as unreasonably, and only in the sum they yield good result. Thanks for kind words :)
Jan 10 2009
Denis Koroskin ÐÉÛÅÔ:I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts).The extra-short formulation of my idea: Objects should be divided on POD (struct) and non-POD (class). Instead of such division as now: POD && value type (struct) and POD && reference type (class).
Jan 10 2009
Weed wrote:Denis Koroskin ÐÉÛÅÔ:The reference versus value type difference is just a matter of defaults. Returning a class instance on the stack from a function is possible with inout parameters, though you can't use a constructor in that case: void main () { scope MyClass obj = new MyClass; foo (obj); } void foo (inout MyClass obj) { // initialize obj somehow }I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts).The extra-short formulation of my idea: Objects should be divided on POD (struct) and non-POD (class). Instead of such division as now: POD && value type (struct) and POD && reference type (class).
Jan 10 2009
Christopher Wright ÐÉÛÅÔ:Weed wrote:Problem not only with constructor calling. This way does not works for temporary objects. For example, at operator overloading in expression like a = b + c + d. The case in detail was considered in this thread: "division of objects into classes and structures is bad", http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81359 Also, it impossible to create an array of scope objects.Denis Koroskin ÐÉÛÅÔ:The reference versus value type difference is just a matter of defaults. Returning a class instance on the stack from a function is possible with inout parameters, though you can't use a constructor in that case: void main () { scope MyClass obj = new MyClass; foo (obj); } void foo (inout MyClass obj) { // initialize obj somehow }I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts).The extra-short formulation of my idea: Objects should be divided on POD (struct) and non-POD (class). Instead of such division as now: POD && value type (struct) and POD && reference type (class).
Jan 10 2009
2009/1/11 Christopher Wright <dhasenan gmail.com>:Weed wrote:I don't think that does what you think it does. Remember that obj is basically a pointer under the hood. So what that 'inout' does is allow you to make obj point to something else. You don't need the 'inout' if all you want to do is change the contents of what obj points to. I think what 'scope MyClass obj' actually does is reserve the appropriate amount of space on the stack somewhere, then make obj point to that space instead of the heap. So that means you can still reassign obj if you feel like it. And it can be reassigned to either a scope or non-scope instance. It doesn't matter to obj because obj is just a pointer. --bbDenis Koroskin =D0=C9=DB=C5=D4:The reference versus value type difference is just a matter of defaults. Returning a class instance on the stack from a function is possible with inout parameters, though you can't use a constructor in that case: void main () { scope MyClass obj =3D new MyClass; foo (obj); } void foo (inout MyClass obj) { // initialize obj somehow }I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts).The extra-short formulation of my idea: Objects should be divided on POD (struct) and non-POD (class). Instead of such division as now: POD && value type (struct) and POD && reference type (class).
Jan 10 2009
2009/1/11 Christopher Wright <dhasenan gmail.com>:No it's not. scope MyClass does not make a MyClass that works like a value type. It merely makes a MyClass instance that's allocated on the stack. The semantics of it otherwise is identical to a regular class. Another difference is that class instances can only be 'scope' in functions. A use case that's missing is: class MyClass { scope OtherClass foo; } This would embed the memory for 'foo' right inside MyClass, so that scope x = new MyClass; Would not involve any heap allocations. Currently if you have a class inside a class, there's no way to use 'scope' to avoid the heap allocation on the contained class. Also you could imagine scope arrays. MyClass foo = new scope MyClass[10]; Where this would do one heap allocation, not 10. There is a problem with this though, mentioned below, precisely because scope MyClass does *not* have value semantics.Instead of such division as now: POD && value type (struct) and POD && reference type (class).The reference versus value type difference is just a matter of defaults.Returning a class instance on the stack from a function is possible with inout parameters, though you can't use a constructor in that case: void main () { scope MyClass obj = new MyClass; foo (obj); } void foo (inout MyClass obj) { // initialize obj somehow }To further follow up on this, what you are showing is *not* returning a class instance on the stack via inout. You are just modifying a pre-existing instance. Returning a scope instance via inout would look like this: void main() { MyClass obj; foo(obj); } void foo(inout MyClass obj) { scope tmp = new MyClass; obj = tmp; } And that will crash because it refers to memory allocated on the stack. What is impossible with D right now is to make a value copy of a class (short of getting hackish with memcpy). But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing. And that's also the problem with putting scope'd things inside another class or an array. Since they don't have value semantics, there's no way to overwrite the memory that's there with a new version of the object. If you try to overwrite it you will instead just change the pointer. (This is what happens with scope objects in functions now). Assuming this worked: class MyClass { scope OtherClass foo; } scope x = new MyClass; x.foo = new OtherClass; You haven't reused the memory that foo originally occupied. You've instead made foo point to the heap. And now you have a chunk of your class that stored the original foo that's dead, useless and uncollectable. So the conclusion is that scope without value semantics is of somewhat limited use. Or at least in the case of embedded scope objects, they should best be considered kind of like 'final', only for cases where you're never going to rebind the reference to something else. --bb
Jan 10 2009
Bill Baxter ÐÉÛÅÔ:But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing.It is not always a good thing. I propose to prohibit only the copying by value of the base type to derivative typeAnd that's also the problem with putting scope'd things inside another class or an array. Since they don't have value semantics,Yes, this is what I mean
Jan 10 2009
2009/1/11 Weed <resume755 mail.ru>:Bill Baxter =D0=C9=DB=C5=D4:Yeh, I just mean there is some merit in disabling value copies. But I don't rule out the possibility that there may be an even better way that banning them altogether.But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing.It is not always a good thing.I propose to prohibit only the copying by value of the base type to derivative typeOk, this is key. How do you propose to do this? In general it requires a runtime check, I think. And I think you need to say that you prohibit copying unless typeA=3D=3DtypeB exactly. If you allow copying either way between base and derived you are asking for trouble. But still given Base x =3D get_one(); Base y =3D get_another(); *x =3D *y; // presumed value copy syntax you have no way in general to know that x and y are really both a Base at compile time. So you must have a run-time check there. Perhaps it could be omitted for -release builds, though.So assuming you had this, the important question is what would you do with = it? You still have the problem that the current system works pretty well. And has a lot of history. So you need a very compelling use case to convince Walter that something should change. --bbAnd that's also the problem with putting scope'd things inside another class or an array. Since they don't have value semantics,Yes, this is what I mean
Jan 10 2009
Bill Baxter ÐÉÛÅÔ:2009/1/11 Weed <resume755 mail.ru>:It can lead to a difficult and non-reproduceable errors than old C++-style splitting. It is possible to try to prohibit assignment of the dereferenced pointers? Simply to prohibit assignment too it is possible, essentially it changes nothing.Bill Baxter ÐÉÛÅÔ:Yeh, I just mean there is some merit in disabling value copies. But I don't rule out the possibility that there may be an even better way that banning them altogether.But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing.It is not always a good thing.I propose to prohibit only the copying by value of the base type to derivative typeOk, this is key. How do you propose to do this? In general it requires a runtime check, I think. And I think you need to say that you prohibit copying unless typeA==typeB exactly. If you allow copying either way between base and derived you are asking for trouble. But still given Base x = get_one(); Base y = get_another(); *x = *y; // presumed value copy syntax you have no way in general to know that x and y are really both a Base at compile time. So you must have a run-time check there. Perhaps it could be omitted for -release builds, though.The most difficult. My arguments: 1. Problem of a choice of correct type for the object. A mathematical matrix - a classical example. A class it should be or structure? My offer without serious consequences allows to move solution of this problem from a design stage to a programming stage - is it will be simple by replacement keyword class to struct. 2. Performance increases. It is not necessary to allocate at the slightest pretext memory in a heap. 3. I offer syntax which presumably does not break an existing code. + On how many I understand, in the existing compiler all necessary for implementation already is, a problem only in syntax addition. language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model. D is compiled language and to borrow reference model incorrectly. In D the programmer should have possibility most to decide where to place object.So assuming you had this, the important question is what would you do with it?And that's also the problem with putting scope'd things inside another class or an array. Since they don't have value semantics,Yes, this is what I meanYou still have the problem that the current system works pretty well. And has a lot of history. So you need a very compelling use case to convince Walter that something should change.of history. But not D. This situation reminds me history with the Hungarian notation: Many years ago many developers have started to deliver interfaces and to sell books where it was used. This very correct invention affirmed as many books that and only in ~5 years there were articles with the materials specifying in groundlessness of usage of this notation. Till this time many entered it into corporate standards and suffered, though, I am sure, they were visited by thoughts about irrelevance of the given notation except for special cases.
Jan 10 2009
On Sun, 11 Jan 2009 05:04:11 +0300, Weed <resume755 mail.ru> wrote:Bill Baxter пишет:Err.. I don't get what you say. The *x = *y is just one of the possible syntaxes, nothing else.2009/1/11 Weed <resume755 mail.ru>:It can lead to a difficult and non-reproduceable errors than old C++-style splitting. It is possible to try to prohibit assignment of the dereferenced pointers? Simply to prohibit assignment too it is possible, essentially it changes nothing.Bill Baxter пишет:Yeh, I just mean there is some merit in disabling value copies. But I don't rule out the possibility that there may be an even better way that banning them altogether.But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing.It is not always a good thing.I propose to prohibit only the copying by value of the base type to derivative typeOk, this is key. How do you propose to do this? In general it requires a runtime check, I think. And I think you need to say that you prohibit copying unless typeA==typeB exactly. If you allow copying either way between base and derived you are asking for trouble. But still given Base x = get_one(); Base y = get_another(); *x = *y; // presumed value copy syntax you have no way in general to know that x and y are really both a Base at compile time. So you must have a run-time check there. Perhaps it could be omitted for -release builds, though.Having the same syntax for both classes and struct is a nice goal, I agree. But it should be taken as a different issue and solved separately, too.The most difficult. My arguments: 1. Problem of a choice of correct type for the object. A mathematical matrix - a classical example. A class it should be or structure? My offer without serious consequences allows to move solution of this problem from a design stage to a programming stage - is it will be simple by replacement keyword class to struct.So assuming you had this, the important question is what would you do with it?And that's also the problem with putting scope'd things inside another class or an array. Since they don't have value semantics,Yes, this is what I mean2. Performance increases. It is not necessary to allocate at the slightest pretext memory in a heap. 3. I offer syntax which presumably does not break an existing code. + On how many I understand, in the existing compiler all necessary for implementation already is, a problem only in syntax addition. language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.D is compiled language and to borrow reference model incorrectly. In D the programmer should have possibility most to decide where to place object.DMD 0.001 was released 7 years ago. Long enough, I think.You still have the problem that the current system works pretty well. And has a lot of history. So you need a very compelling use case to convince Walter that something should change.of history. But not D.This situation reminds me history with the Hungarian notation: Many years ago many developers have started to deliver interfaces and to sell books where it was used. This very correct invention affirmed as many books that and only in ~5 years there were articles with the materials specifying in groundlessness of usage of this notation. Till this time many entered it into corporate standards and suffered, though, I am sure, they were visited by thoughts about irrelevance of the given notation except for special cases.
Jan 10 2009
Denis Koroskin ÐÉÛÅÔ:On Sun, 11 Jan 2009 05:04:11 +0300, Weed <resume755 mail.ru> wrote:(I have incorrectly expressed) If dereferencing was not used in lvalue or rvalue and is both a classes by value it is possible to assignment, except cases when the base type to the derivative is assigned. Example: class C {} class C2 : C {} C c(); C2 c2(); C* c_p = &c; C2* c2_p = &c2; c = c2; // ok c2 = c; // err *c_p = *c2_p; // err *c2_p = *c_p; // err c2 = *c2_p; // err and: c = c2 + *c2_p; // okBill Baxter ÐÉÛÅÔ:Err.. I don't get what you say. The *x = *y is just one of the possible syntaxes, nothing else.2009/1/11 Weed <resume755 mail.ru>:It can lead to a difficult and non-reproduceable errors than old C++-style splitting. It is possible to try to prohibit assignment of the dereferenced pointers? Simply to prohibit assignment too it is possible, essentially it changes nothing.Bill Baxter ÐÉÛÅÔ:Yeh, I just mean there is some merit in disabling value copies. But I don't rule out the possibility that there may be an even better way that banning them altogether.But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing.It is not always a good thing.I propose to prohibit only the copying by value of the base type to derivative typeOk, this is key. How do you propose to do this? In general it requires a runtime check, I think. And I think you need to say that you prohibit copying unless typeA==typeB exactly. If you allow copying either way between base and derived you are asking for trouble. But still given Base x = get_one(); Base y = get_another(); *x = *y; // presumed value copy syntax you have no way in general to know that x and y are really both a Base at compile time. So you must have a run-time check there. Perhaps it could be omitted for -release builds, though.So I offer: the inheritance of structures this one of offers, which in itself it seems insignificant, but useful if to make classes by value.Having the same syntax for both classes and struct is a nice goal, I agree. But it should be taken as a different issue and solved separately, too.The most difficult. My arguments: 1. Problem of a choice of correct type for the object. A mathematical matrix - a classical example. A class it should be or structure? My offer without serious consequences allows to move solution of this problem from a design stage to a programming stage - is it will be simple by replacement keyword class to struct.So assuming you had this, the important question is what would you do with it?And that's also the problem with putting scope'd things inside another class or an array. Since they don't have value semantics,Yes, this is what I meanOh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.2. Performance increases. It is not necessary to allocate at the slightest pretext memory in a heap. 3. I offer syntax which presumably does not break an existing code. + On how many I understand, in the existing compiler all necessary for implementation already is, a problem only in syntax addition. language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.Yes, I know. I hint at that that it seems this scheme have copied because it is popular but have not considered characteristic for C++-like compiled language nuances.D is compiled language and to borrow reference model incorrectly. In D the programmer should have possibility most to decide where to place object.DMD 0.001 was released 7 years ago. Long enough, I think.You still have the problem that the current system works pretty well. And has a lot of history. So you need a very compelling use case to convince Walter that something should change.of history. But not D.
Jan 11 2009
Weed ÐÉÛÅÔ:I guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)." Therefore they do not worry concerning performance of creation of objects in a heap and reference classes for them approach.Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.
Jan 11 2009
Weed wrote:Weed пишет:Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model. AndreiI guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.
Jan 11 2009
Andrei Alexandrescu wrote:Weed wrote:Take it as nicely seasoned. The current jvm gc and memory subsystem is _extremely_ clever. However, it completely relies on the ability to move objects during garbage collection. If it was purely the allocator that behaved that way, you'd be right. But it's interaction with the gc is where the system comes together to form a useful whole. Later, BradWeed пишет:Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model. AndreiI guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.
Jan 11 2009
Brad Roberts wrote:Andrei Alexandrescu wrote:I understand. My point is that a 10-cycles-per-allocation allocator will necessarily use more memory than one that attempts to reuse memory. There's no way around that. I mean we know what those cycles do :o). Some application don't work well with that. Escape analysis does reduce the number of cache-unfriendly patterns, but, as of today, not to the point the issue can be safely ignored. There's no contention that GC has made great progress lately, and that's a great thing. AndreiWeed wrote:Take it as nicely seasoned. The current jvm gc and memory subsystem is _extremely_ clever. However, it completely relies on the ability to move objects during garbage collection. If it was purely the allocator that behaved that way, you'd be right. But it's interaction with the gc is where the system comes together to form a useful whole.Weed пишет:Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model. AndreiI guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.
Jan 12 2009
Andrei Alexandrescu ÐÉÛÅÔ:Brad Roberts wrote:10 *cycles* per allocation?Andrei Alexandrescu wrote:I understand. My point is that a 10-cycles-per-allocation allocatorWeed wrote:Take it as nicely seasoned. The current jvm gc and memory subsystem is _extremely_ clever. However, it completely relies on the ability to move objects during garbage collection. If it was purely the allocator that behaved that way, you'd be right. But it's interaction with the gc is where the system comes together to form a useful whole.Weed ÐÉÛÅÔ:Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model. AndreiI guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.will necessarily use more memory than one that attempts to reuse memory. There's no way around that. I mean we know what those cycles do :o). Some application don't work well with that. Escape analysis does reduce the number of cache-unfriendly patterns, but, as of today, not to the point the issue can be safely ignored. There's no contention that GC has made great progress lately, and that's a great thing.In any case, we cannot add such memory manager in D. And such resource allocation does not approach us, and mandatory creation of objects in a heap does not approach for D.
Jan 12 2009
2009/1/13 Weed <resume755 mail.ru>:Andrei Alexandrescu =D0=C9=DB=C5=D4:reBrad Roberts wrote:Andrei Alexandrescu wrote:Weed wrote:Weed =D0=C9=DB=C5=D4:language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefo=nI guess allocation in Java occurs fast because of usage of the its ow=Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.hememory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, t=.2Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4=nsand later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementatio=.in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly=cMany applications aren't that thrilled with the costs of such a model. AndreiTake it as nicely seasoned. The current jvm gc and memory subsystem is _extremely_ clever. However, it completely relies on the ability to move objects during garbage collection. If it was purely the allocator that behaved that way, you'd be right. But it's interaction with the g=I'm not and expert in garbage collection but... An interesting point was made yesterday on the GDAlgorithms mailing list. Acording to this one game industry veteran, you don't need a fully moving garbage collector to get many of the benefits. If *some* of the memory can be moved around then often that's enough to fill in the gaps and keep fragmentation down. So it may be worth while to have a special kind construct for containing data that the compiler is free to move around. This type would have a hidden pointer inside of it that can be moved around by the gc, but applications would not be allowed to access that pointer. And I suppose that means all access to the data would given via lvalue only. Probably wouldn't take much on the part of the GC to provide the necessary hooks. Just some sort of "relocatable alloc" call. Rest could probably be handled in higher level libs. But like I said I don't know much about GC. --bb10 *cycles* per allocation?is where the system comes together to form a useful whole.I understand. My point is that a 10-cycles-per-allocation allocatorwill necessarily use more memory than one that attempts to reuse memory. There's no way around that. I mean we know what those cycles do :o). Some application don't work well with that. Escape analysis does reduce the number of cache-unfriendly patterns, but, as of today, not to the point the issue can be safely ignored. There's no contention that GC has made great progress lately, and that's a great thing.In any case, we cannot add such memory manager in D. And such resource allocation does not approach us, and mandatory creation of objects in a heap does not approach for D.
Jan 12 2009
Bill Baxter wrote:So it may be worth while to have a special kind construct for containing data that the compiler is free to move around. This type would have a hidden pointer inside of it that can be moved around by the gc, but applications would not be allowed to access that pointer. And I suppose that means all access to the data would given via lvalue only. Probably wouldn't take much on the part of the GC to provide the necessary hooks. Just some sort of "relocatable alloc" call. Rest could probably be handled in higher level libs.Interesting. (Link?) Structs in D are supposed to be location transparent (it is unclear to me to what extent this should be enforced vs. just assumed), so if the compiler can show the address of a struct is not taken, it should be free to move it around. Andrei
Jan 12 2009
On Tue, 13 Jan 2009 04:17:22 +0300, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Bill Baxter wrote:If the compiler can show the address of a struct is not taken, it should recycle the memory :pSo it may be worth while to have a special kind construct for containing data that the compiler is free to move around. This type would have a hidden pointer inside of it that can be moved around by the gc, but applications would not be allowed to access that pointer. And I suppose that means all access to the data would given via lvalue only. Probably wouldn't take much on the part of the GC to provide the necessary hooks. Just some sort of "relocatable alloc" call. Rest could probably be handled in higher level libs.Interesting. (Link?) Structs in D are supposed to be location transparent (it is unclear to me to what extent this should be enforced vs. just assumed), so if the compiler can show the address of a struct is not taken, it should be free to move it around. Andrei
Jan 12 2009
On Tue, Jan 13, 2009 at 10:17 AM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Bill Baxter wrote:The message doesn't appear to have come up on the list archive yet, but here's the full text: """So it may be worth while to have a special kind construct for containing data that the compiler is free to move around. This type would have a hidden pointer inside of it that can be moved around by the gc, but applications would not be allowed to access that pointer. And I suppose that means all access to the data would given via lvalue only. Probably wouldn't take much on the part of the GC to provide the necessary hooks. Just some sort of "relocatable alloc" call. Rest could probably be handled in higher level libs.Interesting. (Link?) Structs in D are supposed to be location transparent (it is unclear to me to what extent this should be enforced vs. just assumed), so if the compiler can show the address of a struct is not taken, it should be free to move it around.Third solution that was popular is to make your data completelyrelocatable and allow the blocks to be moved around as needed. One nice thing I've found is that only some of your data needs to be like this to get the full benefit, because it can move around to fill in the gaps left by all the other fixed-position parts. Especially helpful on consoles, where most of your data is stuff like sound, texture and geometry buffers, which are all trivially relocatable. TomF. """ (TomF is Tom Forsyth, been in the game biz for a long time, now at Intel working on Larabee) --bb
Jan 12 2009
Hello Bill,2009/1/13 Weed <resume755 mail.ru>:Recently, I started looking into garbage collection theory. Of course, the first source I went to was Hans Boem's. Here's a couple of links that might be interesting: http://www.hpl.hp.com/personal/Hans_Boehm/gc/complexity.html http://www.hpl.hp.com/personal/Hans_Boehm/gc/conservative.html And a whole list of other articles here: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ Lots of interesting material... and a fair bit of it is over my head. But, nonetheless, the fundamentals are there. I'm not sure if some of there studies are accurate, biased, or out-dated since I don't keep up with state-of-the-art gc research. But, it seems to me, that Hans is still one of the top experts in the field, so some of what's there must be very pertinant. -JJRAndrei Alexandrescu пишет:I'm not and expert in garbage collection but... An interesting point was made yesterday on the GDAlgorithms mailing list. Acording to this one game industry veteran, you don't need a fully moving garbage collector to get many of the benefits. If *some* of the memory can be moved around then often that's enough to fill in the gaps and keep fragmentation down. So it may be worth while to have a special kind construct for containing data that the compiler is free to move around. This type would have a hidden pointer inside of it that can be moved around by the gc, but applications would not be allowed to access that pointer. And I suppose that means all access to the data would given via lvalue only. Probably wouldn't take much on the part of the GC to provide the necessary hooks. Just some sort of "relocatable alloc" call. Rest could probably be handled in higher level libs. But like I said I don't know much about GC. --bbBrad Roberts wrote:10 *cycles* per allocation?Andrei Alexandrescu wrote:I understand. My point is that a 10-cycles-per-allocation allocatorWeed wrote:Take it as nicely seasoned. The current jvm gc and memory subsystem is _extremely_ clever. However, it completely relies on the ability to move objects during garbage collection. If it was purely the allocator that behaved that way, you'd be right. But it's interaction with the gc is where the system comes together to form a useful whole.Weed пишет:Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model. AndreiI guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.of language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.will necessarily use more memory than one that attempts to reuse memory. There's no way around that. I mean we know what those cycles do :o). Some application don't work well with that. Escape analysis does reduce the number of cache-unfriendly patterns, but, as of today, not to the point the issue can be safely ignored. There's no contention that GC has made great progress lately, and that's a great thing.In any case, we cannot add such memory manager in D. And such resource allocation does not approach us, and mandatory creation of objects in a heap does not approach for D.
Jan 12 2009
On Tue, 13 Jan 2009, Bill Baxter wrote:I'm not and expert in garbage collection but... An interesting point was made yesterday on the GDAlgorithms mailing list. Acording to this one game industry veteran, you don't need a fully moving garbage collector to get many of the benefits. If *some* of the memory can be moved around then often that's enough to fill in the gaps and keep fragmentation down. So it may be worth while to have a special kind construct for containing data that the compiler is free to move around. This type would have a hidden pointer inside of it that can be moved around by the gc, but applications would not be allowed to access that pointer. And I suppose that means all access to the data would given via lvalue only. Probably wouldn't take much on the part of the GC to provide the necessary hooks. Just some sort of "relocatable alloc" call. Rest could probably be handled in higher level libs. But like I said I don't know much about GC. --bbAnd wouldn't ya know it.. I spent parts of saturday pondering on exactly how to implement exactly that. I've got most of the code pictured in my head, but none of it written. :) Maybe one day I'll make the time to try it. Later, Brad
Jan 12 2009
Andrei Alexandrescu wrote:Weed wrote:Actually, memory allocated in the JVM is very cache-friendly, since two subsequent allocations will always be adjacent to one another in physical memory. And, since the JVM uses a moving GC, long-lived objects move closer and closer together. Of course, Java programmers tend to be less careful about memory allocation, so they usually consume **way** too much memory and lose the benefits of the moving GC. Java-the-langauge and Java-the-platform are very efficient, even if the java frameworks and java patterns tend to bloated and nasty. --benjiWeed пишет:Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model. AndreiI guess allocation in Java occurs fast because of usage of the its own memory manager. I do not know how it is fair, but: http://www.ibm.com/developerworks/java/library/j-jtp09275.html "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.Neither of these languages are interpreted, they both are compiled into native code at runtime.
Jan 12 2009
Benji Smith wrote:Actually, memory allocated in the JVM is very cache-friendly, since two subsequent allocations will always be adjacent to one another in physical memory. And, since the JVM uses a moving GC, long-lived objects move closer and closer together.Well the problem is that the allocation size grows quickly. Allocate and dispose one object per loop -> pages will be quickly eaten. for (...) { JavaClassWithAReallyLongNameAsTheyUsuallyAre o = factory.giveMeOne(); o.method(); } The escape analyzer could catch that the variable doesn't survive the pass through the loop, but the call to method makes things rather tricky (virtual, source unavailable...). So then we're facing a quickly growing allocation block and consequently less cache friendliness and more frequent collections. Andrei
Jan 12 2009
Andrei Alexandrescu wrote:Benji Smith wrote:Good point. I remember five years ago when people were buzzing about the possible implementation of escape analysis in the next Java version, and how it'd move a boatload of intermediate object allocations from the heap to the stack. Personally, I don't think it'll ever happen. They can't even agree on how to get *closures* into the language. I personally think the JVM and the HotSpot compiler are two of the greatest accomplishments of computer science. But the Java community has long since jumped the shark, and I don't expect much innovation from that neighborhood anymore. --benjiActually, memory allocated in the JVM is very cache-friendly, since two subsequent allocations will always be adjacent to one another in physical memory. And, since the JVM uses a moving GC, long-lived objects move closer and closer together.Well the problem is that the allocation size grows quickly. Allocate and dispose one object per loop -> pages will be quickly eaten. for (...) { JavaClassWithAReallyLongNameAsTheyUsuallyAre o = factory.giveMeOne(); o.method(); } The escape analyzer could catch that the variable doesn't survive the pass through the loop, but the call to method makes things rather tricky (virtual, source unavailable...). So then we're facing a quickly growing allocation block and consequently less cache friendliness and more frequent collections. Andrei
Jan 12 2009
Benji Smith wrote:[snip] ... But the Java community has long since jumped the shark, and I don't expect much innovation from that neighborhood anymore. --benjiimport javax.actions.aquatic.jumper.*; import javax.zoology.animals.*; class SharkJumper { public SharkJumper() { } public void jump() throws Exception { AnimalFactory animalFactory = new AnimalFactory(false); GenusRegistry genusRegistry = new GenusRegistry(); Animal animal = animalFactory.createAnimal(genusRegistry.findScientifficNameFromCommonName("shark")); ActionFactory actionFactory = new ActionFactory(); Action action = actionFactory.createFromVerb("jump", Culture.createFromShortName("en")); action.performActionOnObjectPassedAsFirstArgument(animal); } } Sorry, couldn't resist a chance to bash Java :D Apologies for any mistakes; it's been a while since I was forced a gunpoint to write Java code... -- Daniel
Jan 12 2009
On Tue, Jan 13, 2009 at 7:30 AM, Daniel Keep <daniel.keep.lists gmail.com> wrote: [snip]Sorry, couldn't resist a chance to bash Java :D Apologies for any mistakes; it's been a while since I was forced a gunpoint to write Java code...That's why there is Scala. A far more elegant language, the same VM. -- Daniel
Jan 14 2009
Weed ÐÉÛÅÔ:Denis Koroskin ÐÉÛÅÔ:And any remark on the sentence?..On Sun, 11 Jan 2009 05:04:11 +0300, Weed <resume755 mail.ru> wrote:(I have incorrectly expressed) If dereferencing was not used in lvalue or rvalue and is both a classes by value it is possible to assignment, except cases when the base type to the derivative is assigned. Example: class C {} class C2 : C {} C c(); C2 c2(); C* c_p = &c; C2* c2_p = &c2; c = c2; // ok c2 = c; // err *c_p = *c2_p; // err *c2_p = *c_p; // err c2 = *c2_p; // err and: c = c2 + *c2_p; // okBill Baxter ÐÉÛÅÔ:Err.. I don't get what you say. The *x = *y is just one of the possible syntaxes, nothing else.2009/1/11 Weed <resume755 mail.ru>:It can lead to a difficult and non-reproduceable errors than old C++-style splitting. It is possible to try to prohibit assignment of the dereferenced pointers? Simply to prohibit assignment too it is possible, essentially it changes nothing.Bill Baxter ÐÉÛÅÔ:Yeh, I just mean there is some merit in disabling value copies. But I don't rule out the possibility that there may be an even better way that banning them altogether.But since classes can be polymorphic, value copying gets you into slicing problems. That's why value copying is disabled to begin with. So disabling value copies is a good thing.It is not always a good thing.I propose to prohibit only the copying by value of the base type to derivative typeOk, this is key. How do you propose to do this? In general it requires a runtime check, I think. And I think you need to say that you prohibit copying unless typeA==typeB exactly. If you allow copying either way between base and derived you are asking for trouble. But still given Base x = get_one(); Base y = get_another(); *x = *y; // presumed value copy syntax you have no way in general to know that x and y are really both a Base at compile time. So you must have a run-time check there. Perhaps it could be omitted for -release builds, though.
Jan 15 2009
On Wed, Jan 7, 2009 at 4:22 AM, Weed <resume755 mail.ru> wrote:(Here I generalise my sentence with supplement) The POD data and the data supporting polymorphism are necessary to us. POD the data is stored in structs and polymorphic objects is classes. Both types (class and struct) can be instanced in a heap or on a stack. (And in invariant ROM too, but there it is not important) Classes and structures support inheritance. But structures do not support polymorphism (as are POD type without vptr) - at attempt to implement virtual function in structure the compiler will give out an error: "struct StructName is POD type, it is not support polymorphism, use class instead of". (And certainly structures are not inherited from classes, including from super class Object) Thus, the programmer always knows the object is POD-data or not. The problem of simple alteration of structure to a class and vice versa when necessary also solved. For an exception of splitting of objects it is necessary to check during compilation: or to forbid assignment on value for types not being to the data (how now it works for the structs objects on value) or to forbid the access to the fields added at descending inheritance (its more difficult but desirable) Please, state critical remarksYour English is really hard to make sense of. That's my guess for why there are no responses. Heck, I'd *like* to respond, but I just can't tell what you're trying to say. --bb
Jan 09 2009
Bill Baxter ÐÉÛÅÔ:All is absolutely poor? If not everything, can you select that demands the explanation?Please, state critical remarksYour English is really hard to make sense of. That's my guess for why there are no responses. Heck, I'd *like* to respond, but I just can't tell what you're trying to say.
Jan 10 2009
Weed wrote:Bill Baxter ÐÉÛÅÔ:Translation: Is it all bad? Otherwise, can you say what you want clarified?All is absolutely poor? If not everything, can you select that demands the explanation?Please, state critical remarksYour English is really hard to make sense of. That's my guess for why there are no responses. Heck, I'd *like* to respond, but I just can't tell what you're trying to say.
Jan 12 2009
Interesting. (Link?)http://sourceforge.net/mailarchive/forum.php?thread_name=e8fc97ba0901111537g3ce284b3m63f6fe2c1543c40 mail.gmail.com&forum_name=gdalgorithms-list I think Bill was referring to Tom Forsyth's post in that thread.
Jan 13 2009