Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Unison developer here! Let's say you have some term:

B = "Hello "

and it hashes to #a3yx. Lets say you also have funcion:

A = B ++ "world" which hashes to #c7c1

when we store the A function, we actually store it as:

#c6c7 = #a3yx ++ "world"

Then later if you update the definition of B:

B = "Hello, "

and that function hashes to, #5e2b, when you tell unison to update B from #a3yx => #5e2b, it will look for all of the places that used to reference #a3yx, like your A function, and will see if those functions still typecheck with the replacement. If so, they are automatically updated. If not, we pretty print the definitions that didn't to a file for you to manually fix.



This is a really interesting system, and I'm excited to give this a try!

Without knowing whether the following cases would actually be useful/relevant, I'm curious if these things apply to Unison:

- Is there a way to "pin" a symbol to a specific hash/version so it won't automatically update when the referred function gets a change? I.e. I could write: A = B@ ++ "world" and when I store and retrieve it, it becomes (example syntax): A = B@a3yx ++ "world"

- Is there a way to refer to a function/symbol by name rather than by hash? I.e. a call site which uses B by looking up which hash is currently associated with the name "B", such that if I do two simultaneous renames, B->D and C->B, the code would now refer to the function previously known as C?

- Are there ways in which the way function updates "bubble up" through the codebase (I assume updating a function means updating every function that calls it, recursively) could become a problem? It would seem that changing one little function could have a knock-on effect that requires re-hashing most of the codebase.


What happens if you have two terms that are incidentally equivalent:

  A = "Hello "
  B = "Hello "
  C = A ++ "world"
  D = B ++ "world"
and then you update the definition of A but not B?


At the point when you've written a term which is incidentally equivalent to another, the Unison codebase manager tool tells you that you're adding a term that is identical and lists its name. You can still technically perform the addition if you really want at that point, but most folks don't want two aliases for the same function floating around. If you do end up adding it, updating A would also update B. Think of the function name as metadata and the actual implementation as the identity of the function.


Is the term merely the hash of its contents, or does it also include the module space? If it's just the hash of its contents, how do you deal with functions which have the same implementation now but shouldn't always - e. g.:

    serviceA.requiredHeaders key = Dictionary.of "X-API-KEY" key

    serviceB.apiKeyHeader apiKey = Dictionary.of "X-API-KEY" apiKey

If they hash to the same thing and I update `serviceA.requiredHeaders` (because the vendor changed from `X-API-KEY` to `X-VENDOR-API-KEY`) do I have to know that these are two different services in order to review the change and untangle these two methods or is there a way to mark these as "structurally equivalent but semantically distinct"?


Yes this is unfortunately a problem that comes up with our current system. We had to solve this early on by distinguishing "unique" types form "structural" types. For types it is obvious that you want to make sure that these types generate a unique hash, even if they are the same structure:

type UserName = UserName Text type Password = Password Text

since the entire point in introducing types here is to actually declare them as different from one another.

But for other it might actually be beneficial to recognize that they are the same type, for example:

type Optional a = None | Some a type Maybe a = Nothing | Just a

To allow for both, you can prefix type with either "structural" or "unique" depending on what behavior you want (unique is the default). We have tossed around the idea of also introducing unique terms which would let you terms like yours as unique terms that should be salted, and let the current behavior of "structural"? terms be the default. The reality is that this hasn't been such a big problem that it has made it to the top of our list yet ;)


(Sorry for replying late to this but) that seems kind of inconvenient! And what if I'm using two libraries which happen to export functions with identical ASTs, and one updates? I guess usually meaningful nominal types will ensure that that doesn't happen but it seems like a nightmare to deal with in the event that it does.


for us, A and B are the same Term since they have the same hash, they are just two different alias for that hash, so if you update either, you are effectively updating both.

In fact if you had the function:

double x = x + x

and you were to rewrite it to be:

double addend = addend + addend

Unison would say "this is the same function, no update needed" as it produces the same AST




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: