Deca - a systems language based on modern PL principles
code.google.com
code.google.com
* ATS http://www.ats-lang.org/#what_is_ats_good_for
* Clay http://claylabs.com/clay/
A lot of work there has been done in completely replacing the entire current software development stack with something more reasonable (in terms of size/bloat and design). They aim for a full system (frontend user apps to the metal) in under 20,000 lines of code. Check it out. Quite the alternative to C, and everything.
Rust certently has a runtime, cant argue with that.
I thought Rust allows a pretty tight control over allocation with the pointer hierarchy feature. The GC is designed not to be global and should be pretty easy ignore. They even have diffrent kinds lambdas to allow the programmer if the should be allocated on the heap or the stack.
I have not done alot of low level programmig but I want to learn more about writting Jits and the pretty much need to be rather low level atm there is not really an alternative then writting them in C (witch sucks).
But when i was making the list I was thinking about if the language could possibly be used in an embed context. C is still king there. Rust I believe, is partially garbage collected in a way that is not practically avoidable. Any use of boxed types or abstract datatypes will incur this penalty. So with that criterion rust is not an option, in an embed system continuous execution is most vital. The languages I listed are either not garbage collected or with an ability to turn it off or use an alternative to abstract datatypes and have basically no overhead. The last time I saw Rust mentioned on HN a team member validly stated that such concerns are not the priority at the moment.
One example is one of the french radar system for missile defense, Normandie.
The choice of LLVM for C interface and performance is also really sensible.
I was surprised to find the language implemented in Scala and Java though. Perhaps there will be some kind of bootstrap, or maybe the ability to access the java libraries is intentional.
Without proper documentation it is a bit hard to evaluate this more fully at this stage. I looked but didn't find many docs yet. Certainly a language to watch.
Sorry about the lack of docs. I've been slowly dumping my undergraduate thesis on this into the wiki, but the language has been evolving and I've been starting a career. Oy ;-).
A compiler transforms a program from one format into another. decac does not execute programs, so it's not an interpreter.
"The fundamental problems of a systems-programming task or environment are hard limits on computational resources and a lack of safety protections. Systems programs have to deal with hardware-imposed limitations on their CPU time, registers, memory space, storage space on I/O devices, and I/O bandwidth. They also often have to deal with a lack of the safety features normally given to most programming environments: garbage-collection of memory, validation of memory accesses, synchronization primitives, abstracted access to I/O devices, and transparent multitasking. In fact, the point of systems programming is usually to create such abstractions and program such protections."
Let's take Go, as an example. (Or D). Per above definition, neither is a "systems programming" language. I know for a fact [2] that Go team would disagree.
So what is the accepted definition of a "modern" systems programming language?
[1]: http://code.google.com/p/decac/downloads/detail?name=Deca%20...
[2]: http://golang.org/doc/go_faq.html#What_is_the_purpose_of_the...
Ideally these would be disjoint sets (in my opinion) but consider this: ASM -> C -> C++ -> Java -> ... looks like a continuum if you're writing any kind of Java code, but there's a sharp discontinuity in there if you're writing (say) a boot loader.
I do agree with that. (Perhaps it would be helpful to apply the high/low qualifier to systems languages?)
> Ideally these would be disjoint sets (in my opinion) but consider this: ASM -> C -> C++ -> Java -> ... looks like a continuum if you're writing any kind of Java code, but there's a sharp discontinuity in there if you're writing (say) a boot loader.
Food for thought. I am not arguing for needless complexity (in a language) as far as the boot up phase is concerned. As far as I understand it, the loader has its critical, but short lived, life-cycle role to play and then it is out of the way. Arguably, it is distinct from the OS. Can we not continue to write them in ASM/C and load operating systems that are written in a more "modern" language?
I still don't imagine an OS being written in a non-systems application language, since you've got drivers and performance critical subsystems to write and things like GC to worry about from the apps-only languages.
Before C existed, there were already operating systems written in PL/I and ALGOL, which provide better type safety and memory management as C or C++.
Unix and C success has regressed what meant to be a proper systems programming language.
There is even a paper from Adele Goldberg about this phenomena, unfortunately I cannot recall the title now.
I tend to think of Go as an attempt to redefine what a systems programming language is (hence the "modern").
I don't think that there can be an established definition of what a modern systems language is, otherwise it would no longer be termed modern. Almost by definition theorists will differ on what the essential characteristics must be.
Right. And (imho) malloc is quite possibly an "old fashioned" way of looking at things:
function malloc(num_bytes: nat): @byte
A reference to a byte block obtained from specifying the number of bytes! I would like to see the modern memory manger be type aware, have a very rich memory model, and allow for the propagation of application level semantics to OS (so they can cooperate in dealing with the current issue: memory access latencies and concurrency).> I don't think that there can be an established definition of [a] modern systems language
Key word is "modern" so here is an attempt to box that a bit: There are 2 possible dimensions to the notion of modern:
1 - it addresses new hardware realities
2 - it enables "progress" in dealing with matter rendered difficult by existing paradigms of system programming.
The realities of a modern system surely include: multi-core SMP; strong likelihood to be employed as distributed nodes; virtualization. So "modern" platforms and deployment patterns are not addressed.
Second, Deca, I gather, would delegate dealing with all this to some higher level (user level) framework built on top of the language. I don't see any progress in that critical front, either.
Because these are system languages, that would happen when hardware is type aware.
Once the "newsig" branch (it's a rewrite from scratch after the original code had troubles with multi-module compilation) with the new signature system (region, effect, type, mutability) can compile some example code again, I'm merging it back into the main branch.
One possible feature that stands out would be macros local to a scope. I actually did this, defined a macro right in the middle of a function to automate some error-handling junk. It felt nasty, but not quite as nasty as copy-pasting or retyping the code, as long as I don't try to re-use the name. It would be nice if my language handled stuff like this.
This is obviously not a huge issue. The language looks awesome.
Check out http://code.google.com/p/decac/source/browse/examples/list.d...
I'd love to see some discussions on possible/practical shortcomings.
(void -> int) incrementer(int initial_value) {
int count = initial_value;
return lambda() { return count++; }
}
might be rewritten as: struct hidden_environment_type {
int count;
}
int incrementer_lambda(hidden_environment_type *env) {
return env->count++;
}
void incrementer(hidden_environment_type *hidden_arg, int initial_value) {
hidden_arg->count = initial_value;
}
Now the caller will allocate a variable of type hidden_environment_type, and pass its address as the first (artificial) argument.Note that lambda functions require a different calling convention to C function pointers, since they need to be passed a pointer to their environment in addition to their regular arguments. Introducing lambdas either requires some resolution of this complication, such as specialisation machinery (ie in C++11, templates provide the necessary specialisation). Another option is to use the environment-passing convention for every indirect call, possibly giving a minor performance hit for calling raw function pointers.
Another issue is that the size of an environment type depends on the code of a function involving it, so lambdas don't have uniform size unless some additional indirection is introduced, probably to heap storage (Apple's blocks extension to C takes this approach). This makes it either impossible or slightly more expensive to store lambda functions in data structures, depending on which implementation you choose.
After all this, your ownership/lifetime question boils down to "who is holding onto the instance of hidden_environment_type?", which is a pretty simple question to answer in C-like languages.
In short, closures now remember what pointers they capture, and you won't be allowed to return a closure over a pointer further up the stack than safe. Other than that, closures capture by value, copying the captured variable into an environment structure.