Introducing alid
Ali Çehreli
acehreli at yahoo.com
Tue Sep 13 15:24:20 UTC 2022
On 9/12/22 22:24, Salih Dincer wrote:
> `source.CachedRange!(ElementCache!(Result)).CachedRange.front` is not
> callable using a `const` object
This exposes at least two issues:
1) The error was because I did not define cached's front as const
because it has to expand the underlying buffer (a member) as needed. (I
would have marked the buffer 'mutable' but we don't have that in D.)
This can be solved in some ways, crudest of which is the following:
(cast()this).expandAsNeeded(id, 1);
Which is technically undefined behavior because the 'cached' range
object could really be on read-only memory but since we are talking
about a range, and such objects are supposed to be mutated, it becomes
an interesting discussion at that point.
(There must be other ways like casting just the buffer but it is related
to the discussion below.)
After fixing it that way (not pushed to github), I hit another
compilation error.
2) This point is about a topic that I brought up recently: Types gain a
'const' eagerly (and they have to, understandably).
For example, in your example you are caching an 'int', but my code sees
const(int) just because std.range.Cycle.front chose to put a 'const' on
itself. (With all good intentions: Cycle.front really does not mutate a
Cycle object.)
However, as my range picks the element type with ElementType!T, I see
const(int) as well. Again, all good so far... And here is my opApply
funtion:
int opApply(int delegate(ref EC.ET) func) scope
{
while(!empty)
{
auto f = front;
int result = func(f); // ERROR
if (result)
{
return result;
}
popFront();
}
return 0;
}
ERROR: delegate `func(ref int)` is not callable using argument types
`(const(int))`
Oh! See: I am passing an int... oh! by ref... I guess I shouldn't
expect my users to use 'const' in their foreach parameters. (I am not
trying to see whether it is possible.)
So instead, I should have decided on my storage type as int (not
const(int)) in this case. It can be done like this:
static if (hasIndirections!(EC.ET))
{
// Use the exact type
alias StorageT = T;
}
else
{
alias StorageT = Unqual!T;
}
But... Do I have the right to choose my storage type as 'int' even
though I am caching const(int)? Perhaps I shouldn't because as discussed
earlier in the general forum, my choice changes function overloading for
my users. So, perhaps I should really store const(int)... (?)
I have to digest these issues more before jumping to a solution. :/
Ali
P.S. Related, I had to provide an opApply function because of this reason:
/**
Support for `foreach` loops
*/
// This is needed to support foreach iteration because although
// RefCounted!CachedRange implicitly converts to CachedRange, which would be
// a range, the result gets copied to the foreach loop. Unfortunately, this
// type does not allow copying so we have to support foreach iteration
// explicitly here.
int opApply(int delegate(ref EC.ET) func) scope
{
// ...
}
See that 'ref' there? Maybe I should have provided different opApply()
functions to cover all cases. I am thinking... :)
Or maybe I should use something else other than RefCounted... Still
thinking...
More information about the Digitalmars-d-announce
mailing list