Confused about the implication operator in assertions - alloy

Signature Test has two fields, a and b:
sig Test {
a: lone Value,
b: lone Value
}
sig Value {}
Note that a and b may or may not have a value.
A Test is valid only if it satisfies this codependency: If a has a value, then b must also have a value:
pred valid (t: Test) {
one t.a => one t.b
}
I want to create an assertion and I expect the Alloy Analyzer to find counterexamples. The assertion is this: If t: Test is valid, then t': Test is also valid, where t' is identical to t, except t' does not have a value for b:
assert Valid_After_Removing_b_Value {
all t, t': Test {
t'.a = t.a
no t'.b
valid[t] => valid[t']
}
}
I expect the Alloy Analyzer to generate counterexamples like this: t has a value for a and b. t' has a value for a but not for b. So, t is valid, but t' is not. But the Analyzer gives counterexamples like this: t has a value for a and b and t' has a value for a and b. I don't understand that. If t has a value for a and b, then t is valid. Likewise, if t' has a value for a and b, then t' is valid. How could that be a counterexample?
What is the right way to express the assertion? Again, my goal is to express this: I assert that if t is valid, then a slightly lesser version of t (e.g., b has no value) is also valid. That should generate counterexamples, due to the codependency.

I think your assertion should be:
assert Valid_After_Removing_b_Value {
all t, t': Test {
(t'.a = t.a &&
no t'.b &&
valid[t]) => valid[t']
}
}
In your original assertion, you assert three independent things. For example, every t' with a b would already be a counterexample.

Related

How does match compiles with `continue` in its arms?

I'm reading The Rust Programming Language book and I stumbled upon a simple expression:
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
How does match work with different kinds of expressions in its arms? E.g. the first arm would simply "return" num so that it's assigned to guess but in the second arm the expression is simply continue. How does match handle that and doesn't "assign" continue to guess but executes it? What happens with the whole assignment expression itself? Is it dropped from the call stack (if that's the correct term)?
continue has a special type: it returns the never type, denoted !.
This type means "the code after that is unreachable". Since continue jumps to the next cycle of the loop, it'll never actually return any value (the same is true for return and break, and it's also the return type of panic!(), including all macros that panic: unreachable!(), todo!(), etc.).
The never type is special because it coerces (converts automatically) to any type (because if something cannot happen, we have no problems thinking about it as u32 or String or whatever - it will just not happen). This means it also unify with any other type, meaning the intersection of any type and ! is the other type.
match requires the expressions' type to unify (as does if). So your code returns the unification of ! and u32 == u32.
You can see that if you'll denote the type (requires nightly, since using the ! type not at return type position is experimental):
let num = match num {
Ok(num) => {
let num: i32 = num;
num
}
Err(()) => {
let never: ! = continue;
never
}
};
Playground.

Why does the order of parameters matter when using the matches! macro?

I'm trying to compare a variable of enum type stored in a vector of structs, with a variable of the same type passed into my function as a parameter. So, both enums are stored in variables. However, I'm getting unexpected results. I'm using the matches!() macro for comparison. Can anyone explain this behaviour?
enum Foo {
A,
B,
}
fn main() {
let a = Foo::A;
if matches!(a, Foo::A) { println!("expected") }
if matches!(a, Foo::B) { println!("not expected 1") }
if matches!(Foo::B, a) { println!("not expected 2") }
let b = Foo::B;
if matches!(a, b) { println!("not expected 3") }
}
Output:
expected
not expected 2
not expected 3
The matches! macro is not symmetrical: the first operand is the expression to be tested and the second operand is a pattern to try matching the first operand against. If this order is not followed, the results will likely be unexpected.
While the first two matches! are well formed and do what you expect, the third and fourth one are most likely not what you want.
matches!(Foo::B, a) // test `Foo::B` against pattern `a`
matches!(a, b) // test `a` against pattern `b`
The expression to be tested is the literal value Foo::B, and the pattern is a new identifier, a in the third example and b in the fourth one. Since the pattern is only an identifier, it will match any expression. It does not relate at all to the variables a and b declared beforehand. The code below would still compile even when b did not exist.
let a = Foo::A;
matches!(a, b);
Note also that these if statements would print warnings, because a new variable was created from the pattern, but was not used.
warning: unused variable: `a`
--> src/main.rs:7:25
|
7 | if matches!(Foo::B, a) { println!("not expected 2") }
| ^ help: if this is intentional, prefix it with an underscore: `_a`
|
= note: `#[warn(unused_variables)]` on by default
See also:
Why does match not work while PartialEq/Eq works fine?
Why is this match pattern unreachable when using non-literal patterns?
Thank you to E_net4 the curator for the helpful answer. I can now get the behaviour I expect using the following:
#[derive(PartialEq)]
enum Foo {
A,
B,
}
fn main() {
let a = Foo::A;
let b = Foo::B;
let s = match a {
n if n == b => "a matches b",
n if n == a => "a matches a",
_ => "no match"
};
println!("{}", s);
}
With output:
a matches a

"Move" mutable reference into itself

I am trying to implement a "transform" function that takes a non-copy enum value and and modifies it based on a parameter, but some of the parameters do nothing. A simplified example is:
enum NonCopy {
A,
B,
C
}
fn transform(to_transfrom: &mut NonCopy, param: u32) -> () {
*to_transfrom = match param {
// transformations
1 => NonCopy::A,
2 => NonCopy::B,
// retains the value
_ => *to_transfrom
};
}
I know that since the NonCopy doesn't implement the Copy trait the value inside to_transform cannot be moved out, however if param is neither 1 or 2 the value of *to_transform is assigned to itself, so it stays the same and nothing should be moved, but the compiler doesn't recognize that.
How can I achieve such a pattern with an assignment to a match expression?
I know I could instead assign in the match expression, but the non-example version is bigger and I do not want to repeat so much code plus it is quite ugly.
A neat little trick in Rust is that when you break out of an expression (via return, break, etc.), you don't actually need to provide a value for that expression. In this case, you can return from the match arm without providing a value:
enum NonCopy {
A,
B,
C
}
fn transform(to_transfrom: &mut NonCopy, param: u32) -> () {
*to_transfrom = match param {
// transformations
1 => NonCopy::A,
2 => NonCopy::B,
// retains the value
_ => return,
};
}

Match shadowing example in the Patterns section of the Rust book is very perplexing

In learning Rust, I encountered the following in the official Rust book:
There’s one pitfall with patterns: like anything that introduces a new
binding, they introduce shadowing. For example:
let x = 'x';
let c = 'c';
match c {
x => println!("x: {} c: {}", x, c),
}
println!("x: {}", x)
This prints:
x: c c: c
x: x
In other words, x => matches the pattern and introduces a new binding
named x that’s in scope for the match arm. Because we already have a
binding named x, this new x shadows it.
I don't understand two things:
Why does the match succeed?
Shouldn't the differing value of c and x cause this to fail?
How does the match arm x binding get set to 'c'?
Is that somehow the return of the println! expression?
There is a fundamental misconception of what match is about.
Pattern-matching is NOT about matching on values but about matching on patterns, as the name imply. For convenience and safety, it also allows binding names to the innards of the matched pattern:
match some_option {
Some(x) => println!("Some({})", x),
None => println!("None"),
}
For convenience, match is extended to match the values when matching specifically against literals (integrals or booleans), which I think is at the root of your confusion.
Why? Because a match must be exhaustive!
match expressions are there so the compiler can guarantee that you handle all possibilities; checking that you handle all patterns is easy because they are under the compiler's control, checking that you handle all values is hard in the presence of custom equality operators.
When using just a name in the match clause, you create an irrefutable pattern: a pattern that cannot fail, ever. In this case, the entire value being matched is bound to this name.
You can exhibit this by adding a second match clause afterward, the compiler will warn that the latter binding is unreachable:
fn main() {
let x = 42;
match x {
name => println!("{}", name),
_ => println!("Other"),
};
}
<anon>:6:5: 6:6 error: unreachable pattern [E0001]
<anon>:6 _ => println!("Other"),
^
Combined with the shadowing rules, which specifically allow hiding a binding in a scope by reusing its name to bind another value, you get the example:
within the match arm, x is bound to the value of 'c'
after the arm, the only x in scope is the original one bound to the value 'x'
Your two points are caused by the same root problem. Coincidentally, the reason that this section exists is to point out the problem you asking about! I'm afraid that I'm basically going to regurgitate what the book says, with different words.
Check out this sample:
match some_variable {
a_name => {},
}
In this case, the match arm will always succeed. Regardless of the value in some_variable, it will always be bound to the name a_name inside that match arm. It's important to get this part first — the name of the variable that is bound has no relation to anything outside of the match.
Now we turn to your example:
match c {
x => println!("x: {} c: {}", x, c),
}
The exact same logic applies. The match arm with always match, and regardless of the value of c, it will always be bound to the name x inside the arm.
The value of x from the outer scope ('x' in this case) has no bearing whatsoever in a pattern match.
If you wanted to use the value of x to control the pattern match, you can use a match guard:
match c {
a if a == x => println!("yep"),
_ => println!("nope"),
}
Note that in the match guard (if a == x), the variable bindings a and x go back to acting like normal variables that you can test.

Match String Tuple in Rust

This is one of those simple-but-I-don't-know-how-to-do-it-in-rust things.
Simply put:
pub fn pair_matcher(tup: &(String, String)) {
match tup {
&("foo".as_string(), "bar".as_string()) => print!("foobar"),
_ => print!("Unknown"),
}
}
I get the error
-:3:17: 3:18 error: expected `,`, found `.`
-:3 &("foo".as_string(),"bar".as_string())=> { print!("foobar"); }
^
How do you match this?
The left hand side of each branch of a match is not an expression, it is a pattern, which restricts what can go there to basically just literals (plus things like ref which change the binding behaviour); function calls are right out. Given how String works, it’s not possible to get one of them into a pattern (because you can’t construct one statically). It could be achieved with if statements:
if tup == ("foo".to_string(), "bar".to_string()) {
print!("foobar")
} else {
print!("Unknown")
}
… or by taking a slice of the Strings, yielding the type &str which can be constructed literally:
match (tup.0.as_slice(), tup.1.as_slice()) {
("foo", "bar") => print!("foobar"),
_ => print!("Unknown"),
}
Constructing a new String each time is an expensive way of doing things, while using the slices is pretty much free, entailing no allocations.
Note that the .0 and .1 requires #![feature(tuple_indexing)] on the crate; one can do without it thus:
let (ref a, ref b) = tup;
match (a.as_slice(), b.as_slice()) {
("foo", "bar") => print!("foobar"),
_ => print!("Unknown"),
}
Because, you see, the left hand side of a let statement is a pattern as well, and so you can pull the tuple apart with it, taking references to each element, with (ref a, ref b) yielding variables a and b both of type &String.
The Patterns section of the guide goes into some more detail on the subject.
The solution here is that you need to cast types in the other direction:
match (tup.0.as_slice(), tup.1.as_slice()) {
("foo", "bar") => print!("foobar"),
}

Resources