Firstly, a name change. So far, the language has only been called "DeadMG++" for an informal name. However, I've currently decided to refer to it as WideC. Why this is, I've forgotten long ago, but I figure it's a better interim name. I've been grappling for some time now the idea of a relatively simple problem. How does one store constant expressions in a type? Consider a relatively simple C++ class
class X {
static const int i = 5;
};
int main() {
int array[X::i];
}
How does this get replicated in WideC?
In fact, specifically, consider my previous application of a memory allocator. The relative complexity of specifying it was just wrong- because it had to exist in *two* times at once. This means that there's only one real solution- namespaces and types are the same thing. Types represent data that *will* exist. Namespaces represent data that *does* exist. However, conceptually, the two are the same. I already had the beginnings of this idea with accessibility in namespaces, and the follow-up with considering mutable namespaces. Now, I'm going to finalize that with a strict equality- the same idea as Standard.Functional.Function versus a FunctionReference. I also had to solve the infinitely recursive problem of the allocator depending on a hash map- which will depend on the allocator.
I'm thinking of using almost "instant-objects" for this job. That is, namespaces will be automatically default constructed - and they may have construction logic- and they may also have destruction logic. They'll be constructed once from source, and then can be mutated for the "next" phase, and can also be queried as to their contents.
That is, "meta-objects" like the allocator dealie that I posted previously would now be simpler to specify, and in addition, I could get rid of those annoying "compile-time" and "run-time" blocks and simply use deduction.
namespace Standard {
namespace Memory {
namespace Allocator {
// implicitly "private" and "compile-time"
HashMap(
key := int,
value := VariableReference
allocator := GCAllocator
) Pools;
VariableReference Default := HeapAllocator; // basically "new"
GetAllocator(Size)() {
if (Size > 48)
return Default;
if (Pools.Find(Size) == Pools.End())
Pools[Size] = Pool(Size);
return Pools[Size];
}
public {
Allocate(Size)() {
return GetAllocator(Size).Allocate();
}
Allocate(T)() {
return GetAllocator(T.Size()).Allocate(T);
}
Allocate()(Size) {
return Default.Allocate(Size);
}
}
}
}
}
On reflection, I'm not sure that this is actually *better*. Sure, it removes keywords and scoping from the language, but I'm not sure that it's actually better.
Perhaps the fundamental issue here at hand is the N-pass system to begin with. What you're really talking about is a three-pass deal- one to hold the type of the allocator's compile-time stuff, one to hold the type of the allocator's run-time stuff, and one for the run-time itself. Using the namespace might remove the problems of "How do I access the type's compile-time data and call it's compile-time functions through a TypeReference?". Which you can't.
Actually, that's not really true. The data doesn't actually exist at compile-time. It exists in some sort of mid-time. Code-generation time. The issue is that, well, partly, this stuff is bending my mind in ways it was never supposed to go and it's been much too long. And secondly, I never actually intended the language to be able to do that.
I might just opt for the namespace system for now. It's simpler.
No comments:
Post a Comment