BruceIV
Joined 14 years ago
Joined 14 years ago
We intend to write a "proper compiler" at some point (probably either a Clang fork or a Cforall front-end on LLVM), but it hasn't been a priority for our limited engineering staff yet. I think we are getting a summer student to work on our debugging story (at least in GDB -- setting it up so it knows how to talk to our threading runtime and demangle our names), and improving our debugging capabilities has been a major focus of our pre-beta-release push.
Fun fact from when we switched our implementation to use VLAs: if you call alloca() for stack memory instead, it doesn't work properly inside a loop, because it never releases the memory until the stack frame is exited.
void* malloc_T(size_t sizeof_T, size_t alignof_T) {
return malloc(sizeof_T);
}
int* i = (int*)malloc_T(sizeof(int), alignof(int));
In this case, since the compiler verifies that int is actually a type with known size (fulfilling `sized(T)`), it can generate all the casts and size parameters above, knowing they're correct.[1] To anyone inclined to bash my definition of polymorphism, I'm mostly talking about parametric polymorphism here, though Cforall also supports ad-hoc polymorphism (name-overloading). The phrasing I used accounts for both, and I simplified it for pedagogical reasons.
More specifically, C++-style OO couples (1) in-memory layout of types, (2) behaviour of objects, (3) encapsulation boundaries, and (4) the hierarchical "is-a" relationship. In Cforall, (1) and (3) are handled by the usual C mechanisms of struct types and translation-unit boundaries [we go to great effort to maintain C-style separate compilation, though we will likely build a better namespace/module system at some point], (2) by traits, and (4) by a yet-to-be-implemented system of RTTI for specific "inherited" types [likely when the undergrad RA who started our exceptions implementation comes back as a Master's student this fall].
As you mention, many use-cases (including widgets in GUIs, but also abstract syntax trees in compilers) require some sort of heterogeneous collection type to work properly, and for this OO is the right model. We just don't want to force the entirety of that model on every use case, so we can just take traits when we want to write a polymorphic function over related types or an ADT like "Set" which requires its keys be sortable, or just take RTTI for exception handling, when the set of exception types we're handling is known statically, but we need to determine if the thrown exception inherits from one of the caught types.
[1] https://golang.org/doc/faq#Is_Go_an_object-oriented_language
forall(dtype T | sized(T))
T* malloc() { // in our stdlib
return (T*)malloc(sizeof(T)); // calls libc malloc
}
int* i = malloc(); // infers T from return typeThe exception implementation isn't done yet, but it's waiting on (limited) run-time type information, it already respects RAII.