On Thu, 29 Sep 2011 20:14:01 -0400, Peter Alexander
<peter.alexander...@gmail.com> wrote:
On 29/09/11 8:01 PM, Steven Schveighoffer wrote:
Again, I ask, what is a real-world example of something that needs lazy
caching (or where lazy caching significantly helps performance) for
comparison. You have already stated that you appreciate it's not const,
so you must have *something* that needs it.
1. A renderer lazily caching world transform matrices.
How does this relate to opEquals?
2. Collision detection queries often cache recent intermediate results
due to spacial coherency between queries.
Surely you are not doing collision detection with opEquals?
3. A simple asset loader may lazily load assets on demand (rather than
having to eagerly load things up front).
This is a good one. The thought of loading a resource just to throw it
away because const won't let you store it is not really acceptable.
I can see this being related to opEquals more than the others. I wonder
how often this would affect opEquals in practice.
I have to think about this, and how it could possibly be solvable. I
suspect we may need to do something that supports logical const
specifically for this problem (i.e. not generalized logical const). BTW,
see my other thread "logical const without casts" for a possible solution.
4. String hashes are cached all over the place for fast resource look
ups.
strings have no place to store a cache. Plus resource lookup is not
opEquals.
I'm honestly quite amazed that I have to justify my belief that caching
is useful, and commonly used. Caches are everywhere: your CPU has
multiple levels of caches, you hard disk has caches, your browser
caches, domain lookups are cached; and they're all lazy, too. Lazy
caching is a cornerstone of optimisation.
Oh, I am not questioning the value or usefulness of caching in general.
What I'm wondering is how often it's needed for comparisons.
What we are discussing is why opEquals should not be const, not why all
functions should not be const.
So far, I don't think it's a very common requirement. It certainly
doesn't seem like it's so important that the entire body of D code in
existence should have to deal with mutable opEquals. The fact that it's
mutable now is really a legacy D1 issue.
Inline assembler isn't a common requirement either, but that's no
argument to ignore it.
Inline assembler is a basic requirement, even if it's not used often.
Many low-level pieces depend on it.
Besides, having inline assembler does *not* affect code that does not use
inline assembler. This is not the same thing as making opEquals cater to
non-const implementations.
I suppose something like __restrict isn't very important to you either.
It's certainly used a lot less than lazy caching. However, it's worth
pointing out that __restrict was introduced into compilers through
popular demand by people that needed it. These things are real and
should not be ignored.
I'm unaware of __restrict, so I can't really comment on it.
But I'll respond to the general argument that something that isn't used
often is still useful:
Yes, things can be included that are used infrequently, as long as the
inclusion of such support does not adversely affect code that doesn't need
it. The problem we have here is:
1. opEquals is not const, so you cannot compare const objects. This is
downright unacceptable.
2. A compromise solution where opEquals is both const and non const in
Object sacrifices performance and simplicity for the benefit of having the
*possibility* of obj == obj working for lazy-caching opEquals.
3. Is it worth making the majority of opEquals implementations (i.e. those
that are const-only) lower performing in order to allow for the
possibility? How much do we gain by downgrading const opEquals?
4. Is it worth making existing code stop compiling in order to switch to
const opEquals exclusively?
My opinion is:
1. we need const opEquals. There is no debate on this I think.
2. The compromise solution is not worth the gain. I'd rather have most of
my objects compare as quickly as possible.
3. It should be possible to create a mutable opEquals and have it hook
with obj == obj. This is different than the compromise solution, which
puts both const and non-const opEquals in Object. This means we need to
reengineer how the compiler does opEquals for objects.
4. Yes, it is worth breaking existing compilation to switch to const
opEquals in Object.
-Steve