Understanding complicated signatures in alloy - alloy

in the below
sig building{
abv: Man -> Man
}
{
all m:Man | Above(m,m.abv)
}
What does the below mean? How is it related to the signature definition? Is this a relation for the sig?
{
all m:Man | Above(m,m.abv)
}

That is called "appended fact", and the meaning is that it must hold for all atoms of the corresponding sig. So, an equivalent fact for your model would be
fact {
all b: building |
all m: Man | Above[m, m.(b.abv)]
}
In appended facts you can use the this keyword to refer to the current atom of the corresponding sig, so a clearer way to write your appended fact would be to explicitly write m.(this.abv), as opposed to relying on abv being implicitly expanded to this.abv.

Related

Using macro output as a method name

I'm trying to write a macro that automatically expands a set of enum variants into a builder (base on a previous question, though I don't think that's relevant). Basically, I want to pass it a value, a builder struct and a list of enum variants and generate match arms. The result should be equivalent to this:
match a {
Attribute::InsuranceGroup { value } => builder.insurance_group(value),
};
I think I've managed to get fairly close, but I can't figure out how to convert the UpperCamelCase InsuranceGroup to lower_camel_case insurance_group using the casey crate, in order to call the builder method. Currently, I have:
macro_rules! unwrap_value {
($var:ident, $builder:ident, [ $( $enum:ident :: $variant:ident ),+ $(,)? ]) => {
match $var {
$($enum::$variant { value } => $builder.snake!($variant) (value),)*
}
}
}
unwrap_value! {
a, builder, [Attribute::InsuranceGroup]
}
However, this fails at $builder.snake!($variant) with the analyser complaining that it expects (, ,, ., ::, ?, } or an operator, instead of !.
I also tried moving snake! outside, snake!($builder.$variant), but then it says it can't find $builder in this scope.
While I would be interested in any suggestions of alternatives to using the builder which would eliminate this problem, I'm more interested in understanding what I'm doing wrong with the macros in order to better understand them.
While I would strongly recomment using the paste crate (23,999,580 total downloads vs 7,611 for casey as the time of writing, paste is even available on the playground!), I will explain here why casey didn't work for the sake of knowledge (and suggest a solution! But one you shouldn't use).
The first version didn't work because macros cannot be used after the dot. You can check that out easily:
macro_rules! m {
() => { m };
}
v.m!();
error: expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `!`
--> src/main.rs:6:4
|
6 | v.m!();
| ^ expected one of 7 possible tokens
Neither they will be allowed here in the future (probably), because this will collide (and confuse) with the possibility for postfix macros in the future. This is stated by the reference, too: no MacroInvocation is allowed after the dot in MethodCallExpr, TupleIndexingExpr or FieldExpr.
The natural solution is to wrap the whole call in macros (insert the (value) also there, because otherwise it considers that as if you've written (v.method)(value) and that is invalid method call): snake!($builder.$variant(value)).
However, now the compiler complains with a strange error:
error[E0425]: cannot find value `builder` in this scope
--> src\lib.rs:6:44
|
6 | $($enum::$variant { value } => snake!($builder.$variant(value)),)*
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a unit struct with a similar name exists: `Builder`
...
17 | struct Builder;
| --------------- similarly named unit struct `Builder` defined here
...
26 | / unwrap_value! {
27 | | a, builder, [Attribute::InsuranceGroup]
28 | | }
| |_____- in this macro invocation
|
= note: this error originates in the macro `snake` (in Nightly builds, run with -Z macro-backtrace for more info)
What? WHAT?? Surely builder is in scope! We declared it! Just straight before the macro call (me at least)!
The result is macro hygiene.
How does snake!() generates its identifiers? Well, let's dive into the code...
Ident::new(&transform(ident.to_string()), Span::call_site())
Hmm, let's go to the docs of Span::call_site()...
The span of the invocation of the current procedural macro. Identifiers created with this span will be resolved as if they were written directly at the macro call location (call-site hygiene) and other code at the macro call site will be able to refer to them as well.
(Emphasis mine. "The macro" here refers to the calling proc-macro, i.e. snake!() in this case).
And indeed, we can reproduce this error if we just spell out builder ourselves. Because the macro doesn't see builder. It can only see variables it created. In fact, using call-site hygiene here is a bug of casey. paste does the correct thing and uses the hygiene of the original identifier.
In fact, this just reveals a bigger problem with our approach: what if the variable will not be snake-cased already? It should be, but if not, we will snake-case it incorrectly!
But what can we do? The paste crate gives us proper control over what identifiers we want to change, but casey does not (another reason to choose paste)! Can we walk against our proc macro?
Can we??
Maybe. I see at least one approach that doesn't require us to do that (find it yourself!). But I actually do want to work against our proc-macro. Try at least. Because why not? It's funny.
snake!() doesn't look into groups. That means, it will change something like AbC - but not something like (AbC). So we can just wrap $builder in parentheses...
$($enum::$variant { value } => snake!(($builder).$variant(value)),)*
(No need to handle value because it is already snake-cased, and originates in our macro).
And it works! Voilà! (You should not depend on that. This may be a bug and subject to changes.)
Well after hunting for hours I finally found a solution shortly after posting. Instead of using the casey crate I'm using the paste crate, which includes the functionality I need. The macro code then becomes:
macro_rules! unwrap_value {
($var:ident, $builder:ident, [ $( $enum:ident :: $variant:ident ),+ $(,)? ]) => {
match $var {
$($enum::$variant { value } => paste!($builder.[<$variant:snake>](value)) ,)*
}
}
}

Function signature for generic numbers

I am trying to make a few generic functions that work on numbers, but I'm struggling with the function signatures.
Perhaps I am attacking the problem from the wrong angle, but here is where I got on my own so far. I am not hellbent on making this work this way; so if I am attacking the problem (of creating a small lib of generally useful math functions) from the wrong angle, then by all means educate me.
Let's say I want a function, add that adds up two numbers:
use std::ops::Add;
fn add(a: Add, b: Add) -> Add::Output {
a + b
}
This won't compile. Here is a playground though: https://play.integer32.com/?version=stable&mode=debug&edition=2015&gist=4589325b5c8d1f1b19440424878caa98
I get essentially two errors. The first:
error[E0393]: the type parameter `RHS` must be explicitly specified
--> src/main.rs:8:11
|
8 | fn add(a: Add, b: Add) -> Add::Output {
| ^^^ missing reference to `RHS`
|
= note: because of the default `Self` reference, type parameters must be specified on object types
I have read the chapter on advanced traits in the Rust book, so i "sort-of/kind-of" understand the RHS message, but they attack the problem of adding the Add trait to your particular data structure (a Point in the example); but never show a function signature of a function that takes anything that can be added up. So I am a little lost.
The second error:
error[E0223]: ambiguous associated type
--> src/main.rs:8:27
|
8 | fn add(a: Add, b: Add) -> Add::Output {
| ^^^^^^^^^^^ ambiguous associated type
|
= note: specify the type using the syntax `<Type as std::ops::Add>::Output`
This goes away if I write <i32 as Add>::Output, but that is not what I want. I specifically want the function to work on anything that can be added up (assuming both a and b to be the same type).
You are conflating traits and types.
Add is a trait. A trait can be implemented for a type or a class of types, but it is not a type itself.
Function arguments need to be declared with a type, not a trait. This is the main problem with your prototype – Add is not a type, so you can't use it as the type of a variable or a function argument.
Rust allows you to declare generic types, essentially type variables. You can then place trait bounds on the generic types, which require that whatever type is substituted for the generic type must implement some trait. Your example using a generic type parameter T looks like this:
fn add<T: Add>(a: T, b: T) -> T::Output
This prototype requires that a and b both have the same type T, and that T implements the Add trait.

What is the syntax: `instance.method::<SomeThing>()`?

I read the below syntax from byteorder:
rdr.read_u16::<BigEndian>()
I can't find any documentation which explains the syntax instance.method::<SomeThing>()
This construct is called turbofish. If you search for this statement, you will discover its definition and its usage.
Although the first edition of The Rust Programming Language is outdated, I feel that this particular section is better than in the second book.
Quoting the second edition:
path::<...>, method::<...>
Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., "42".parse::<i32>())
You can use it in any kind of situation where the compiler is not able to deduce the type parameter, e.g.
fn main () {
let a = (0..255).sum();
let b = (0..255).sum::<u32>();
let c: u32 = (0..255).sum();
}
a does not work because it cannot deduce the variable type.
b does work because we specify the type parameter directly with the turbofish syntax.
c does work because we specify the type of c directly.

"Expected reference, found struct Rc" when cloning and returning an Rc

I have a piece of code like this:
use std::cell::RefCell;
use std::rc::Rc;
struct A(bool);
impl A {
fn get_ref(&self) -> &Rc<RefCell<bool>> {
&Rc::new(RefCell::new(self.0))
}
fn copy_ref(&self) -> &Rc<RefCell<bool>> {
Rc::clone(self.get_ref())
}
}
fn main() {
let a = A(true);
a.copy_ref();
}
and I received warning complaining about the Rc::clone function not getting a reference:
error[E0308]: mismatched types
--> src/main.rs:12:9
|
12 | Rc::clone(self.get_ref())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `std::rc::Rc`
|
= note: expected type `&std::rc::Rc<std::cell::RefCell<bool>>`
found type `std::rc::Rc<std::cell::RefCell<bool>>`
I have been working on this all night but I cannot get it to work. The method get_ref is already typed as returning &Rc<RefCell<bool>>, but why would the compiler give the error?
The error is not talking about the argument you put into Arc::clone(), but the whole expression Rc::clone(...) which has a different type (Rc<...>) than the return type of your function (&Rc<...>).
If you were passing a wrong argument to Rc::clone, it would like look this:
--> src/main.rs:13:19
|
13 | Rc::clone(false)
| ^^^^^ expected reference, found bool
|
= note: expected type `&std::rc::Rc<_>`
found type `bool`
So the naive way to fix the type error is to write &Rc::clone(...) instead. Then the last expression of your function has the same type as your function's declared return type. But as you will notice, you will get other errors afterwards.
Let's take a step back to see that your approach is flawed here. For the most important point, please see "Is there any way to return a reference to a variable created in a function?". Spoiler: you really don't want to. So constructs like your get_ref() just don't make sense, as you return a reference to a variable you create inside your function (a variable of type Rc).
In your case the direct solution is probably pretty simple: just remove the reference. Rc<T> is already a pointer/reference type, so there is no need (in general) to have a reference to it.
However, since you are using Rc, you are probably interested in reference counting. So in that case, you probably shouldn't create a new Rc every time the function is called. Otherwise you could end up with a bunch of Rcs with reference count 1, which is not really the point. So instead, your type A should already store an Rc<RefCell<bool>>.
But all I'm doing here is guessing what you actually want to do which is not clear from your question. Maybe you can ask a different question, or add the information to this question, or explain this in the comments.

How does Rust infer resultant types from From::<>::from()?

In this snippet from Hyper's example, there's a bit of code that I've annotated with types that compiles successfully:
.map_err(|x: std::io::Error| -> hyper::Error {
::std::convert::From::<std::io::Error>::from(x)
})
The type definition of From::from() seems to be fn from(T) -> Self;
How is it that what seems to be a std::io::Error -> Self seems to return a hyper::Error value, when none of the generics and arguments I give it are of the type hyper::Error?
It seems that some sort of implicit type conversion is happening even when I specify all the types explicitly?
Type information in Rust can flow backwards.
The return type of the closure is specified to be hyper::Error. Therefore, the result of the block must be hyper::Error, therefore the result of From::from must be hyper::Error.
If you wanted to, you could use ...
<hyper::Error as ::std::convert::From>::<std::io::Error>::from(x)
... which would be the even more fully qualified version. But with the closure return type there, it's unnecessary.
Type inference has varying degrees.
For example, in C++ each literal is typed, and only a fully formed type can be instantiated, therefore the type of any expression can be computed (and is). Before C++11, this led to the compiler giving an error message: You are attempting to assign a value of type X to a variable of type Y. In C++11, auto was introduced to let the compiler figure out the type of the variable based on the value that was assigned to it.
In Java, this works slightly differently: the type of a variable has to be fully spelled out, but in exchange when constructing a type the generic bits can be left out since they are deduced from the variable the value is assigned to.
Those two examples are interesting because type information does not flow the same way in both of them, which hints that there is no reason for the flow to go one way or another; there are however technical constraints aplenty.
Rust, instead, uses a variation of the Hindley Milner type unification algorithm.
I personally see Hindley Milner as a system of equation:
Give each potential type a name: A, B, C, ...
Create equations tying together those types based on the structure of the program.
For example, imagine the following:
fn print_slice(s: &[u32]) {
println!("{:?}", s);
}
fn main() {
let mut v = Vec::new();
v.push(1);
print_slice(&v);
}
And start from main:
Assign names to types: v => A, 1 => B,
Put forth some equations: A = Vec<C> (from v = Vec::new()), C = B (from v.push(1)), A = &[u32] OR <A as Deref>::Output = &[u32] OR ... (from print_slice(&v),
First round of solving: A = Vec<B>, &[B] = &[u32],
Second round of solving: B = u32, A = Vec<u32>.
There are some difficulties woven into the mix because of subtyping (which the original HM doesn't have), however it's essentially just that.
In this process, there is no consideration for going backward or forwarded, it's just equation solving either way.
This process is known as Type Unification and if it fails you get a hopefully helpful compiler error.

Resources