Live data from Hacker News

Why Specifications Don't Compose

hillelwayne.com

61–65 of 65 posts

Re: Why Specifications Don't Compose

#61

Earlier quoted context omitted.

I don’t understand this at all. Either you have a totally different definition of namespacing to me (For me, this is basically getting to write x in most places and Foo::x and Bar::x in some places instead of foo_x and bar_x everywhere), or you’re just not addressing any of the issues discussed in the article (fairness, liveness, framing, etc).

Look at the 2nd paragraph of the motivating conversation: ``` Lars, 7:53: In software engineering, we have largely figured out modularization. All modern programming languages have some form of module system. You can pull in a module and import its functions anywhere. ``` ... and then they write a blog about how this is impossible. namespace is one trivial part of modularization (avoiding naming clashes). All impleme…

I think the point of the article isn’t that you don’t have namespaces (which are basically trivial) but that, given two names, you can’t often combine them into something that gives you what you want. Instead you need to tease apart their definitions and combine them in a more complicated way. And it is this problem that the article is about

Re: Why Specifications Don't Compose

#62

Earlier quoted context omitted.

Though in that case requiring that Next blinks both 'x' and 'y' should obviously mean they are required to blink synchronously. Depending on how you model World you can either compose the two Next functions that blink x and y or you can multiply their respective worlds and use the product map. None of these feel unnatural.

Sure, that's a natural way of reading this requirement, but is it the right way? How would you specify the system such that it can produce: [(x, y), (!x, y), (!x, !y), (x, !y), (!x, y), ...] (that is, any interleaving of the two blinks that preserves the constraint that there is at least one blink in each "step")

If you ask me requiring at least one blink in each step is a bit awkward as it is a global requirement as opposed to a local one.

But you can add the requirement Next(World) World if you really want to. Then you just get two sets:

- Next(World) World

- Next(World).x in (World.x, !World.x)

and

- Next(World) World

- Next(World).y in (World.y, !World.y)

and if you combine them you get

- Next(World) World

- Next(World).x in (World.x, !World.x)

- Next(World).y in (World.y, !World.y)

which seems to do what you want.

Adding global constraints seems like an easy way to shoot yourself in the foot though.

Re: Why Specifications Don't Compose

#63
post #56

Earlier quoted context omitted.

No. I haven't left anything. I'm just saying that expecting that useful widespread formal specification language will be something as simple as LTT is wildly optimistic and you should expect that it will rather mirror and encompass the complexities and requirements of actual programming, like necessity of composability. And it will most likely be somewhere between practical but unsound specification languages and tho…

It must be sound or it's of no use. Reminds me of the Ultraviolet Catastrophe. They had a theory that gave them precise answers, they just happened to be blatantly wrong.

Unsound things can be useful. https://frenchy64.github.io/2018/04/09/unsoundness-reply.htm...

Re: Why Specifications Don't Compose

#64
post #40

If your programming language encourages you to structure your code in ways that don't compose when there are other perfectly good ways of structuring it that do compose then what you have on your hands is a bad programming language.

Hillel, you called me out on Twitter so I felt like it would be best if I elaborated for a few reasons. Firstly, hopefully it will be reassuring to know that although my comment seemed glib I was actually trying to engage with the substance of your work, secondly, it will help clarify my thoughts, and thirdly, someone else may be interested.

I don't have any experience with machine-verified specifications but I do have experience writing computer programs and (traditional, human-checked) mathematical proofs, so my comment comes from that perspective.

Regarding

> Me: 200 words on how we're talking about composing specifications, not code, because specifications aren't programming languages

> HN: [parent]

I'm sorry if the use of the terminology "programming language" was jarring. I tend to take the point of view that a huge range of human activity in what are traditionally called programming languages, probabilistic graphical models, languages for constraint solving and optimisation, a lot of mathematics (especially category-heavy mathematics) and even writing YAML for configuration is actually all just different aspects of the same thing. I chose the word "programming" in the parent which might betray some bias on my part but regardless of the word chosen the practice of combining smaller logical pieces into larger logical pieces is common to all. Your article is suggesting that there is something about the nature of specifications that makes this composition harder than it is for executable code.

The conclusion may be true (I have no idea) but I'm afraid that I just don't see how your article justifies it. In the first example I see a language LTL whose design encourages users to write small logical units that cannot be composed[1] easily with the && operation. A more awkward encoding does achieve compositionality (through stuttering-invariance). It looks like TLA+ provides notation to make it more natural to write the small logical units in ways that they can be composed easily with &&. That makes it sound to me like TLA+ is a better language than LTL (for this purpose)! Better languages make it easier and more natural to write smaller units in ways that can be composed. That's all my parent comment says!

In the second example it is composition with && itself that proves to be impossible. The composition rule is something more complicated:

    Next = (NextX(z) && Same(y)) || (NextY(z) && Same(x))
    Spec = InitX && InitY && □[Next]_xyz
Unless I'm missing something, there's nothing wrong or hard about that composition rule, it's just the tooling that doesn't make it easy to work with. In Haskell we compose monadic functions with >>=. That would make life really awkward unless we had do notation. The problem is not that monadic functions are hard to compose, it's that the language needs to support them ergonomically. I can't see anything in your post that suggests to me that specifications are by nature hard to compose. All I can see is unergonomic languages.

See also https://www.haskellforall.com/2016/04/worst-practices-should...

[1] composed in the sense which your article elaborates, that is, in a way which combines the properties of both in some desirable way

Re: Why Specifications Don't Compose

#65
post #64
post #40

If your programming language encourages you to structure your code in ways that don't compose when there are other perfectly good ways of structuring it that do compose then what you have on your hands is a bad programming language.

Hillel, you called me out on Twitter so I felt like it would be best if I elaborated for a few reasons. Firstly, hopefully it will be reassuring to know that although my comment seemed glib I was actually trying to engage with the substance of your work, secondly, it will help clarify my thoughts, and thirdly, someone else may be interested. I don't have any experience with machine-verified specifications but I do ha…

As also mentioned on Twitter, I think I'm taking the criticism of this article much harder than usual. I have a response to your comment, but it's a bit "sideways" from the actual discussion. Ping me on email/twitter DM?
Post reply on HN