digitalmars.D - Give struct the status it deserves
- Hong (30/30) Mar 25 2006 Structs are second class citizens of... or maybe refugees of D, they are...
- Hasan Aljudy (4/49) Mar 25 2006 structs are a light wieght alternative to classes.
- Hong (11/14) Mar 25 2006 Thanks, that is one work arounds, the avoidance approach.
- Hasan Aljudy (3/24) Mar 26 2006 What's wrong with classes?!
- BCS (9/11) Mar 26 2006 HA!! I know someone who has done research on exactly that and says that ...
- Hong (11/13) Mar 26 2006 Ok, even people are telling me that class is not slower, I have decided ...
- Derek Parnell (10/24) Mar 26 2006 On my machine, the 'class' version was 135 times slower.
- Hasan Aljudy (28/54) Mar 26 2006 Heh, this is so flawed.
- Dave (32/86) Mar 26 2006 These run as the same speed on my system, which is pretty cool since the
- Derek Parnell (68/75) Mar 26 2006 I wasn't so sure about the 'passed around' claim. So I amended my test t...
- Dave (43/56) Mar 27 2006 Not what I'm seeing - give this a try:
- Derek Parnell (10/30) Mar 27 2006 You're right. I was using the 'inout' paradigm which uses byRef method. ...
- Hong (10/64) Mar 26 2006 Probably should point out that the major point of the benchmark is to te...
- Derek Parnell (108/134) Mar 26 2006 I think that you're amendment does not make them logically or otherwise ...
- Hasan Aljudy (9/45) Mar 26 2006 The program doesn't really do anything, you know. Creating a new
- Derek Parnell (15/59) Mar 27 2006 Wow! Really?! Are you sure?
- Wolfgang Draxinger (17/26) Mar 27 2006 It makes no difference for the use of objects if they are on the
- Alexander Panek (2/32) Mar 27 2006
- Hong (16/28) Mar 27 2006 Wolfgang wrote:
- Derek Parnell (14/24) Mar 27 2006 I really do understand the theory. And on the surface, it would seem tha...
- Hasan Aljudy (75/105) Mar 27 2006 Yes, I'm sure.
- Hasan Aljudy (60/63) Mar 27 2006 Here's a slightly modified version of Dave's code.
-
Dave
(7/14)
Mar 27 2006
That wasn't my intention
I just wanted to point out that classes can... - Ben Phillips (6/69) Mar 27 2006 Basically what your benchmark (along with Hong's) prove is that classes ...
- David Medlock (5/11) Mar 28 2006 Or if you still want to use classes, you can use an object pool.
- Charles (2/25) Mar 28 2006
- Derek Parnell (11/15) Mar 27 2006 I understand.
- Bruno Medeiros (79/88) Apr 02 2006 Now this is odd. I didn't expect classes on the heap to be much slower
- Thomas Kuehne (10/15) Apr 02 2006 -----BEGIN PGP SIGNED MESSAGE-----
- Bruno Medeiros (7/22) Apr 02 2006 AGH... seems the Windows search doesn't search inside *.d files, thus, I...
- Hasan Aljudy (2/25) Apr 02 2006 I use Visual Studio's "find in files" feature.
- James Dunne (12/35) Apr 02 2006 Windows Search only works on file extensions that it has search filters
- Bruno Medeiros (17/38) Apr 02 2006 Hum, after some testing it seems the class overhead is caused primarily
- Rioshin an'Harthen (53/84) Mar 27 2006 Heh, this is so flawed.
- Hasan Aljudy (6/120) Mar 27 2006 Heheh, how funny!
- John Reimer (7/20) Mar 25 2006 I agree with both these points, especially #1. I wish D had some sort
- Alexander Panek (29/73) Mar 26 2006 I don't know, but are you aware of what a struct is used for? It
- Hong (2/75) Mar 26 2006
- Alexander Panek (2/4) Mar 26 2006 Prove me wrong.
- Stewart Gordon (24/60) Mar 27 2006 Or they are writing or using a D interface to a C or other foreign API.
- Oskar Linde (29/71) Mar 27 2006 The problem with not having real constructors is that you can not
- Dave (50/72) Mar 27 2006 You know, with all of the talk of cache locality and what-not w.r.t. pas...
- Stewart Gordon (34/103) Mar 28 2006 Is the definition of a "real" constructor simply such that one is
- Norbert Nemec (22/22) Mar 28 2006 I partly agree with you.
-
Stewart Gordon
(15/22)
Mar 28 2006
Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons: 1. most D programmers don't use struct, unless they happen to be the poor guy writing the C interface. 2. to use structs you have to use pointers, but the spec says pointers are only provided for C compatibility, structs are to be avoided as long as the world spins. 3. pointers + overloaded operators make a mess.... this is a less offensive example: (*o) = (*t)[(*i) * (*j)] ... the pointers and operators are abusing each other. 4. structs cannot have constructor, "static opCall" is best you can do. 5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency. 6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer. 7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies. 8. structs have different behaviours between array and Vector, array [] returns a reference, Vector [] returns a copy, nice rookie trap. Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new" 2. add constructor for struct, destructors are not necessary. I use structs because I need efficiency and stack allocated data structures, however, it is painful to see a C++ program turns into a C like program when ported to D.
Mar 25 2006
Hong wrote:Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons: 1. most D programmers don't use struct, unless they happen to be the poor guy writing the C interface. 2. to use structs you have to use pointers, but the spec says pointers are only provided for C compatibility, structs are to be avoided as long as the world spins. 3. pointers + overloaded operators make a mess.... this is a less offensive example: (*o) = (*t)[(*i) * (*j)] ... the pointers and operators are abusing each other. 4. structs cannot have constructor, "static opCall" is best you can do. 5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency. 6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer. 7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies. 8. structs have different behaviours between array and Vector, array [] returns a reference, Vector [] returns a copy, nice rookie trap. Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new" 2. add constructor for struct, destructors are not necessary. I use structs because I need efficiency and stack allocated data structures, however, it is painful to see a C++ program turns into a C like program when ported to D.structs are a light wieght alternative to classes. Seriously, if structs don't suffice for your needs, use classes! You won't lose /that/ much performance.
Mar 25 2006
Thanks, that is one work arounds, the avoidance approach. There are 2 approaches to structs, 1. Minimalist approach, use structs only for C interfaces, and tiny data types such as Point for GUI programming. Most Java programmer would prefer this. 2. Use structs for all data structures that do not require heap allocation, such as containers. MinTL is a good example. However, current support for struct makes this approach difficult. People used to C++ might prefer this approach, when performance is critical. If D is to gain a foot hold on the high performance computing world, such as scientific computing, more support for struct will be needed. In article <e044ro$ifn$1 digitaldaemon.com>, Hasan Aljudy says...structs are a light wieght alternative to classes. Seriously, if structs don't suffice for your needs, use classes! You won't lose /that/ much performance.
Mar 25 2006
What's wrong with classes?! Classes won't make your code slow. Hong wrote:Thanks, that is one work arounds, the avoidance approach. There are 2 approaches to structs, 1. Minimalist approach, use structs only for C interfaces, and tiny data types such as Point for GUI programming. Most Java programmer would prefer this. 2. Use structs for all data structures that do not require heap allocation, such as containers. MinTL is a good example. However, current support for struct makes this approach difficult. People used to C++ might prefer this approach, when performance is critical. If D is to gain a foot hold on the high performance computing world, such as scientific computing, more support for struct will be needed. In article <e044ro$ifn$1 digitaldaemon.com>, Hasan Aljudy says...structs are a light wieght alternative to classes. Seriously, if structs don't suffice for your needs, use classes! You won't lose /that/ much performance.
Mar 26 2006
In article <e07506$1ss2$1 digitaldaemon.com>, Hasan Aljudy says...What's wrong with classes?! Classes won't make your code slow.HA!! I know someone who has done research on exactly that and says that they make code VARY slow (as in several times slower) I'll talk to him tomorrow and see if I can get some links to post. One example of things that make classes slow is that all methods are called by reference (from object* get vtbl (1), add index (2), load (3) call from ptr(4) as opposed to call function from incline address) The other thing is that structs don't have a vtbl in each instance and therefor can be used to map data to files and hardwear.
Mar 26 2006
Ok, even people are telling me that class is not slower, I have decided to make a benchmark to test them out. Here they are, Version using struct http://members.iinet.net.au/~honglee/benchmark/benchmarkstruct.d Version using class http://members.iinet.net.au/~honglee/benchmark/benchmarkclass.d On my computer, the struct version runs 300 times faster than the class version. Interestingly, deleting the object explicitly in the class version actually slowed the program even further. The difference seems real. In article <e07506$1ss2$1 digitaldaemon.com>, Hasan Aljudy says...What's wrong with classes?! Classes won't make your code slow.
Mar 26 2006
On Mon, 27 Mar 2006 00:32:40 +0000 (UTC), Hong wrote:Ok, even people are telling me that class is not slower, I have decided to make a benchmark to test them out. Here they are, Version using struct http://members.iinet.net.au/~honglee/benchmark/benchmarkstruct.d Version using class http://members.iinet.net.au/~honglee/benchmark/benchmarkclass.d On my computer, the struct version runs 300 times faster than the class version. Interestingly, deleting the object explicitly in the class version actually slowed the program even further. The difference seems real.On my machine, the 'class' version was 135 times slower. I changed the 'struct' version to use a pointer (Point *p = new Point;) and that now took 50 times slower than the first struct version. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 27/03/2006 12:05:14 PM
Mar 26 2006
Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version. on my machine:class100000000 operation took 0 m 0.25 sstruct100000000 operation took 0 m 15.265 s Try to come up with a more realistic example, and optamize both versions. This way, you can prove that it's the class vs. struct issue and not an optimization issue. Hong wrote:Ok, even people are telling me that class is not slower, I have decided to make a benchmark to test them out. Here they are, Version using struct http://members.iinet.net.au/~honglee/benchmark/benchmarkstruct.d Version using class http://members.iinet.net.au/~honglee/benchmark/benchmarkclass.d On my computer, the struct version runs 300 times faster than the class version. Interestingly, deleting the object explicitly in the class version actually slowed the program even further. The difference seems real. In article <e07506$1ss2$1 digitaldaemon.com>, Hasan Aljudy says...What's wrong with classes?! Classes won't make your code slow.
Mar 26 2006
These run as the same speed on my system, which is pretty cool since the accessor function for class Point.x is vitual. If you finalize it the class version is actually faster. No doubt the OP has a point when you try to alloc. classes in a tight loop, and I'd agree that stack allocated classes would be great, but if you can work around the allocation bottleneck then classes tend to be faster and easier to code because they are passed around by reference w/o pointer syntax. class Point { static int count = 0; int _x = 1; int x() { return _x; } // this is vitual } Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } ;--- struct Point { static int count = 0; int _x = 1; package int x() { return _x; } } Point p; for (uint i = 0; i < n; ++i) { Point.count += p.x; } In article <e07ka1$2kml$1 digitaldaemon.com>, Hasan Aljudy says...Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version. on my machine:class100000000 operation took 0 m 0.25 sstruct100000000 operation took 0 m 15.265 s Try to come up with a more realistic example, and optamize both versions. This way, you can prove that it's the class vs. struct issue and not an optimization issue. Hong wrote:Ok, even people are telling me that class is not slower, I have decided to make a benchmark to test them out. Here they are, Version using struct http://members.iinet.net.au/~honglee/benchmark/benchmarkstruct.d Version using class http://members.iinet.net.au/~honglee/benchmark/benchmarkclass.d On my computer, the struct version runs 300 times faster than the class version. Interestingly, deleting the object explicitly in the class version actually slowed the program even further. The difference seems real. In article <e07506$1ss2$1 digitaldaemon.com>, Hasan Aljudy says...What's wrong with classes?! Classes won't make your code slow.
Mar 26 2006
On Mon, 27 Mar 2006 04:11:37 +0000 (UTC), Dave wrote:These run as the same speed on my system, which is pretty cool since the accessor function for class Point.x is vitual. If you finalize it the class version is actually faster. No doubt the OP has a point when you try to alloc. classes in a tight loop, and I'd agree that stack allocated classes would be great, but if you can work around the allocation bottleneck then classes tend to be faster and easier to code because they are passed around by reference w/o pointer syntax.I wasn't so sure about the 'passed around' claim. So I amended my test to pass the object and the results were almost identical. So it appears that passing structs is not an issue at all. In fact, if you look at the generated machine code, the struct seems to be passed by reference even if you code otherwise. ------------------ version(test_struct_stack) { struct Point { static int count = 0; int x() { return 1; } } void upd(Point p) { Point.count += p.x; } void doit() { Point p; upd(p); } const static char[] Title = "STACK STRUCTS"; } version(test_struct_heap) { struct Point { static int count = 0; int x() { return 1; } } void upd(Point p) { Point.count += p.x; } void doit() { Point *p = new Point; upd(*p); } const static char[] Title = "HEAP STRUCTS"; } version(test_class) { class Point { static int count = 0; int x() { return 1; } } void upd(Point p) { Point.count += p.x; } void doit() { Point p = new Point; upd(p); } const static char[] Title = "CLASSES"; } ----------------------- -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 27/03/2006 4:02:10 PM
Mar 26 2006
In article <17vpw8ovosqie$.1f65d29ys83k6$.dlg 40tude.net>, Derek Parnell says...On Mon, 27 Mar 2006 04:11:37 +0000 (UTC), Dave wrote:Not what I'm seeing - give this a try: import std.stdio, std.date; struct S { char[1000] str; } class C { char[1000] str; } void main() { const int y = 1_000_000; { S s; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooS(s); } d_time en = getUTCtime(); writefln((en-st) / cast(double)TicksPerSecond); } { C c = new C; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooC(c); } d_time en = getUTCtime(); writefln((en-st) / cast(double)TicksPerSecond); } } void fooS(S s) { s.str[] = '\0'; } void fooC(C c) { c.str[] = '\0'; }These run as the same speed on my system, which is pretty cool since the accessor function for class Point.x is vitual. If you finalize it the class version is actually faster. No doubt the OP has a point when you try to alloc. classes in a tight loop, and I'd agree that stack allocated classes would be great, but if you can work around the allocation bottleneck then classes tend to be faster and easier to code because they are passed around by reference w/o pointer syntax.I wasn't so sure about the 'passed around' claim. So I amended my test to pass the object and the results were almost identical. So it appears that passing structs is not an issue at all. In fact, if you look at the generated machine code, the struct seems to be passed by reference even if you code otherwise.
Mar 27 2006
On Mon, 27 Mar 2006 15:16:38 +0000 (UTC), Dave wrote:In article <17vpw8ovosqie$.1f65d29ys83k6$.dlg 40tude.net>, Derek Parnell says...You're right. I was using the 'inout' paradigm which uses byRef method. If you just use the 'in' paradigm, then it does copy struct data to the called routine. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 28/03/2006 10:19:18 AMOn Mon, 27 Mar 2006 04:11:37 +0000 (UTC), Dave wrote:Not what I'm seeing - give this a try:These run as the same speed on my system, which is pretty cool since the accessor function for class Point.x is vitual. If you finalize it the class version is actually faster. No doubt the OP has a point when you try to alloc. classes in a tight loop, and I'd agree that stack allocated classes would be great, but if you can work around the allocation bottleneck then classes tend to be faster and easier to code because they are passed around by reference w/o pointer syntax.I wasn't so sure about the 'passed around' claim. So I amended my test to pass the object and the results were almost identical. So it appears that passing structs is not an issue at all. In fact, if you look at the generated machine code, the struct seems to be passed by reference even if you code otherwise.
Mar 27 2006
Probably should point out that the major point of the benchmark is to test the allocation and deallocation of 100000000 object or struct, i.e. test the performance between "stack allocation" and "heap allocation with GC". Anyway, your modified version is very flawed, for a number of reasons, * only one allocation is done for the class version but 100000000 structs were created, clearly not a comparison here. * structs are more or less designed to use stack allocation, but you forced it to use heap allocation and made it GC collected. This does not demonstrate how structs are used 99% of the time. In article <e07ka1$2kml$1 digitaldaemon.com>, Hasan Aljudy says...Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version. on my machine:class100000000 operation took 0 m 0.25 sstruct100000000 operation took 0 m 15.265 s Try to come up with a more realistic example, and optamize both versions. This way, you can prove that it's the class vs. struct issue and not an optimization issue. Hong wrote:Ok, even people are telling me that class is not slower, I have decided to make a benchmark to test them out. Here they are, Version using struct http://members.iinet.net.au/~honglee/benchmark/benchmarkstruct.d Version using class http://members.iinet.net.au/~honglee/benchmark/benchmarkclass.d On my computer, the struct version runs 300 times faster than the class version. Interestingly, deleting the object explicitly in the class version actually slowed the program even further. The difference seems real. In article <e07506$1ss2$1 digitaldaemon.com>, Hasan Aljudy says...What's wrong with classes?! Classes won't make your code slow.
Mar 26 2006
On Sun, 26 Mar 2006 19:57:08 -0700, Hasan Aljudy wrote:Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version.I think that you're amendment does not make them logically or otherwise the same. Your class version does one GC operation (create a new object) but your struct version does one GC operation per iteration - a new Point is allocated for every iteration. Here is my amended benchmark test program. In this, I test structs created on the stack, structs created on the heap, and classes (created on the heap of course). The class edition runs about 3 times longer than the heap struct edition and about 16 times longer that the stack struct edition. The heap struct edition runs about 5 times longer than the stack struct edition. So given that there is a big difference between classes (on the heap) and structs on the heap, those differences seem to be attributable to the implementation of classes over the implementation of structs. In these tests, all editions do one 'create' per iteration, and all use a member function in the created object. So in effect, the only differences are where the object resides and whether its a class or struct. // -------------- code starts ------------------- private import std.c.stdio; private import std.c.time; private import std.stdio; const static uint n = 100000000; version(test_struct_stack) { struct Point { static int count = 0; int x() { return 1; } } void doit() { Point p; Point.count += p.x; } const static char[] Title = "STACK STRUCTS"; } version(test_struct_heap) { struct Point { static int count = 0; int x() { return 1; } } void doit() { Point *p = new Point; Point.count += p.x; } const static char[] Title = "HEAP STRUCTS"; } version(test_class) { class Point { static int count = 0; int x() { return 1; } } void doit() { Point p = new Point; Point.count += p.x; } const static char[] Title = "CLASSES"; } int main() { clock_t time1 = clock(); for (uint i = 0; i < n; ++i) { doit(); } clock_t time2 = clock(); double seconds = (time2 - time1); seconds /= CLOCKS_PER_SEC; int minutes = cast(int)(seconds/60); seconds -= minutes*60; writefln("Testing %s %d operation took %sm %ss", Title, Point.count, minutes, seconds); return 0; } // -------------- code ends ------------------- Here is the compile and run output. --------------------------- C:\temp>build bt -version=test_struct_stack -Tbtss -full Path and Version : y:\util\build.exe v2.9(1197) built on Wed Aug 10 11:03:42 2005 y:\dmd\bin\..\..\dm\bin\link.exe bt,btss.exe,,user32+kernel32,btss.def/noi; C:\temp>build bt -version=test_struct_heap -Tbtsh -full Path and Version : y:\util\build.exe v2.9(1197) built on Wed Aug 10 11:03:42 2005 y:\dmd\bin\..\..\dm\bin\link.exe bt,btsh.exe,,user32+kernel32,btsh.def/noi; C:\temp>build bt -version=test_class -Tbtc -full Path and Version : y:\util\build.exe v2.9(1197) built on Wed Aug 10 11:03:42 2005 y:\dmd\bin\..\..\dm\bin\link.exe bt,btc.exe,,user32+kernel32,btc.def/noi; C:\temp>btss Testing STACK STRUCTS 100000000 operation took 0m 5.648s C:\temp>btsh Testing HEAP STRUCTS 100000000 operation took 0m 27.68s C:\temp>btc Testing CLASSES 100000000 operation took 1m 31.462s C:\temp> --------------------------- -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 27/03/2006 3:29:29 PM
Mar 26 2006
Derek Parnell wrote:On Sun, 26 Mar 2006 19:57:08 -0700, Hasan Aljudy wrote:The program doesn't really do anything, you know. Creating a new instance serves no purpose at all. So, as an optimization, you can do away without constant allocation; just reuse the same object. The example serves very well to illustrate how slow it is to allocate millions of objects on the heap in one go. However, it provides no proof that, in pratical situations, structs are much much faster than classes. Which is basically what the example tries to hint at.Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version.I think that you're amendment does not make them logically or otherwise the same. Your class version does one GC operation (create a new object) but your struct version does one GC operation per iteration - a new Point is allocated for every iteration.
Mar 26 2006
On Mon, 27 Mar 2006 17:12:34 +1100, Hasan Aljudy <hasan.aljudy gmail.com> wrote:Derek Parnell wrote:Wow! Really?! Are you sure?On Sun, 26 Mar 2006 19:57:08 -0700, Hasan Aljudy wrote:The program doesn't really do anything, you know.Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version.I think that you're amendment does not make them logically or otherwise the same. Your class version does one GC operation (create a new object) but your struct version does one GC operation per iteration - a new Point is allocated for every iteration.Creating a new instance serves no purpose at all. So, as an optimization, you can do away without constant allocation; just reuse the same object.I think you are deliberately missing the point, Hasan. I thought the point was to show that heap-allocated things are inherently slower than stack-allocated things. The original example didn't do a good job of that but my subsequent example does I believe. Can you please comment on my example code?The example serves very well to illustrate how slow it is to allocate millions of objects on the heap in one go. However, it provides no proof that, in pratical situations, structs are much much faster than classes. Which is basically what the example tries to hint at.But I think my example does show that classes (allocated on the heap) are slower than structs whether allocated on the heap or on the stack. Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong. -- Derek Parnell Melbourne, Australia
Mar 27 2006
Derek Parnell wrote:It makes no difference for the use of objects if they are on the heap or on the stack. Both are only portions of the same address space (and may even clash if they interpenetrate). The only thing that makes things slow is the allocation of heap memory which may cause the garbage collector to kick in. But once the memory is allocated it can be used as fast as stack memory.Creating a new instance serves no purpose at all. So, as an optimization, you can do away without constant allocation; just reuse the same object.I think you are deliberately missing the point, Hasan. I thought the point was to show that heap-allocated things are inherently slower than stack-allocated things.Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong.I don't see a reason for this. There's no difference in accessing the data. Put a struct on the stack, the compiler will compile it to access it indirectly (i.e. by "pointers"). Allocate a class on the heap, it get's accessed in the very same way. As a rule of thumb: Any data you going to work with in a D program is encapsulated in classes. Stuff that gets dumped into files or memory goes into structs. It's that simple. -- Wolfgang Draxinger
Mar 27 2006
Amen! Wolfgang Draxinger wrote:Derek Parnell wrote:It makes no difference for the use of objects if they are on the heap or on the stack. Both are only portions of the same address space (and may even clash if they interpenetrate). The only thing that makes things slow is the allocation of heap memory which may cause the garbage collector to kick in. But once the memory is allocated it can be used as fast as stack memory.Creating a new instance serves no purpose at all. So, as an optimization, you can do away without constant allocation; just reuse the same object.I think you are deliberately missing the point, Hasan. I thought the point was to show that heap-allocated things are inherently slower than stack-allocated things.Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong.I don't see a reason for this. There's no difference in accessing the data. Put a struct on the stack, the compiler will compile it to access it indirectly (i.e. by "pointers"). Allocate a class on the heap, it get's accessed in the very same way. As a rule of thumb: Any data you going to work with in a D program is encapsulated in classes. Stuff that gets dumped into files or memory goes into structs. It's that simple.
Mar 27 2006
Derek made the benchmark quite nice, thank you for that. Wolfgang wrote:The only thing that makes things slow is the allocation of heap memory which may cause the garbage collector to kick in.Wolfgang wrote:But once the memory is allocated it can be used as fast as stack memory.This is not entirely correct. Memory fragmentation means that cache miss is much more frequent on heap allocated data structures. Struct makes it such that data can be bundled nicely together in memory, making them faster to access. Wolfgang wrote:I don't see a reason for this. There's no difference in accessing the data. Put a struct on the stack, the compiler will compile it to access it indirectly (i.e. by "pointers"). Allocate a class on the heap, it get's accessed in the very same way.Derek meant that struct allocation is much faster than class allocation (~150x), allocation needs to be included when measuring performance, not just access speed. Wolfgang wrote:As a rule of thumb: Any data you going to work with in a D program is encapsulated in classes. Stuff that gets dumped into files or memory goes into structs. It's that simple.This is the minimal struct approach. However, since that we have already shown that struct allocation/deallocation is more than 100x faster, it makes good sense to use struct for data types that require enormous amount of allocation/deallocation, such as Vector3d in computer graphics, or Point in GUI programming. In fact minTL uses struct to create containers.
Mar 27 2006
On Mon, 27 Mar 2006 22:40:21 +1100, Wolfgang Draxinger <wdraxinger darkstargames.de> wrote:Derek Parnell wrote:I really do understand the theory. And on the surface, it would seem that your analysis is valid, however the timings show otherwise. There really is a difference between heap-allocated classes and heap-allocated structs. Classes are slower. Prove it yourself. Write your own benchmark test and submit its results. Critique my example - pull it apart and improve it. Show me where I've bungled. Until then, the figures show that classes are always slower than structs when used for equivalent tasks.Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong.I don't see a reason for this. There's no difference in accessing the data. Put a struct on the stack, the compiler will compile it to access it indirectly (i.e. by "pointers"). Allocate a class on the heap, it get's accessed in the very same way.As a rule of thumb: Any data you going to work with in a D program is encapsulated in classes. Stuff that gets dumped into files or memory goes into structs. It's that simple.Yes it is - in theory. Practice may dicate otherwise though. -- Derek Parnell Melbourne, Australia
Mar 27 2006
Derek Parnell wrote:On Mon, 27 Mar 2006 17:12:34 +1100, Hasan Aljudy <hasan.aljudy gmail.com> wrote:<snip>Yes, I'm sure. In practical situations, allocating stuff on the heap is not really what you want to do in your program; it's just a way to achieve what you want to do. If you don't understand what I mean, take this very simple example: You want to print numbers 1 through 1000 on the screen. you can do it with a while loop: int i = 0; while( i <= 1000 ) { writefln(i); i++; } but, you can also do it with a for loop: for( int i = 0; i <= 1000; i++ ) { writefln(i); } and a goto int i = 0; doit: i++; writefln(i); if( i <= 1000 ) goto doit; and here's another while loop: int i = 0; while( true ) { writefln(i); i++; if( i > 1000 ) break; } or, you can do it sorta like this: writefln(1); writefln(2); writefln(3); . . . writefln(999); writefln(1000); all these programs do the same thing, they just do it differently. Philisophically, you can argue that these programs do different things, the first one does a while loop, the second one does a for loop, the third one does a goto, the last one does it sequentially .. etc. However, practically, you're doing the same thing, in different ways. Some ways can be faster than the others. Here for example, is a stupid way of doing the above program: for( int i = 0; i <= 1000; i++ ) { writefln(i); for( int j = 0; j < 1000000000; j++ ) { //waste time int y = 10; int x = 5; x = x + y; } } However, it still works. Just .... very slow. This applies to the given benchmark. You're not doing anything, besides wasting heap space and wasting time allocating on the heap.The program doesn't really do anything, you know.Wow! Really?! Are you sure?OK, sorry, I didn't check your example yet. This does not affect my point. Memory allocation is not the only thing you do with classes/structs. I'd like to think of it as just an implementation/optimization issue. One thing were classes would win over structs is pass by reference vs. pass by value. Create a huge struct, with say, 40 or 50 fields, instantiate it once, then pass it around by value inside a loop (say, a 1000 times). Then edit the program and change the struct to a class, and when you create it, use "new", and don't change anything else.Creating a new instance serves no purpose at all. So, as an optimization, you can do away without constant allocation; just reuse the same object.I think you are deliberately missing the point, Hasan. I thought the point was to show that heap-allocated things are inherently slower than stack-allocated things. The original example didn't do a good job of that but my subsequent example does I believe. Can you please comment on my example code?The example serves very well to illustrate how slow it is to allocate millions of objects on the heap in one go. However, it provides no proof that, in pratical situations, structs are much much faster than classes. Which is basically what the example tries to hint at.But I think my example does show that classes (allocated on the heap) are slower than structs whether allocated on the heap or on the stack. Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong. --Derek Parnell Melbourne, Australia
Mar 27 2006
Derek Parnell wrote:Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong.Here's a slightly modified version of Dave's code. ------- import std.stdio, std.date; struct S { char[10000] str; } class C { char[10000] str; } void main() { const int y = 1_000_000_0; //structs { S s; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooS(s); } d_time en = getUTCtime(); writef("struct: "); writefln((en-st) / cast(double)TicksPerSecond); } //classes { C c = new C; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooC(c); } d_time en = getUTCtime(); writef("class: "); writefln((en-st) / cast(double)TicksPerSecond); } } void fooS(S s) { s.str[9999] = 15; } void fooC(C c) { c.str[9999] = 15; } ---------- on my machine: C:\test\d\struct.vs.class\pass>dave struct: 44.422 class: 0.046 that's about 1000 times faster 44.422/.046 = 965.696 Note: I don't believe this to be a valid benchmark, but I believe it's just as valid as Hong's benchmark. It's designed to make the class version win.
Mar 27 2006
In article <e09vl7$2u5f$1 digitaldaemon.com>, Hasan Aljudy says...Derek Parnell wrote:That wasn't my intention <g> I just wanted to point out that classes can have an advantage as well. I think Don Clungston's recent post regarding optimizing temp. creation out of things like opAdd could solve many concerns about having to use structs in place of classes because of heap allocation bottlenecks. - DaveClasses are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong.Note: I don't believe this to be a valid benchmark, but I believe it's just as valid as Hong's benchmark. It's designed to make the class version win.
Mar 27 2006
Basically what your benchmark (along with Hong's) prove is that classes and structs each have different uses (duh!). Use structs in situations like Hong's case where classes would require a ton of allocation, and use classes in situations like your case where passing by value would induce enormous overhead costs. In article <e09vl7$2u5f$1 digitaldaemon.com>, Hasan Aljudy says...Derek Parnell wrote:Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong.Here's a slightly modified version of Dave's code. ------- import std.stdio, std.date; struct S { char[10000] str; } class C { char[10000] str; } void main() { const int y = 1_000_000_0; //structs { S s; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooS(s); } d_time en = getUTCtime(); writef("struct: "); writefln((en-st) / cast(double)TicksPerSecond); } //classes { C c = new C; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooC(c); } d_time en = getUTCtime(); writef("class: "); writefln((en-st) / cast(double)TicksPerSecond); } } void fooS(S s) { s.str[9999] = 15; } void fooC(C c) { c.str[9999] = 15; } ---------- on my machine: C:\test\d\struct.vs.class\pass>dave struct: 44.422 class: 0.046 that's about 1000 times faster 44.422/.046 = 965.696 Note: I don't believe this to be a valid benchmark, but I believe it's just as valid as Hong's benchmark. It's designed to make the class version win.
Mar 27 2006
Ben Phillips wrote:Basically what your benchmark (along with Hong's) prove is that classes and structs each have different uses (duh!). Use structs in situations like Hong's case where classes would require a ton of allocation, and use classes in situations like your case where passing by value would induce enormous overhead costs.Or if you still want to use classes, you can use an object pool. Since object pools are a nice paradigm in some instances, I wonder if a good standard set of library primitives could be built into phobos? -DavidM
Mar 28 2006
Or if you still want to use classes, you can use an object pool. Since object pools are a nice paradigm in some instances, I wonder if a good standard set of library primitives could be built into phobos?Good idea , I was wanting this recently too. David Medlock wrote:Ben Phillips wrote:Basically what your benchmark (along with Hong's) prove is that classes and structs each have different uses (duh!). Use structs in situations like Hong's case where classes would require a ton of allocation, and use classes in situations like your case where passing by value would induce enormous overhead costs.Or if you still want to use classes, you can use an object pool. Since object pools are a nice paradigm in some instances, I wonder if a good standard set of library primitives could be built into phobos? -DavidM
Mar 28 2006
On Mon, 27 Mar 2006 17:23:05 -0700, Hasan Aljudy wrote:Note: I don't believe this to be a valid benchmark, but I believe it's just as valid as Hong's benchmark. It's designed to make the class version win.I understand. To make them equivalent, use the 'inout' calling convention for the struct. Change to 'void fooS(inout S s)' and the timings are the same. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 28/03/2006 12:51:07 PM
Mar 27 2006
Derek Parnell wrote:But I think my example does show that classes (allocated on the heap) are slower than structs whether allocated on the heap or on the stack. Classes are slower than structs. Prove otherwise. I'm happy to be shown that I'm wrong. --Derek Parnell Melbourne, AustraliaNow this is odd. I didn't expect classes on the heap to be much slower than structs on the heap. After all, what is the extra overhead of classes? It has the size overhead of having 2 more pointers (for ClassInfo and for the monitor) and the overhead of initializing those pointers when instantiating a class. Anything else? I thought not, however, I tried to run a test (see code below), where I would simulate a class creation with a struct, adding that overhead, yet the struct version is still twice as fast (with or without optimization)! Why is that?? The best that I could find was by looking at the assembly code, and that in the class version a _d_newclass function is called instead of _d_new for the struct version, yet does _d_newclass do more than _d_new other than just initialize the pointers? // -------------- code starts ------------------- private import std.c.stdio; private import std.c.time; private import std.stdio; const static uint n = 100000000; struct PointStruct { void * classinfo; void * monitor; void Construct(void *newclassinfo) { this.classinfo = newclassinfo; this.monitor = cast(void *) 0x98765; } } void doitStruct() { PointStruct *p = new PointStruct; p.Construct(cast(void *) 0x12345678); } final class PointClass { } void doitClass() { PointClass p = new PointClass; } int main() { writefln(PointClass.classinfo.init.length," : ", PointStruct.sizeof); clock_t time1 = clock(); for (uint i = 0; i < n; ++i) { version(test_struct_heap) { doitStruct(); } version(test_class_heap) { doitClass(); } } double seconds = (clock() - time1); seconds /= CLOCKS_PER_SEC; writefln("Testing operation took %ss", seconds); return 0; } // -------------- code ends ------------------- sh-2.04$ build main -version=test_struct_heap -Tbtsh -full c:\devel\D.tools\dmd\bin\..\..\dm\bin\link.exe main,btsh.exe,,user32+kernel32,btsh.def/noi; sh-2.04$ build main -version=test_class_heap -Tbtch -full c:\devel\D.tools\dmd\bin\..\..\dm\bin\link.exe main,btch.exe,,user32+kernel32,btch.def/noi; sh-2.04$ time ./btsh.exe 8 - 8 Testing operation took 18.204s real 0m18.328s user 0m0.015s sys 0m0.015s sh-2.04$ time ./btch.exe 8 - 8 Testing operation took 42.516s real 0m42.625s user 0m0.015s sys 0m0.015s -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 02 2006
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bruno Medeiros schrieb am 2006-04-02:The best that I could find was by looking at the assembly code, and that in the class version a _d_newclass function is called instead of _d_new for the struct version, yet does _d_newclass do more than _d_new other than just initialize the pointers?have a look at: src/phobos/internal/gc/gc.d Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFEL8wo3w+/yD4P9tIRAgSsAJ9pC8xp4D8N5+ykxPueNKw0nmm1OwCgvcs1 U2k6rgOjvcYbtgYUJwjUKWY= =97Mb -----END PGP SIGNATURE-----
Apr 02 2006
Thomas Kuehne wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bruno Medeiros schrieb am 2006-04-02:AGH... seems the Windows search doesn't search inside *.d files, thus, I didn't find that before. Way to go Windows :( Seems I'll have to use the command line. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DThe best that I could find was by looking at the assembly code, and that in the class version a _d_newclass function is called instead of _d_new for the struct version, yet does _d_newclass do more than _d_new other than just initialize the pointers?have a look at: src/phobos/internal/gc/gc.d Thomas
Apr 02 2006
Bruno Medeiros wrote:Thomas Kuehne wrote:I use Visual Studio's "find in files" feature.-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bruno Medeiros schrieb am 2006-04-02:AGH... seems the Windows search doesn't search inside *.d files, thus, I didn't find that before. Way to go Windows :( Seems I'll have to use the command line.The best that I could find was by looking at the assembly code, and that in the class version a _d_newclass function is called instead of _d_new for the struct version, yet does _d_newclass do more than _d_new other than just initialize the pointers?have a look at: src/phobos/internal/gc/gc.d Thomas
Apr 02 2006
Bruno Medeiros wrote:Thomas Kuehne wrote:Windows Search only works on file extensions that it has search filters defined for. This is why you can search within Word / Excel (and many other binary format) documents as if they were text. I'm sure there's some way (aside from writing a custom search filter) to get Windows Search to treat '.d' files as text. I'd say the search idea was good, but should've defaulted to searching unknown files as UTF-8 encoded text just for a sensible default that could be worked around. -- Regards, James Dunne-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bruno Medeiros schrieb am 2006-04-02:AGH... seems the Windows search doesn't search inside *.d files, thus, I didn't find that before. Way to go Windows :( Seems I'll have to use the command line.The best that I could find was by looking at the assembly code, and that in the class version a _d_newclass function is called instead of _d_new for the struct version, yet does _d_newclass do more than _d_new other than just initialize the pointers?have a look at: src/phobos/internal/gc/gc.d Thomas
Apr 02 2006
Thomas Kuehne wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bruno Medeiros schrieb am 2006-04-02:Hum, after some testing it seems the class overhead is caused primarily by the call: _gc.setFinalizer(p, &new_finalizer); The class test with this line runs in 40 seconds. With just: _gc.setFinalizer(p, null); it runs in 31 seconds. And finally without the line at all it runs in 19 seconds, which is now quite close to the struct version. Since this class has no destructors (in it self, or in a base class), I think setting up a finalization is redundant, unless there is some need related to the monitor releasing (dont know about it). In any case there is some room for compiler optimization. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DThe best that I could find was by looking at the assembly code, and that in the class version a _d_newclass function is called instead of _d_new for the struct version, yet does _d_newclass do more than _d_new other than just initialize the pointers?have a look at: src/phobos/internal/gc/gc.d Thomas -----BEGIN PGP SIGNATURE----- iD8DBQFEL8wo3w+/yD4P9tIRAgSsAJ9pC8xp4D8N5+ykxPueNKw0nmm1OwCgvcs1 U2k6rgOjvcYbtgYUJwjUKWY= =97Mb -----END PGP SIGNATURE-----
Apr 02 2006
[sorry, couldn't resist :P] "Hasan Aljudy" <hasan.aljudy gmail.com> wrote:Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version.Heh, this is so flawed. The benchmark is designed so that the class version runs faster than the struct version. change class version to: for (uint i = 0; i < n; ++i) { Point p = new Point(); Point.count += p.x; // delete p; } and the struct version to: Point p; for (uint i = 0; i < n; ++i) { Point.count += p.x; }on my machine:on my machine:class100000000 operation took 0 m 0.25 sstruct100000000 operation took 0 m 15.265 sclass100000000 operation took 0 m 43.594 sstruct100000000 operation took 0 m 0.218 sTry to come up with a more realistic example, and optamize both versions. This way, you can prove that it's the class vs. struct issue and not an optimization issue.Maybe you should try to come up with a more realistic example, and optimize both. Now you optimized the class version, but not the struct version. It's easy to claim classes as faster when you selectively optimize one and not the other. I intentionally optimized the other way around. If your "optimization" proves classes are faster, then mine proves structs are faster. And the code is still the same - there's no logical difference in how they work (except for garbage collecting much more in the class version, as you had in the struct version). To be sure, if both are optimized: // struct Point p; for (uint i = 0; i < n; ++i) { p.count += p.x; } // class Point p = new Point(); for (uint i = 0; i < n; ++i) { p.count += p.x; // delete p; } the times for the class version change to:class100000000 operation took 0 m 0.25 s which is equivalent with the 0.218 s it took for the struct version. If you want to prove classes faster than structs, please don't go about it optimizing only the class version and not the struct one. Otherwise, you end up looking like a fool.
Mar 27 2006
Heheh, how funny! Dude, you're re-iterating my point exactly. I was *not* trying to prove that classes are faster than structs; I was just proving that the example is flawed, by providing a similarily flawed example!! Rioshin an'Harthen wrote:[sorry, couldn't resist :P] "Hasan Aljudy" <hasan.aljudy gmail.com> wrote:Heh, this is so flawed. it's got nothing to do with classes vs. structs. The benchmark is designed so that the struct version runs faster than the class version. change the class version to: Point p = new Point(); for (uint i = 0; i < n; ++i) { Point.count += p.x; // delete p; } and the struct version to: for (uint i = 0; i < n; ++i) { Point * p = new Point(); Point.count += p.x; } These programs don't logically do anything different. However, the class version now runs much much faster than the struct version.Heh, this is so flawed. The benchmark is designed so that the class version runs faster than the struct version. change class version to: for (uint i = 0; i < n; ++i) { Point p = new Point(); Point.count += p.x; // delete p; } and the struct version to: Point p; for (uint i = 0; i < n; ++i) { Point.count += p.x; }on my machine:on my machine:class100000000 operation took 0 m 0.25 sstruct100000000 operation took 0 m 15.265 sclass100000000 operation took 0 m 43.594 sstruct100000000 operation took 0 m 0.218 sTry to come up with a more realistic example, and optamize both versions. This way, you can prove that it's the class vs. struct issue and not an optimization issue.Maybe you should try to come up with a more realistic example, and optimize both. Now you optimized the class version, but not the struct version. It's easy to claim classes as faster when you selectively optimize one and not the other. I intentionally optimized the other way around. If your "optimization" proves classes are faster, then mine proves structs are faster. And the code is still the same - there's no logical difference in how they work (except for garbage collecting much more in the class version, as you had in the struct version). To be sure, if both are optimized: // struct Point p; for (uint i = 0; i < n; ++i) { p.count += p.x; } // class Point p = new Point(); for (uint i = 0; i < n; ++i) { p.count += p.x; // delete p; } the times for the class version change to:class100000000 operation took 0 m 0.25 s which is equivalent with the 0.218 s it took for the struct version. If you want to prove classes faster than structs, please don't go about it optimizing only the class version and not the struct one. Otherwise, you end up looking like a fool.
Mar 27 2006
Hong wrote:Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new" 2. add constructor for struct, destructors are not necessary. I use structs because I need efficiency and stack allocated data structures, however, it is painful to see a C++ program turns into a C like program when ported to D.of reference attribute for other types similar to that designed into classes. It's confusing moving back and forth between the practically deprecated pointers and the reference types native to classes. Nor do pointers and references always intermix adequately in ADT's. -JJR
Mar 25 2006
Hong wrote:Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons: 1. most D programmers don't use struct, unless they happen to be the poor guy writing the C interface.I don't know, but are you aware of what a struct is used for? It encapsules data and provides an easy access to chunks of data related to one bunch of information / object.2. to use structs you have to use pointers, but the spec says pointers are only provided for C compatibility, structs are to be avoided as long as the world spins.Who in the world told you not to use pointers? I haven't seen that in the documentation, sorry.3. pointers + overloaded operators make a mess.... this is a less offensive example: (*o) = (*t)[(*i) * (*j)] ... the pointers and operators are abusing each other. 4. structs cannot have constructor, "static opCall" is best you can do.Take a look at std.boxer, there you have a constructor like function/template.5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency.As said, I can't find anything in the documentation that says you should not use pointers. "Structs and unions are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type. External types can be defined by the operating system API, or by a file format. Object oriented features are provided with the class data type." -- http://www.digitalmars.com//d/struct.html6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer.What's the problem here? Same goes with classes.7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies. 8. structs have different behaviours between array and Vector, array [] returns a reference, Vector [] returns a copy, nice rookie trap.A Vector is no array, keep that in mind. There're still pointers, you know? ;)Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new"Pointers *are* necessary. D is a high level language, of course, but also provides the ability to write low level code. And structs, as they *are*, are a very important part of this ability.2. add constructor for struct, destructors are not necessary.As said before.I use structs because I need efficiency and stack allocated data structures, however, it is painful to see a C++ program turns into a C like program when ported to D.You can also provide effient code with classes, if you feel your code is 'ugly' with structs. Also, structs should not be abused. Structs are structs and classes are classes - they both have their specific purposes, one should not forget that. Regards, Alex PS: No offense intended.
Mar 26 2006
I hope you really know what you are talking about. In article <e06353$7o9$1 digitaldaemon.com>, Alexander Panek says...Hong wrote:Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons: 1. most D programmers don't use struct, unless they happen to be the poor guy writing the C interface.I don't know, but are you aware of what a struct is used for? It encapsules data and provides an easy access to chunks of data related to one bunch of information / object.2. to use structs you have to use pointers, but the spec says pointers are only provided for C compatibility, structs are to be avoided as long as the world spins.Who in the world told you not to use pointers? I haven't seen that in the documentation, sorry.3. pointers + overloaded operators make a mess.... this is a less offensive example: (*o) = (*t)[(*i) * (*j)] ... the pointers and operators are abusing each other. 4. structs cannot have constructor, "static opCall" is best you can do.Take a look at std.boxer, there you have a constructor like function/template.5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency.As said, I can't find anything in the documentation that says you should not use pointers. "Structs and unions are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type. External types can be defined by the operating system API, or by a file format. Object oriented features are provided with the class data type." -- http://www.digitalmars.com//d/struct.html6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer.What's the problem here? Same goes with classes.7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies. 8. structs have different behaviours between array and Vector, array [] returns a reference, Vector [] returns a copy, nice rookie trap.A Vector is no array, keep that in mind. There're still pointers, you know? ;)Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new"Pointers *are* necessary. D is a high level language, of course, but also provides the ability to write low level code. And structs, as they *are*, are a very important part of this ability.2. add constructor for struct, destructors are not necessary.As said before.I use structs because I need efficiency and stack allocated data structures, however, it is painful to see a C++ program turns into a C like program when ported to D.You can also provide effient code with classes, if you feel your code is 'ugly' with structs. Also, structs should not be abused. Structs are structs and classes are classes - they both have their specific purposes, one should not forget that. Regards, Alex PS: No offense intended.
Mar 26 2006
Hong wrote:I hope you really know what you are talking about.Prove me wrong.
Mar 26 2006
Hong wrote:Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons: 1. most D programmers don't use struct, unless they happen to be the poor guy writing the C interface.Or they are writing or using a D interface to a C or other foreign API. Or they want to save the overhead of memory allocation by using a lightweight alternative for those situations where the power of classes isn't needed. Or they are interfacing a binary file format.2. to use structs you have to use pointers, but the spec says pointers are only provided for C compatibility, structs are to be avoided as long as the world spins.No I don't. What are you talking about?3. pointers + overloaded operators make a mess.... this is a less offensive example: (*o) = (*t)[(*i) * (*j)] ... the pointers and operators are abusing each other. 4. structs cannot have constructor, "static opCall" is best you can do.What's wrong with that? Do you simply miss the word "new" in uses of static opCall?5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency.If you want classes, you know where to find them.6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer.Why would anyone want to do that? What's wrong with simply Qwert yuiop = asdfg; // to create a copy Qwert* zxcvb = &asdfg; // to create a pointer7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies.That's an issue with those containers, rather than with structs themselves.8. structs have different behaviours between array and Vector, array [] returns a reference, Vector [] returns a copy, nice rookie trap. Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new" 2. add constructor for struct, destructors are not necessary. I use structs because I need efficiency and stack allocated data structures, however, it is painful to see a C++ program turns into a C like program when ported to D.Maybe you could elaborate on how these reference semantics would work such that they'd be any different from classes. Stewart. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d- s:- C++ a->--- UB P+ L E W++ N+++ o K- w++ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y ------END GEEK CODE BLOCK------ My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 27 2006
Stewart Gordon wrote:Hong wrote:[snip]Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons:The problem with not having real constructors is that you can not guarantee that your struct gets initialized correctly.4. structs cannot have constructor, "static opCall" is best you can do.What's wrong with that? Do you simply miss the word "new" in uses of static opCall?Small structs (the cases were structs are most useful) can often more efficient to pass by value than by reference.5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency.If you want classes, you know where to find them.If I understand correctly, Hong is talking about struct members (i.e. a member variable of a struct type), that should be accessed through an accessor method. I.e: Array!(Position) points = ...; points[5].x = 7; Or: myInstance.pos.x = 5; (Where pos is accessed through a getter method)6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer.Why would anyone want to do that? What's wrong with simply Qwert yuiop = asdfg; // to create a copy Qwert* zxcvb = &asdfg; // to create a pointerI agree that this is not an issue with structs. But it is an issue with the language. Given: struct Position { int x,y; } There is no way to duplicate the behavior of: Position[] points = ...; points[5].y = 5; points[3].x += 2; With an user defined container type.7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies.That's an issue with those containers, rather than with structs themselves.You could consider: struct MyPointContainer { Position[] points; inout Position opIndex(uint ix) { return &points[ix]; } } Where inout denotes that the struct is returned by reference. /OskarImho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new"Maybe you could elaborate on how these reference semantics would work such that they'd be any different from classes.
Mar 27 2006
In article <e0948b$1ihl$1 digitaldaemon.com>, Oskar Linde says...Stewart Gordon wrote:You know, with all of the talk of cache locality and what-not w.r.t. passing small structs by value vs. reference, I've yet to see the "conventional wisdom" (that passing byref is faster) proven wrong, even in larger programs where there has to be things being constantly being moved in and out of cache, etc. I'm not saying that is always the case, but 'often' above is pretty strong there. I'd say at best "sometimes" is a better phrase. // Yes, yes I know this is may not reflect a typical 'real world' program // But still there is a 4x difference on my AMD64 and P4 ('modern // processor') boxen, with byref being the faster. import std.stdio, std.date; struct S { int i, j, k; } class C { int i, j, k; } void main() { const int y = 100_000_000; { S s; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooS(s); } d_time en = getUTCtime(); writefln("struct byval: ",(en-st) / cast(double)TicksPerSecond); } { S s; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooS2(&s); } d_time en = getUTCtime(); writefln("struct byref: ",(en-st) / cast(double)TicksPerSecond); } { C c = new C; d_time st = getUTCtime(); for(int x = 0; x < y; x++) { fooC(c); } d_time en = getUTCtime(); writefln("class: ",(en-st) / cast(double)TicksPerSecond); } } void fooS2(S* s) { s.i = s.j = s.k = 0; } void fooS(S s) { s.i = s.j = s.k = 0; } void fooC(C c) { c.i = c.j = c.k = 0; }Hong wrote:[snip]Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons:The problem with not having real constructors is that you can not guarantee that your struct gets initialized correctly.4. structs cannot have constructor, "static opCall" is best you can do.What's wrong with that? Do you simply miss the word "new" in uses of static opCall?Small structs (the cases were structs are most useful) can often more efficient to pass by value than by reference.5. structs are more efficient? Not when structs are passed around by value. To change a struct member: 1. make a copy 2. change the copy 3. Copy the copy back into the original location. Two damned copies for.... efficiency.If you want classes, you know where to find them.
Mar 27 2006
Oskar Linde wrote:Stewart Gordon wrote:Is the definition of a "real" constructor simply such that one is required to use a constructor rather than a static initialiser or leaving default initialisers to it? <snip>Hong wrote:[snip]Structs are second class citizens of... or maybe refugees of D, they are victims of discrimination. Following are the reasons:The problem with not having real constructors is that you can not guarantee that your struct gets initialized correctly.4. structs cannot have constructor, "static opCall" is best you can do.What's wrong with that? Do you simply miss the word "new" in uses of static opCall?Note that the OP hasn't mentioned container methods by this point. It therefore appears that this was about properties of the struct itself. But looking down, it now appears that it was *meant* to be about containers. <snip>If I understand correctly, Hong is talking about struct members (i.e. a member variable of a struct type), that should be accessed through an accessor method. I.e: Array!(Position) points = ...; points[5].x = 7;6. yes, you can use pointers to change a struct member without copying, if you can be bothered to define 2 accessor methods, one returns a copy another one returns a pointer.Why would anyone want to do that? What's wrong with simply Qwert yuiop = asdfg; // to create a copy Qwert* zxcvb = &asdfg; // to create a pointerYou can if you define opIndex to return a pointer. But that would require you to use a * when it's the value you need. Or, as was suggested, define a separate accessor method that returns a pointer. But I see your point now.I agree that this is not an issue with structs. But it is an issue with the language. Given: struct Position { int x,y; } There is no way to duplicate the behavior of: Position[] points = ...; points[5].y = 5; points[3].x += 2; With an user defined container type.7. Most standard containers (DTL) do not allow a pointer to a contained struct to be retrieved, all changes, or just about anything has to be done via copies.That's an issue with those containers, rather than with structs themselves.Yes, that's a possibility. Though the & ought not to be there - the referencing/dereferencing would be implicit on both sides with inout returns, just as it is with out/inout parameters. And it isn't giving structs reference semantics, it's a way of enabling returns from functions to have reference semantics in the same way as out/inout function parameters have. It would work on any type, not just structs. I suppose that, when this is done container[42] = something; would be interpreted by looking first for an opIndexAssign and then for an opIndex with inout return. But how would overload resolution work between the two forms? Stewart. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d- s:- C++ a->--- UB P+ L E W++ N+++ o K- w++ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y ------END GEEK CODE BLOCK------ My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.You could consider: struct MyPointContainer { Position[] points; inout Position opIndex(uint ix) { return &points[ix]; } } Where inout denotes that the struct is returned by reference.Imho, following are little suggestions for structs to make first class citizens of D: 1. have some sort of reference semantic to replace pointers. Pointers are not necessary unless structs are used with "new"Maybe you could elaborate on how these reference semantics would work such that they'd be any different from classes.
Mar 28 2006
I partly agree with you. 1) A constructor for structs would definitely be necessary: Currently, a struct is always initialized to all-zero fields. The "static opCall" is nice syntactic sugar for changing the contents of the struct afterwards, but it does not allow a guaranteed initialization, since D does not force you to call opCall. 2) Reference handling similar to C++ would be very desirable. Of course, a pointer can always be used instead, but it makes very ugly code and is probably one of the reasons why structs are used so rarely in D. 3) Yes, classes are inefficient when used for purposes that should be done with a struct. I have seen implementations of 3D-vector arithmetics in D where the vector was defined as class. This means: each vector has to be allocated on the heap!!! The benchmark example that you give may be artificial but it is not at all unrealistic to have a loop that allocates and deallocates 100000 small data structures. It makes a tremendous difference whether this is done on the heap or on the stack! It is good that D has a clear distinction between classes and structs, but structs should be viewed as an important concept and given all the power possible. Saying "use a class instead" is hardly ever an acceptable excuse for lacking power in structs. Greetings, Norbert
Mar 28 2006
Norbert Nemec wrote:I partly agree with you. 1) A constructor for structs would definitely be necessary: Currently, a struct is always initialized to all-zero fields. The "static opCall" is nice syntactic sugar for changing the contents of the struct afterwards, but it does not allow a guaranteed initialization, since D does not force you to call opCall.<snip> Struct members can have default initialisers. The only way in which it "does not allow a guaranteed initialization" is that it's possible to override default initialisers with a static initialiser. But that's just like changing members one-by-one after it's been initialised. Stewart. -- -----BEGIN GEEK CODE BLOCK----- Version: 3.1 GCS/M d- s:- C++ a->--- UB P+ L E W++ N+++ o K- w++ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y ------END GEEK CODE BLOCK------ My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit.
Mar 28 2006