December 30, 2008
Weed wrote:
> Don пишет:
>> Weed wrote:
>>> Denis Koroskin пишет:
>>>
>>>>>  80490eb:       8d 85 6c fe ff ff       lea    -0x194(%ebp),%eax
>>>>>  80490f1:       50                      push   %eax
>>>>>  80490f2:       8d 85 2c fb ff ff       lea    -0x4d4(%ebp),%eax
>>>>>  80490f8:       e8 67 ff ff ff          *call   8049064*
>>>>>  80490fd:       e8 62 ff ff ff          *call   8049064*
>>>>>     return c2.i;
>>>>>  8049102:       8b 85 cc fc ff ff       mov    -0x334(%ebp),%eax
>>>>> ...
>>>>>
>>>>>
>>>>> (in 80490f8 and 80490fd simply two calls successively)
>>>>>
>>>>> If structures and classes were same that excellent optimization in any
>>>>> case would turn out
>>>> If that's your use case, then your should seriosly reconsider using
>>>> struct instead of class for your objects.
>>> Classes always give such overhead if them to use in such quality. For
>>> example, classes basically cannot be used as any mathematical objects
>>> using overload of arithmetics. But also not only arithmetics, it it is
>>> simple as a good example.
>>>
>>>> Alternatively, you can use +=
>>>> instead.
>>> Here yes, but if I add classes of different types? Then not to escape
>>> any more from creation of the temporary object in the heap.
>>>
>>>> Other than that, this is not a convincing argument.
>>>>
>>>> Reading many of your posts I came to a conclusion that you are
>>>> shortsighted and too crazy about performance. What you care about is a
>>>> premature optimization, which is a root of all the evil. You should
>>>> ensure that your programm is complete and correct, first and *then*
>>>> start doing profiling and optimizations.
>>> The program is already ready. It entirely consists of the various
>>> mathematics. Approximately %30 times of performance are spent for
>>> similar superfluous work. On C++ the program will work on %30 faster (I
>>> hope :)) and on D I am will turn out to do nothing with it.
>>>
>>>
>>>> Going back to the topic, dividing user types into two cathegories
>>>> (structs and classes) is considered modern and right.
>>> I do not accept such argument:)
>>>
>>>> Some languages
>>>> lack structs support at all (e.g. Java), but structs are too useful for
>>>> optimization and language interoperation to drop them in a systems
>>>> programming language. Some lack classes and try doing everything with
>>>> structs (C). D takes the best of both worlds.
>>> Probably I have not understood something, but I do not suggest to refuse
>>> structures in general. I suggest to allow to create classes on a stack
>>> as it is made in C++. That is actually to make structures and classes
>>> same, than they and are, for example, in C++.
>>>
>>> In the initial message I have shown that for perfomance important that
>>> the class could be transferred and on value. And it not artful premature
>>> optimisation - objects on value always so are transferred, all
>>> programmers know it and use when do not wish to allocate a place in a
>>> heap, that is usually always when the object will live in {}.
>>>
>>> Besides, a class in a stack it is normal - keyword addition "scope" for
>>> classes too speaks about it.
>>>
>>> Rigidly having divided classes and structures D deprives of the
>>> programmer of some possibilities which give it C++-like languages. I
>>> consider that such languages should give all possibilities which allows
>>> CPU but hiding concrete architecture, otherwise I would choose less
>>> difficult in use language.
>> 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.
> 
> And if polymorphism is necessary and such calculations are necessary as
> I have above described? To emulate polymorphism with the mixins? Or
> simply to reconcile to such obvious losses?
> 
> I about that that division into classes and structures in language D
> automatically reduce perfomance of programs. Unlike languages where this
> division is not present (C++).

There is a niche of cases where using the C++-style duality of classes and structs is useful. I think those cases are marginal, and that the conceptual division fostered by D is the better way to go because it's clean and avoids a lot of the inherent problems of duality.

Andrei
December 30, 2008
Don wrote:
> Christopher Wright wrote:
>> Don wrote:
>>> The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:
>>
>> The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.
> 
> That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.
> 
>>
>> Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass.
>>
>> I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.
> 
> I'm talking about a language solution. I want to solve this for the general case.

Don't forget that the case you are solving is not general enough because  you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.

Andrei
December 30, 2008
Andrei Alexandrescu пишет:
> Weed wrote:
>> Don пишет:
>>> Weed wrote:
>>>> Denis Koroskin пишет:
>>>>
>>>>>>  80490eb:       8d 85 6c fe ff ff       lea    -0x194(%ebp),%eax
>>>>>>  80490f1:       50                      push   %eax
>>>>>>  80490f2:       8d 85 2c fb ff ff       lea    -0x4d4(%ebp),%eax
>>>>>>  80490f8:       e8 67 ff ff ff          *call   8049064*
>>>>>>  80490fd:       e8 62 ff ff ff          *call   8049064*
>>>>>>     return c2.i;
>>>>>>  8049102:       8b 85 cc fc ff ff       mov    -0x334(%ebp),%eax
>>>>>> ...
>>>>>>
>>>>>>
>>>>>> (in 80490f8 and 80490fd simply two calls successively)
>>>>>>
>>>>>> If structures and classes were same that excellent optimization in
>>>>>> any
>>>>>> case would turn out
>>>>> If that's your use case, then your should seriosly reconsider using struct instead of class for your objects.
>>>> Classes always give such overhead if them to use in such quality. For example, classes basically cannot be used as any mathematical objects using overload of arithmetics. But also not only arithmetics, it it is simple as a good example.
>>>>
>>>>> Alternatively, you can use +=
>>>>> instead.
>>>> Here yes, but if I add classes of different types? Then not to escape any more from creation of the temporary object in the heap.
>>>>
>>>>> Other than that, this is not a convincing argument.
>>>>>
>>>>> Reading many of your posts I came to a conclusion that you are shortsighted and too crazy about performance. What you care about is a premature optimization, which is a root of all the evil. You should ensure that your programm is complete and correct, first and *then* start doing profiling and optimizations.
>>>> The program is already ready. It entirely consists of the various mathematics. Approximately %30 times of performance are spent for similar superfluous work. On C++ the program will work on %30 faster (I hope :)) and on D I am will turn out to do nothing with it.
>>>>
>>>>
>>>>> Going back to the topic, dividing user types into two cathegories (structs and classes) is considered modern and right.
>>>> I do not accept such argument:)
>>>>
>>>>> Some languages
>>>>> lack structs support at all (e.g. Java), but structs are too useful
>>>>> for
>>>>> optimization and language interoperation to drop them in a systems
>>>>> programming language. Some lack classes and try doing everything with
>>>>> structs (C). D takes the best of both worlds.
>>>> Probably I have not understood something, but I do not suggest to
>>>> refuse
>>>> structures in general. I suggest to allow to create classes on a stack
>>>> as it is made in C++. That is actually to make structures and classes
>>>> same, than they and are, for example, in C++.
>>>>
>>>> In the initial message I have shown that for perfomance important that
>>>> the class could be transferred and on value. And it not artful
>>>> premature
>>>> optimisation - objects on value always so are transferred, all
>>>> programmers know it and use when do not wish to allocate a place in a
>>>> heap, that is usually always when the object will live in {}.
>>>>
>>>> Besides, a class in a stack it is normal - keyword addition "scope" for classes too speaks about it.
>>>>
>>>> Rigidly having divided classes and structures D deprives of the programmer of some possibilities which give it C++-like languages. I consider that such languages should give all possibilities which allows CPU but hiding concrete architecture, otherwise I would choose less difficult in use language.
>>> 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.
>>
>> And if polymorphism is necessary and such calculations are necessary as I have above described? To emulate polymorphism with the mixins? Or simply to reconcile to such obvious losses?
>>
>> I about that that division into classes and structures in language D automatically reduce perfomance of programs. Unlike languages where this division is not present (C++).
> 
> There is a niche of cases where using the C++-style duality of classes and structs is useful. I think those cases are marginal, and that the conceptual division fostered by D is the better way to go because it's clean and avoids a lot of the inherent problems of duality.


It is very a pity.
My small opinion: it is impossible to reduce performance for struggle
against potential errors - such languages already are, it more
high-level. It how to refuse pointers because they are dangerous,
difficult for beginners and without them it is possible to make any
algorithm.


What is D?
D is a general purpose systems and applications programming language. It
is a higher level language than C++, but *retains* the ability to write
high performance code and interface directly with the operating system
API's and with hardware.
http://www.digitalmars.com/d/2.0/overview.html
December 30, 2008
Andrei Alexandrescu wrote:
> Don wrote:
>> Christopher Wright wrote:
>>> Don wrote:
>>>> The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:
>>>
>>> The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.
>>
>> That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.
>>
>>>
>>> Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass.
>>>
>>> I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.
>>
>> I'm talking about a language solution. I want to solve this for the general case.
> 
> Don't forget that the case you are solving is not general enough because  you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.

Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.
December 30, 2008
Weed wrote:
[about structs vs. classes]
> It is very a pity.
> My small opinion: it is impossible to reduce performance for struggle
> against potential errors - such languages already are, it more
> high-level. It how to refuse pointers because they are dangerous,
> difficult for beginners and without them it is possible to make any
> algorithm.

It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.

> What is D?
> D is a general purpose systems and applications programming language. It
> is a higher level language than C++, but *retains* the ability to write
> high performance code and interface directly with the operating system
> API's and with hardware.
> http://www.digitalmars.com/d/2.0/overview.html

Probably the worst thing that could happen to that description is it Kafka-esquely morphing into a dogma.


Andrei
December 30, 2008
Don wrote:
> Andrei Alexandrescu wrote:
>> Don wrote:
>>> Christopher Wright wrote:
>>>> Don wrote:
>>>>> The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:
>>>>
>>>> The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.
>>>
>>> That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.
>>>
>>>>
>>>> Essentially, you need a struct MyClassAddition that just records operands. Then give it an implicit cast to MyClass that does the work. This is an ugly solution because you need to duplicate the operator overloads on MyClassXXX as well as MyClass.
>>>>
>>>> I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.
>>>
>>> I'm talking about a language solution. I want to solve this for the general case.
>>
>> Don't forget that the case you are solving is not general enough because  you are focusing on eliminating temporaries, which is only part of the story. I suggest you make place in your thoughts for loop fusion.
> 
> Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.

I think the matrices case is important enough to make it its own class of problems. For example, bitmap processing is another instance of matrix usefulness, just one that doesn't usually jump to mind when thinking of matrices.

Then how about BigInt and arbitrary precision numbers? Wouldn't fusing some operations together be useful?


Andrei
December 30, 2008
On Wed, Dec 31, 2008 at 4:32 AM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> Don wrote:
>>
>> Andrei Alexandrescu wrote:
>>>
>>> Don wrote:
>>>>
>>>> Christopher Wright wrote:
>>>>>
>>>>> Don wrote:
>>>>>>
>>>>>> The creation of temporaries during expressions is something I'm currently working on solving. The case you mentioned is addressed by a proposal I made long ago:
>>>>>
>>>>> The easiest way is to add an intermediate struct. This takes a fair bit of manual effort, though, and prevents you from using auto.
>>>>
>>>> That particular case is the easiest possible one. The case x = y - x, for example, is much more difficult to recognize.
>>>>
>>>>>
>>>>> Essentially, you need a struct MyClassAddition that just records
>>>>> operands. Then give it an implicit cast to MyClass that does the work. This
>>>>> is an ugly solution because you need to duplicate the operator overloads on
>>>>> MyClassXXX as well as MyClass.
>>>>>
>>>>> I believe I got this solution from an article by Andrei. It should work pretty well for classes that define few overloads.
>>>>
>>>> I'm talking about a language solution. I want to solve this for the general case.
>>>
>>> Don't forget that the case you are solving is not general enough because
>>>  you are focusing on eliminating temporaries, which is only part of the
>>> story. I suggest you make place in your thoughts for loop fusion.
>>
>> Yes. That's the classic problem for matrices, but I'm still trying to work out if it is really a general problem. I was hoping to see some new use cases, but none so far.
>
> I think the matrices case is important enough to make it its own class of problems. For example, bitmap processing is another instance of matrix usefulness, just one that doesn't usually jump to mind when thinking of matrices.

Graph algorithms can often be thought of as matrices too.
I recall some shortest path algorithms where you write edge weight
between node i & j in the i,j entry.  Then you do a multiply on the
matrices, but instead of using the regular vector inner product for
each <row, column>, you use max().  I forget which algo it is.  I'm
thinking Floyd-Warshall.  Also there was some algorithm I recall that
can be done with a boolean matrix.  Probably some kind of connected
components algo?

--bb
December 30, 2008
Andrei Alexandrescu:
> What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.

But probably C compilers (and JavaVirtualMachines) have improved from the first ones, so the performance difference is now smaller. And in GCC if you use C you find lot of intrinsics (for example one for each new SIMD instruction) that mitigates the problem even more.

Bye,
bearophile
December 30, 2008
Bill Baxter wrote:
> On Wed, Dec 31, 2008 at 4:32 AM, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>> Don wrote:
>>> Andrei Alexandrescu wrote:
>>>> Don wrote:
>>>>> Christopher Wright wrote:
>>>>>> Don wrote:
>>>>>>> The creation of temporaries during expressions is something I'm
>>>>>>> currently working on solving. The case you mentioned is addressed by a
>>>>>>> proposal I made long ago:
>>>>>> The easiest way is to add an intermediate struct. This takes a fair bit
>>>>>> of manual effort, though, and prevents you from using auto.
>>>>> That particular case is the easiest possible one. The case x = y - x,
>>>>> for example, is much more difficult to recognize.
>>>>>
>>>>>> Essentially, you need a struct MyClassAddition that just records
>>>>>> operands. Then give it an implicit cast to MyClass that does the work. This
>>>>>> is an ugly solution because you need to duplicate the operator overloads on
>>>>>> MyClassXXX as well as MyClass.
>>>>>>
>>>>>> I believe I got this solution from an article by Andrei. It should work
>>>>>> pretty well for classes that define few overloads.
>>>>> I'm talking about a language solution. I want to solve this for the
>>>>> general case.
>>>> Don't forget that the case you are solving is not general enough because
>>>>  you are focusing on eliminating temporaries, which is only part of the
>>>> story. I suggest you make place in your thoughts for loop fusion.
>>> Yes. That's the classic problem for matrices, but I'm still trying to work
>>> out if it is really a general problem. I was hoping to see some new use
>>> cases, but none so far.
>> I think the matrices case is important enough to make it its own class of
>> problems. For example, bitmap processing is another instance of matrix
>> usefulness, just one that doesn't usually jump to mind when thinking of
>> matrices.
> 
> Graph algorithms can often be thought of as matrices too.
> I recall some shortest path algorithms where you write edge weight
> between node i & j in the i,j entry.  Then you do a multiply on the
> matrices, but instead of using the regular vector inner product for
> each <row, column>, you use max().  I forget which algo it is.  I'm
> thinking Floyd-Warshall.  Also there was some algorithm I recall that
> can be done with a boolean matrix.  Probably some kind of connected
> components algo?
> 
> --bb

Any graph algorithm that uses e.g. the adjacency matrix... well, uses a matrix :o).

Andrei
December 30, 2008
Andrei Alexandrescu пишет:
> Weed wrote:
> [about structs vs. classes]
>> It is very a pity.
>> My small opinion: it is impossible to reduce performance for struggle
>> against potential errors - such languages already are, it more
>> high-level. It how to refuse pointers because they are dangerous,
>> difficult for beginners and without them it is possible to make any
>> algorithm.
> 
> It's attractive to deal in absolutes, but also dangerous. When C came about, naysayers complained that it was consistently 30% slower than assembler, and generated larger code by an even higher margin. Then, some asked, what would you choose, one OS that's cool because it's written in C, or one that's one third faster? and so on. What people have forgotten by now is that C *was* high level. And it *did* incur a performance hit. It also had desirable properties that overcame that hit.
> 

Can in C# (it uses as far as I know too such sharing) such approach and it is justified - microsoft accelerates replacement of hardware for new OS. :) But we after all not blindly copy C#?

After all this problem can be solved, IMHO.
I suggest to make so:

1. To leave structures in that kind in which they is (POD)

2. To permit classes declaration such what they in C++

3. To permit transfer the classes on value (for compulsory pass by reference and for declaration through "new" now we have "ref" keyword)

3. To check slicing during compilation. It is possible?

4. "scope" for classes to deprecate as superfluous


In that case there will be problems?


>> What is D?
>> D is a general purpose systems and applications programming language. It
>> is a higher level language than C++, but *retains* the ability to write
>> high performance code and interface directly with the operating system
>> API's and with hardware.
>> http://www.digitalmars.com/d/2.0/overview.html
> 
> Probably the worst thing that could happen to that description is it Kafka-esquely morphing into a dogma.

Seriously, I trusted it