-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce runs #348
Introduce runs #348
Conversation
Rules for thee, but not for me? |
Also, the diff is 2.5 kLOC, can you please make a note as to which files are autogen/trivially changed so I can ignore them? |
Feel free to ignore everything in |
|
||
The following operator is similar to `[A]_x` of TLA+: | ||
|
||
```scala | ||
stutter(A, x) | ||
A.stutter(x) | ||
orKeep(A, x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a scenario where someone wants to stutter over variables that are different from the set of variables being updated by the action A
? I can't event understand what that would mean.
If x
is always the set of variables being updated by A
, WDYT about getting rid of the argument? Then we can call the operators something like optionally(A)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. TLA+ has variables in [A]_vars
, since there are no explicit assignments there. Factored it out in a separate issue, since the stuttering operators were already in the manual before: #354
|
||
The following operator is similar to `<A>_x` of TLA+: | ||
|
||
```scala | ||
nostutter(A, x) | ||
A.nostutter(x) | ||
mustChange(A, x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an expectation (like in a testing framework). WDYT of A.changing(x)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we remove variables in the stuttering operator, we should also remove them in this one, as this one is the negation of stuttering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not exactly a negation. [A]_x
is defined as A \/ x' = x
and <A>_x
is defined as A /\ x' # x
. This second one I can see being used with a set of vars different then the set of vars being defined by A, as it can constrain A even further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. I am just saying that <A>_x
was introduced as a dual of [A]_x
. You are probably right that it does not make a lot of sense in the presence of effects and the requirement that all variables should be touched.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sutter
/nostutter
have the benefit of being clearly dual. OrKeep
and MustChange
have no such obvious relation in their names, IMO.
I don't know what motivates the change in names here, but I think we should at least keep the names related. So maybe something like
noChanges
/changes
orKeep
/noKeep
(I don't like these)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's postpone this for #354
These operators are not used in specs yet, so there is no rush to pick a perfect name in this PR.
// execute Init and then Next ten times, while asserting n < 5 | ||
run run4 = { | ||
Init.then(10.times(all { | ||
assert(n < 5), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the motivation for adding assert
? It seems like a way of reporting counterexamples, but I don't think this should be done at the language level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it looks like the only convenient way of specifying a failing test as a run. The expectation is basically that the run should go through, unless the assertion fails somewhere. I don't like asserts in TLC. We probably can live with asserts in the runs. But it would be great to have something better than asserts.
{ name: 'then', effect: '(Read[r1] & Update[u1], Read[r2] & Update[u2]) => Read[r1] & Update[r2]' }, | ||
{ name: 'times', effect: '(Read[], Read[r] & Update[u]) => Read[r] & Update[r]' }, | ||
{ name: 'assert', effect: '(Read[r]) => Read[r]' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to update those to produce a Run
effect, right? So we can't use those in other types of definitions that are not run
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly. I did not know how to do that :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end, we will have a model-checker written in TNT 😂
I've only read the language docs, I like the approach! Haven't reviewed the code.
non-negative). If you want to repeat `A` from `i` to `j` times, you can combine | ||
it with `orKeep` as follows: | ||
|
||
```scala | ||
i.times(A).then((j - i).times(A.orKeep(vars))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to promote this to a closure
operator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also thinking about doing that, but then what would be the difference between closure
and always
on finite prefixes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point :)
The operator `times` has the following syntax: | ||
|
||
```scala | ||
n.times(A) | ||
times(n, A) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this lead to confusion with the set product operator? Maybe repeat
is a better name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point. I copied this name from ruby
, which reads very nice, e.g., five times A.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will rename it to A.repeated(n)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you still planning to make this change? I agree that times
could be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is called repeated
now
Also, like Thomas, I've just read the language part. |
Co-authored-by: Kukovec <[email protected]> Co-authored-by: Thomas Pani <[email protected]>
Co-authored-by: Gabriela Moreira <[email protected]>
@shonfeder, for some reason I am getting this error on MacOS (zsh): npm run integration
...
TAP version 13
0..0
not ok 0 'exit': unknown command type
---
location: |
line 26
supported commands:
- program
- in
- out
- err
- check
---
# FAILED TO PARSE TESTS |
@konnov is your worktree clean? The mac tests are passing in CI. |
Actually, |
I think I have addressed the issues, except for stuttering, which is factored out into another issue. Anybody wants to review? |
Maybe these are more helpful debugging ideas:
Given the error message, I'm wondering if you'll find something like
|
It's all good. The older version of |
I see! Hopefully there is a way we can pin the version of our dev deps so we can automate away these kinds of issues in the future. |
This should help avoid friction due to incompatible versions in our toolchain in the future. See, e.g., #348 (comment)
Weird, I could swear that I had done this before (pinning the version in package.lock so we don't require a global installation). I was actually questioning why it wasn't working, but it seems like my change never made it through main or was reverted somehow. Thanks for fixing this, @shonfeder! |
Does anybody have cycles to get this merged? :) |
I'm reviewing now. Sorry for the delay. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like at least one left-over change you meant to make in response to previous reviews? I also have a few questions and suggestions.
The operator `times` has the following syntax: | ||
|
||
```scala | ||
n.times(A) | ||
times(n, A) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you still planning to make this change? I agree that times
could be confusing.
@@ -1646,33 +1770,33 @@ keeping this operator. | |||
to identify assignments in actions. We introduced `Unchanged` only in the | |||
Temporal mode, which is needed for refinements. | |||
|
|||
#### Stutter | |||
#### OrKeep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this being renamed? Seems likely to introduce more confusion imo. "Stutter" already has a lot of docs around it in TLA+, and is specific and unusual enough no one is likely to confuse its meaning for something they already know.
But OrKeep
could evoke other associations (related to disjunction, maybe intuitions about processing collections etc.) and users will lose the benefit of finding docs on TLA suttering when they search for it.
|
||
The following operator is similar to `<A>_x` of TLA+: | ||
|
||
```scala | ||
nostutter(A, x) | ||
A.nostutter(x) | ||
mustChange(A, x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sutter
/nostutter
have the benefit of being clearly dual. OrKeep
and MustChange
have no such obvious relation in their names, IMO.
I don't know what motivates the change in names here, but I think we should at least keep the names related. So maybe something like
noChanges
/changes
orKeep
/noKeep
(I don't like these)
?
run run1 = { | ||
(n <- 1) | ||
.then(n <- 2) | ||
.then(n <- 3) | ||
.then(n <- 6) | ||
.then(n <- 3) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite cool.
How soon before users will want to be able to do:
run run1 = {
n <- 1;
n <- 2;
n <- 6;
n <- 3;
}
:D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's why we have then
:)
Co-authored-by: Shon Feder <[email protected]>
Co-authored-by: Shon Feder <[email protected]>
I think I have implemented all the required changes and introduced a follow-up issue on stuttering operators. |
Awesome! I can’t wait to play with this feature :) |
Closes #344. This PR introduces the concept of a run, which is not explicitly present in TLA+. I kind of skipped the discussions and ADR phase here and went straight to extending the manual and implementing the new operators in the simulator. By doing so, I have iterated several times on the syntax. After all, we have:
run
, not supported by the effects checker yet.Run
, similar to the modesAction
andTemporal
.Run
operators:A.then(B)
is sequential composition ofA
and thenB
.i.times(A)
A.repeated(i)
is sequential composition ofA
exactlyi
times.assert(P)
testsP
and produces a runtime error, ifP
evaluates to false.