It was created in 2009 for an EPFL school project, and is now self-hosting, currently in v0.9.4. It produces clean, portable C code, its SDK works on Windows, OSX, Linux, Haiku, FreeBSD, and probably more. Has been used to create games, power live streaming backend architecture (in production), write compilers, IRC servers, IRC bots, torrent clients, implement Lisp, JIT assemblers, package managers, and more. https://github.com/languages/ooc
logger := Logger new(stdout) logger log("Started at " + Time currentTimeMillis()) work() time := Time currentTimeMillis() logger log("Finished at %d" format(time)) }
programming. While this doesn’t prevent the creation of generic containers, type safety is not guaranteed. C++ meta-programming is done via templates: compile-time instanciation, compile-time type safety, significant cost in compilation time and binary size. RTTI available via typeid. JVM-based languages (Java, Scala, Groovy, etc.) have generic classes, with type erasure because of backwards-compatibility. Limited compile-time type-safety (can be overriden) and no introspection possible at runtime.
interface. e.g. String, Logger, etc. A primitive type: cover, cover from. e.g. Int, Boolean Java has a similar distinction (int vs Integer). In ooc, instead of boxing and unboxing, primitive types are allowed as generic type parameters.
func (=value) get: func -> T { value } } Number of generic parameters is not limited: Map: abstract class <K, V> { put: abstract func (key: K, value: V) get: abstract func (key: K) -> V }
types add to the semantics of the language and have no natural C translation. /* what is the generic version of this? */ int identity(int value) { return value; } Generic type sizes can vary: operations on generic values must work whatever their actual size is at runtime. So must operations on arrays of generic values.
returned by the TypeName class() function. This structure contains the width of the type. typedef uint8_t *Any; void identity(Class *T, Any value, Any ret) { if (ret) { memcpy(ret, value, T->size) } }
concrete type, the generic value is unboxed by dereferencing its address. void somefunc(Any value) { int i = *((int*) value); // do something with i } For arrays of generic types, the position of an element is computed at runtime using its index and the size of an element.
of their value directly is an extra indirection (dereference), which incurs a speed penalty. Calling memcpy is much more expensive than the = operator in C. No C compiler is smart enough to optimize memcpy to something else. gc malloc calls are more expensive than stack allocations (for local generic variables). These explanations were based on intuition, the subject of this work was to implement generic specialization to assess the performance problem and solve it.
the inline keyword (pre-existing, unused). It also adds a compiler instruction named #specialize. It is used to manually mark a type parameter combination for specialization: For example, #specialize ArrayList<Int> would make all lists of integers faster, and all other combinations would work as usual.
no-compromise C++ and JVM models. It allows partial specialization of generic types. Unspecialized code remains as fast as generic collections in C (cf. qsort), and specialized code performance is comparable to C++ template code. Further work is needed for legacy code to take advantage of the optimizations implemented here, because of abstraction leaks.