<alexgordon>
whitequark: basically my plan is for each module, to generate little pieces of .hpp and .cpp for each symbol
<alexgordon>
then tsort, then paste them together to get a translation unit and a header
<alexgordon>
then pass that to the compiler
<alexgordon>
actually, probably don't need to generate full headers
<alexgordon>
can just pull in the relevant symbol .hpp pieces when generating a .cpp file
<alexgordon>
then the rest is easy
<alexgordon>
also using hashes to track changes
<alexgordon>
bit like git
<alexgordon>
but what'll make it work is precise tracking of just what depends on everything else, and what HAS to go in headers, vs what can go in .cpp files and be forward declared
<alexgordon>
hm
<alexgordon>
"ABI" vs API incompatibilities
<whitequark>
just use ocaml or something
<alexgordon>
whitequark: LOL that's quitter talk!
<purr>
LOL
<alexgordon>
ocaml is nice, but furrow is 10x betterer!
<whitequark>
no, for implementation
<whitequark>
ocaml is a dsl for writing compilers :)
<alexgordon>
right now I'm using python and C++
<whitequark>
yes, and both are horrible for that task
<alexgordon>
ha
<alexgordon>
python is great for argument parsing
<alexgordon>
import argparse
<whitequark>
is there anything else it is great for?
<alexgordon>
syscally stuff
<alexgordon>
working with the fs
<whitequark>
eating cpu
<alexgordon>
It Just Works™ with windows
<alexgordon>
I'm using it for the entire frontend
<whitequark>
ugh
<alexgordon>
then it goes and calls the real C++ compiler
<alexgordon>
also it has great sqlite support for the build cache
<alexgordon>
when I say "frontend" I mean the user interface, not the front end of the compiler
<whitequark>
ah
<whitequark>
that's somewhat more sane
<alexgordon>
my aim is to build a package manager in there too
<alexgordon>
so it'll be a bit like npm, but written in python and for furrow :P
<purr>
<elliottcable> white goo dreeping down my strema
<purr>
whitequark: ‘edible glitter in poop’ → “If you’re looking to add a little bling to your bowel movements, save up $425 of your hard-earned money and buy a gold pill. It’s a capsule coated in 24k gold and filled with tiny flecks of actual gold, which your body can’t digest.”
<alexgordon>
whitequark: :D
<whitequark>
what the fuck
<whitequark>
all of that
<alexgordon>
my
<alexgordon>
brain
<alexgordon>
my poor, poor brain
<alexgordon>
this is too much
<alexgordon>
the circular dependencies make hashing really difficult as a way of tracking changes
<alexgordon>
I know this problem IS solvable, because humans manage to do it
<alexgordon>
but I can't for the life of me work out how to teach the computer how it do it
<whitequark>
um, track whether an object was already hashed or not?
<alexgordon>
the problem is that functions have implementation (function body) and interface (type signature) dependencies
<whitequark>
like, convert your graph into a DAG
<alexgordon>
but it's not acyclic
<whitequark>
well, what you need is a deterministic iteration order over a graph
<alexgordon>
since functions can be mutually recursive
<whitequark>
in order to hash it
<alexgordon>
and two data structures can mention each other
<alexgordon>
so you can't just do hash(name || signature || body || dependencies)
<whitequark>
ah, I think I understand
<whitequark>
you need to compute a hash for every single entity with regards to all of its dependencies
<whitequark>
as opposed to a global hash
<alexgordon>
yeah, to avoid recompiling everything that uses a module if one function changes
<whitequark>
the simple solution is to do that DAG thing I suggest
<whitequark>
but interpret every single entity as a root, iteratively
<whitequark>
oh, no, that won't work.
<whitequark>
hmmmmm
<alexgordon>
ha ha haaaaa
<alexgordon>
yeah it's hard
<whitequark>
I think what you need is to separate your graph into strongly connected components
<whitequark>
if you do that and then contract every component into a vertex, it becomes a DAG
<whitequark>
and you can actually do sensible separate recompilation if you have a DAG
<whitequark>
you need to recompile each strongly connected component as a whole
<alexgordon>
I'm not sure how that gets you change tracking though
<whitequark>
well, you don't need to compute hashes for cyclic structures anymore
<whitequark>
since the "big picture" is a DAG
<alexgordon>
but the hashes is how I'm identifying the functions
<alexgordon>
for the purposes of determining whether they were modified
<whitequark>
and in order to compute a hash for a strongly connected component, you may select any deterministic order
<whitequark>
well
<whitequark>
use names of dependencies while hashing
<alexgordon>
what I *want* to be able to do is to say "foo was at 6f5902ac237024bdd0c176cb93063dc4 but now it's at f54a1fca2d39a6861ed89c203cbabe53, therefore I need to recompile everything that depends on foo"
<whitequark>
there is simply no sensible way to hash a cyclic structure.
<whitequark>
would, roughly speaking, hashing the AST of a function suffice for *detecting modifications to functions*?
<alexgordon>
or maybe there is
<whitequark>
not their dependencies
<whitequark>
you're trying to solve two distinct problems at once, detecting modifications to functions and detecting modifications to their dependencies
<alexgordon>
maybe it's simpler than I'm making it
<alexgordon>
no wait that doesn't work
<alexgordon>
dammit! haha
<alexgordon>
whitequark: the latter is easy enough, since I know what depends on them
<alexgordon>
the former is harder, if you consider it to be detecting modifications to functions *or to their dependencies*
<whitequark>
well, DON'T
<whitequark>
the problem you're trying to solve is internally contradictory
<whitequark>
that's why you can't do it
<alexgordon>
but that's my favourite type of problem!
<whitequark>
oh well, you can proceed alone then
<alexgordon>
hahaha
<alexgordon>
lemme prove to myself that this is in fact impossible
* alexgordon
goes to find paper
<whitequark>
consider a single function f() { f() }
<whitequark>
when is it modified?
<alexgordon>
it's modified if it's modified!
<alexgordon>
if you change it to f() { f() + 1 }
<whitequark>
exactly
<whitequark>
ocaml's solution to hashing cyclic structures is to stop hashing after a certain number of steps
<whitequark>
but that obviously won't work for you
<alexgordon>
but for that case
<alexgordon>
you CAN hash it so that the hash changes if it or any of its dependencies change
<alexgordon>
the hash would just be hash("f() { f() + 1 }")
<whitequark>
so it's hashing the AST, as I've said
<alexgordon>
well
<alexgordon>
no
<whitequark>
yes
<whitequark>
it's equivalent
<alexgordon>
that bit haven't figured out yet
<alexgordon>
it depends whether you need interface or implementation
<whitequark>
wat
<alexgordon>
for example, it might be sufficient just to hash the type signature
<alexgordon>
since you don't need to recompile if a dependency changes internally, only if its external interface changes
<alexgordon>
I'm thinking I might have two hashes for each: an implementation hash (that changes if the internals change) and an interface hash (that only changes if the name or type signature change)
<whitequark>
depends on whether you have monomorphization
<whitequark>
"C++ templates"
<alexgordon>
yah
<alexgordon>
well, I do
<whitequark>
then signature is not enough
<alexgordon>
but not always
<alexgordon>
a function with type :: Int -> Int obviously has no templates
<alexgordon>
so it can happily live in its own module object file
<alexgordon>
a function like :: (A -> B) -> [A] -> [B] needs to be in each translation unit, and so yes the interface is not enough
<whitequark>
also does http://imgur.com/PNMhVPJ make me the only person in here with a working language impl? :D