digitalmars.D - RE: division of objects into classes and structures is bad
Weed wrote:Don пишет:it isWeed wrote:Don пишет:Weed wrote: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, it80490eb: 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.about is asimple as a good example.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 carefaster (Ipremature 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 %30withhope :)) 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 everythingstackstructs (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 athatas 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"scope" forthe 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 additionallowsclasses 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 whichthisAnd 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 whereCPU but hiding concrete architecture, otherwise I would choose less difficult in use language.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.You certainly can do something about it. By rearranging the expression, you can avoid the unnecessary creation of temporaries.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.division is not present (C++).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.That's not what I meant. You can have an object which contains a pointer to heap-allocated data (eg, it could contain a dynamic array). Turning the object from a class into a struct does not remove the heap allocation.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.My point is that you might hope to be able to avoid memory allocation entirely, putting the new value of c2 in-place, but case (a) and (b) make it impossible. There will always be ONE heap allocation.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;OK, then you're getting into another issue...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.I fail to see how D's distinction between classes and structs has any bearing on this. The optimisations you're talking about are only possible in the presence of polymorphism, in cases where you can prove that polymorphism is not being used! I suspect that if you're encountering this issue in speed-critical code, there's a problem with your design.No, I think the design of objects in D is sound. I think operator overloading in both D and C++ is incomplete.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 ÐÉÛÅÔ:Weed wrote:I consider that it wrong and I quote myself: =========Don ÐÉÛÅÔ:it isWeed wrote:Don ÐÉÛÅÔ:Weed wrote: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, it80490eb: 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.is asimple as a good example.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 aboutfaster (Ipremature 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 %30withhope :)) 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 everythingstackstructs (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 athatas 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"scope" forthe 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 additionallowsclasses 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 whichthisAnd 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 whereCPU but hiding concrete architecture, otherwise I would choose less difficult in use language.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.You certainly can do something about it. By rearranging the expression, you can avoid the unnecessary creation of temporaries.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.division is not present (C++).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.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. =========Alternatively, you can use += instead.And still the object can to access, for example, to a file system in the constructor. :) But if the programmer has written object so that it was fast (did not use call to a heap) that all will be ok.That's not what I meant. You can have an object which contains a pointer to heap-allocated data (eg, it could contain a dynamic array). Turning the object from a class into a struct does not remove the heap allocation.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.If class are stored in a stack that there will be no.My point is that you might hope to be able to avoid memory allocation entirely, putting the new value of c2 in-place, but case (a) and (b) make it impossible. There will always be ONE heap allocation.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).Quite right, if polymorphism I would not be necessary to me did not use classes, it is obvious. All the rest that you have told it the common words so experts in marketing speak. :) I give concrete examples from a life where D is bad. You see a design problem in the code resulted above? By the way, one of serious problem: if necessary it is difficult enough to alter a class in structure and vice versa. Insufficiently simply to change the keyword. And it is serious, it is not necessary to me to tell about planning.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;OK, then you're getting into another issue...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.I fail to see how D's distinction between classes and structs has any bearing on this. The optimisations you're talking about are only possible in the presence of polymorphism, in cases where you can prove that polymorphism is not being used! I suspect that if you're encountering this issue in speed-critical code, there's a problem with your design.It simply sugar, it is not necessary to forgetNo, I think the design of objects in D is sound. I think operator overloading in both D and C++ is incomplete.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
Weed wrote:Don ÐÉÛÅÔ:If the overhead caused by using classes is unacceptable, then yes. I'd want to see the definition of "checkpoint". If it's really polymorphic, how can it be stored on the stack? This doesn't make sense to me.Weed wrote:I consider that it wrong and I quote myself: =========Don ÐÉÛÅÔ:it isWeed wrote:Don ÐÉÛÅÔ:Weed wrote: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, it80490eb: 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.is asimple as a good example.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 aboutfaster (Ipremature 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 %30withhope :)) 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 everythingstackstructs (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 athatas 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"scope" forthe 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 additionallowsclasses 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 whichthisAnd 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 whereCPU but hiding concrete architecture, otherwise I would choose less difficult in use language.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.You certainly can do something about it. By rearranging the expression, you can avoid the unnecessary creation of temporaries.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.division is not present (C++).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.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. =========Alternatively, you can use += instead.And still the object can to access, for example, to a file system in the constructor. :) But if the programmer has written object so that it was fast (did not use call to a heap) that all will be ok.That's not what I meant. You can have an object which contains a pointer to heap-allocated data (eg, it could contain a dynamic array). Turning the object from a class into a struct does not remove the heap allocation.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.If class are stored in a stack that there will be no.My point is that you might hope to be able to avoid memory allocation entirely, putting the new value of c2 in-place, but case (a) and (b) make it impossible. There will always be ONE heap allocation.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).Quite right, if polymorphism I would not be necessary to me did not use classes, it is obvious. All the rest that you have told it the common words so experts in marketing speak. :) I give concrete examples from a life where D is bad. You see a design problem in the code resulted above?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;OK, then you're getting into another issue...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.I fail to see how D's distinction between classes and structs has any bearing on this. The optimisations you're talking about are only possible in the presence of polymorphism, in cases where you can prove that polymorphism is not being used! I suspect that if you're encountering this issue in speed-critical code, there's a problem with your design.By the way, one of serious problem: if necessary it is difficult enough to alter a class in structure and vice versa. Insufficiently simply to change the keyword. And it is serious, it is not necessary to me to tell about planning.It simply sugar, it is not necessary to forgetNo, I think the design of objects in D is sound. I think operator overloading in both D and C++ is incomplete.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 ÐÉÛÅÔ:Where a problem?If the overhead caused by using classes is unacceptable, then yes. I'd want to see the definition of "checkpoint". If it's really polymorphic, how can it be stored on the stack? This doesn't make sense to me.Quite right, if polymorphism I would not be necessary to me did not use classes, it is obvious. All the rest that you have told it the common words so experts in marketing speak. :) I give concrete examples from a life where D is bad. You see a design problem in the code resulted above?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.I fail to see how D's distinction between classes and structs has any bearing on this. The optimisations you're talking about are only possible in the presence of polymorphism, in cases where you can prove that polymorphism is not being used! I suspect that if you're encountering this issue in speed-critical code, there's a problem with your design.By the way, one of serious problem: if necessary it is difficult enough to alter a class in structure and vice versa. Insufficiently simply to change the keyword. And it is serious, it is not necessary to me to tell about planning.
Dec 30 2008