
Loci: A C++-like systems programming language - rayiner
http://loci-lang.org
======
rayiner
Found this the other day, and wanted to share. Source is here:
[https://github.com/scross99/locic](https://github.com/scross99/locic).
Pleasantly readable and surprisingly compact given that it implements
polymorphism, templates, modules, etc, as well as code generation to LLVM.

What I think is particularly need is making lvalues and rvalues explicit
constructs in the language: [http://loci-
lang.org/LvaluesAndRvalues.html](http://loci-lang.org/LvaluesAndRvalues.html),
as well as being able to redefine the behavior of certain implicit operations
relating to copies and moves: [http://loci-
lang.org/ImplicitOperations.html](http://loci-
lang.org/ImplicitOperations.html).

~~~
millstone
That parser is something:
[https://github.com/scross99/locic/blob/master/lib/Parser/Par...](https://github.com/scross99/locic/blob/master/lib/Parser/Parser.y)

~~~
72deluxe
It really is! I wonder why they didn't specify the namespaces they were using
instead of littering it with namespace and scope operators?

~~~
scross
The intention is to avoid any kind of name clashes; I don't think this really
inhibits readability.

------
panic
I like this language because it doesn't try to do anything too fancy. It's
"just" a streamlined C++.

I do wonder how they're planning on avoiding overhead with the garbage
collector, though. Once you have a single garbage collected object on your
heap, it seems like you'd have to start scanning the whole thing to make sure
the garbage collected object is still alive.

~~~
rayiner
The overhead of GC is independent of heap size. Take the following variables:

    
    
        L = total size of live objects in heap
        H = maximum size of heap
        P = time between collections
        R_a = rate of allocation
        R_s = rate of heap scanning
    

It's easy to define P and R_s (assume a mark-sweep collector so we can ignore
copy reserve):

    
    
        P = (H - L) / R_a
        R_s = L / P
    

Substitute and simplify:

    
    
        R_s = L / ((H - L) / R_a)
        R_s = L / (H - L) * R_a
    

In other words, _it doesn 't matter how big your heap is._ If you make your
heap twice the live size, the amount of heap scanning you do will always be
equal to your allocation rate times some constant. If H = 2L, that constant is
1.

So the way to improve performance is to cut down on that allocation rate. If
you use RAII for most objects, and GC only occasionally, your allocation rate,
net of non-GC allocations, will be very low, which means your scanning rate
will be very low. You'll have to traverse all live objects every GC cycle, but
you'll rarely have to do a GC cycle.

~~~
tomp
Are you sure about this? The main overhead of a mark-and-sweep GC isn't the
marking phase, it's the sweeping phase - you need to find and free all dead
objects (to mark them as free/add them to the free list), and since you don't
know where they are (by definition, since they are dead, they have no
references pointing at them) you have to scan the whole heap (or at least all
the pages that were objects were allocated/live on since the last GC cycle).

~~~
rayiner
R_s for a naive mark-sweep looks like this:

    
    
        R_s = (L + H) / (H - L) * R_a
    

For a copying collector:

    
    
        R_s = L / (H - 2L) * R_a
    

If H is a constant multiple of L, then your scan rate will be a constant
multiple of your allocation rate, independent of heap size.

In practice, you won't sweep the whole heap after each GC cycle, but will do
it lazily:
[http://www.hboehm.info/gc/complexity.html](http://www.hboehm.info/gc/complexity.html).
The point in that article about marking time dominating allocation/sweep is
even more true today. Allocation and sweep access memory linearly and are
easily parallelized. Meanwhile, marking accesses memory randomly, and the
maximum concurrency is dependent on the shape of the live object graph.

------
keypusher
This looks very promising. As a Python developer who primarily does systems
programming, I sometimes have to jump into C for system calls and
optimization, or to Java for stronger type safety and real interfaces, neither
of which I particularly enjoy. I could definitely see doing new projects in a
language like this.

~~~
kxo
Have you seen Nim? ([http://nim-lang.org](http://nim-lang.org))

~~~
possibilistic
Nim should look very attractive to Python developers. It's a good looking
language that has positioned itself in a good market: static typing, looks and
feels like scripting (not verbose), and almost systems level (has GC).

I haven't got any experience with Go development, but from those I know that
use it, I hear nothing but promising things about Nim. "Modern" is a word that
gets used.

Between Rust and Nim, we're starting to see some really clever new languages
that fix common pain points. Both of these are so neat it makes me feel as
though we're in a programming language boom right now.

~~~
dmacvicar
While it is not the case of nim, I tend to think LLVM enabled a lot of this
"boom".

It gives you a high quality set of components that cover a big bunch of the
things you need when implementing a compiler. Energy can be spent in the
language itself.

------
tomp
I don't understand why vtables are implemented as hash tables.

The docs [1] describe that objects (of class type) only contain data (i.e.
object fields), and no vtable pointers. Only when an object is cast to an
interface type is a vtable generated and passed along with the object pointer
in a _fat pointer_.

However, instead of just structuring the vtable as an array of pointers to
methods (ordered e.g. by name), Loci instead generates a hashtable with method
resolution stubs in case of conflicts. I don't understand why - since the
target interface's type (and methods) are known at compile-time, it would be
just as easy to fix the ordering of the methods and use the array approach
(like in C++), instead of using a hashtable.

[1] [http://loci-lang.org/DynamicDispatch.html](http://loci-
lang.org/DynamicDispatch.html)

~~~
wvenable
This is the reason:

"This design also differs from C++ in that vtable pointers are not stored in
objects, but are part of an interface type reference. _This decision is
particularly appropriate to the language, since Loci doesn’t require classes
to explicitly implement interfaces_ "

~~~
tomp
This is irrelevant. Every time an object is cast to an interface, the compiler
needs to know the definition of that interface. Therefore, it's just as easy
to generate a hashtable or an array.

------
dasmithii
After a quick read, I'm impressed. Looks like general improvement over c++.

------
mastodont
But why? If it is already like C++ why build a new language?

~~~
scross
I think this page answers your question: [http://loci-
lang.org/LanguageGoals.html](http://loci-lang.org/LanguageGoals.html)

Basically I've had a lot of experience working with C++ on various projects
and while I like it very much I've also observed its weaknesses (right now I'm
struggling against slow build times); after a while it seemed logical to build
a language that would solve a lot of these problems so that I wouldn't have to
face them over and over again for each project.

------
iamed2
I think this may fill a void in the "teaching language" space. It doesn't
require lots of boilerplate but retains some key teachable moments (type
system, pointers, stack vs heap, interfaces, etc.). I think a language with
this sort of brevity and breadth of features would do well as a replacement
for the Java/Python/C/C++ hodgepodge that currently exists at many
universities.

------
yellowapple
So the kicker: is it ABI-compatible with C++? I've come to like the C
compatibility in Julia and Rust (and I'm sure I'll come to like the C
compatiblity in Loci, too), but the relative lack of C++ interface support
(something that I know Julia's been working on, at least based on what I've
seen on the mailing lists) has been a bit of a sore point for integrating with
C++ projects.

~~~
lucozade
A quick look at the docs make this a definite no.

The name mangling scheme is similar to (one of) C++'s so that could probably
be made more compatible. However the vtable mechanism is completely
incompatible and given the reasoning in the docs (to support structural
typing), I don't think it's a big stretch to say that it's a fundamental
incompatibility.

TBH I'd be quite surprised if many (any?) languages will aim for C++ ABI
compatibility that's much beyond simple extensions to the C ABI. Even ignoring
the lack of a standard C++ ABI, once you start getting into virtual functions,
exception handling and, especially, templates, you end up constraining your
language to a point where you're probably better off just using C++.

I may well be wrong on this, LLVM helps a lot with the grunt work of name
mangling, exceptions, trampolines etc. so it may be possible to get to a sweet
spot that supports a significant number of important libraries without
hamstringing the language too much. Not going to hold my breath though...

------
Daemon404
I can't find any mention of if they provide a C-compatible ABI. Kinda useless
as a systems language if they don't - you can't call it from anything else.

~~~
ori_b
[http://loci-lang.org/CompatibilityWithC.html](http://loci-
lang.org/CompatibilityWithC.html)

~~~
Daemon404
Perhaps I scanned too quickly. I probably missed since there is no actual
mention of ABI (or e.g. _which_ calling conventions it supports on what
platforms). The page is confusing - it seems to discuss ABI and syntax and
stuff, which isn't exactly related to "compatability" afaict.

I digress... just the usual problems with wiki-type sites.

~~~
wvenable
It compiles to LLVM and LLVM abstracts the calling convention. So it might be
safe to assume it supports all the calling conventions that LLVM supports.

~~~
Daemon404
Sure, but that requires knowledge of how LLVM works. Some dude checking out
the language probably doesn't.

------
okamiueru
> the language aims to have no performance overhead versus C and C++.

Could someone expand on this for me? What is the performance overhead
typically associated with C/C++?

~~~
cgh
It means Loci will perform similarly to C and C++, not that C and C++ have
some particular overhead that Loci doesn't.

------
shmerl
Who runs the project? Who created it?

~~~
trevex
Seems it was created by one developer called Stephen Cross (scross.co.uk). I
am quite impressed by his accomplishment. The only thing I miss are custom
allocators.

~~~
wbhart
He's 2.5 years out of his undergraduate degree. This is incredibly
sophisticated code and documentation for such a person. Quite aside from the
language, the person himself is worthy of note!

~~~
perdunov
The guy seems to be one of those super-productive programmers.

~~~
72deluxe
We should ask him how he manages it - is it lack of sleep, loads of coffee and
no social life?

I found that the best thing when I needed to be "productive".

------
jokoon
Languages are tools you use for their syntax, not for the work they do for you
or the abstract paradigms they encourage.

~~~
pjc50
Eh? Languages are tools you use for their ecosystem, and especially for what
work you can have done for you and what kinds of correctness the language
encourages. Syntax is something you have to put up with as part of
constructing a program.

~~~
jokoon
languages can be cross platform. you can talk to 2 different person and they
will understand you.

syntax is a huge help, it's a shortcut to being able to understand what the
program does. syntax is good.

------
oxryly1
It bothers me that this is offered anonymously. I can't invest any time into
checking it out without any concept of who produced it.

~~~
adnzzzzZ
If that's seriously a problem then just don't check it out. I personally find
it ridiculous that it's a requirement for someone's identity to be attached to
a project in order for someone to even consider seeing what it's about.

