Is it possible to declare alias fields in Alloy? - alloy

In my current model, I am finding it helpful to define alias fields. These are fields that are really just expressed as an expression of an existing field. I recently discovered the = syntax for declarations, which makes this really easy:
sig Foo {}
sig Class {
thing1 : Foo,
thing2 : Foo,
alias = thing1 + thing2
}
I can refer to alias in constraints, but not in other field declarations. For example:
sig Foo {}
sig Class {
thing1 : Foo,
thing2 : Foo,
alias = thing1 + thing2,
reference : alias
}
results in A syntax error has occurred: The name "alias" cannot be found.
Is there a reason why I can't refer to alias in this context?
On a related note, is there any documentation on declaring fields using =? I can't find it referenced anywhere in the documentation.

I'm not aware of the equals syntax in declarations. But you don't need it; just write your example like this instead
sig Foo {}
sig Class {
thing1, thing2: Foo,
alias: set Foo,
reference: set alias
} {
alias = thing1 + thing2
}

Aliases were originally defined using let expressions.
I don't know if it still works in current Alloy implementations, but in Alloy 4, I'd write:
let alias = thing1 + thing2
sig Foo {}
sig Class {
thing1 : Foo,
thing2 : Foo,
reference : alias
}
run{}

Related

Can I alias a type inside of a trait's definition, without the compiler assuming that I am defining an associated type with a default?

The code below doesn't compile on stable Rust 1.52:
trait Trait {
type Foo;
}
trait OtherTrait {
type Bar: Trait;
type MyFoo = <Self::Bar as Trait>::Foo; // This is currently illegal...
// ...but I want to be able to write this:
fn example1() -> Self::MyFoo;
/// Instead of having to write this:
fn example2() -> <Self::Bar as Trait>::Foo;
}
The compiler complains that "associated type defaults are unstable". However, I don't want MyFoo to be an associated type with a default, only a convenient alias for <Self::Bar as Trait>::Foo inside the body of OtherTrait. Is there any way to achieve this?
Is there any way to achieve this?
Not exactly that, but you can achieve similar result by defining an ordinary type alias outside the trait:
type OtherFoo<T> = <<T as OtherTrait>::Bar as Trait>::Foo;
trait OtherTrait {
type Bar: Trait;
fn example1() -> OtherFoo<Self>;
}
Where you intended to write Bla::MyFoo, or the longer <T as OtherTrait>::MyFoo for a generic T, you can write OtherFoo<Bla> and OtherFoo<T> respectively. It works nicely if you can get over it not being scoped inside OtherTrait.

Which method of getting a reference to a struct field is the preferred way?

I've been overwhelmed by all the ways to get a reference to a struct field from a reference to a struct. These are the ways I'm aware of right now:
struct Foo {
bar: i32,
}
let foo = &Foo { bar: 123 };
let bar1 = &foo.bar;
let ref bar2 = foo.bar;
let ref bar3 = (*foo).bar;
let &Foo { bar: ref bar4 } = foo;
let Foo { bar: bar5 } = foo;
let Foo { bar: ref bar6 } = foo;
let Foo { bar: ref bar7 } = *foo;
Which of these is the "preferred way"? I assume that field access like foo.bar is preferred for a single field and pattern matching for getting multiple ones in one go, but it's unclear to me which of the multiple ways I've listed above I should use for each case.
There's no reason to avoid the direct access which would be
let bar1 = &foo.bar;
This is easier to write and to read. You don't need pattern matching here.
Pattern matching is an additional tool, which basically solves two kinds of problems:
destructure a value into several ones, for example let (a, b) = c;
being conditional ("refutable") in a while let, if let, match arm
See All the places patterns can be used.
Some of your declarations are officially discouraged. Clippy would warn you about the ref ones.

Implementing Nested Traits

I have some traits which (after removing functions and some parameter bloat) look like:
trait Foo { }
trait Boo { }
trait Bar<T: Foo> { }
trait Baz { }
If U implements Bar<T> for some T implementing Foo and U implements Boo, then one is able to derive an implementation of Baz for U. However, I wasn't able to write valid Rust code doing this.
A few tries were:
impl<T: Foo, U: Bar<T> + Boo> Baz for U { }
which gives
error: the type parameter T is not constrained by the impl trait, self type, or predicates [E0207]
whereas
impl<U: Bar<T> + Boo> Baz for U { }
yields
error: type name T is undefined or not in scope [E0412]
Could one/how could one do this in (stable) Rust (hopefully without any dynamic dispatch)?
Edit: Some people hinted at some similar questions for which there were essentially two approaches (and I find both of them unsuitable for my situation):
Using associated types. I don't want to do this because I want to keep track of T, e.g. I want to write some functions which have a signature like fn bla<T: Foo, U: Bar<T>, V: Bar<T>>() where I want to know that U and V implement Bar<T> for the same T. (Or is there way of doing this with associated types?)
Using some kind of wrapping by putting U and T in a struct. I don't want to use this either because I have several levels of such "trait dependencies", so wrapping things in each level would bloat the code a lot.
So the updated question would be: Is there a solution to this problem without using associated types or wrappers?
You can do it making T an associated type:
trait Foo { }
trait Boo { }
trait Bar {
type T: Foo;
}
trait Baz { }
impl<U: Bar + Boo> Baz for U
// this where clause is not necessary (this bound is already true)
// where U::T: Foo
{ }
I don't want to do this because I want to keep track of T, e.g. I want to write some functions which have a signature like fn bla<T: Foo, U: Bar<T>, V: Bar<T>>() where I want to know that U and V implement Bar<T> for the same T. (Or is there way of doing this with associated types?)
Yes, you can do it with associated types:
fn bla<U: Bar, V: Bar<T = U::T>>() { }

How to import a struct that is inside of other package?

I tried to learn Go but I frequently feel frustrating because some basic features that other languages has seems not working in Go. So basically, I would like to use struct type that is
define in other file. I was able to use functions except struct type. In main.go,
package main
import (
"list"
)
func main() {
lst := list.NewList(false)
lst.Insert(5)
lst.Insert(7)
lst.InsertAt(2, 1)
lst.PrintList()
}
This works perfectly (and all other functions) as I expect (list is in $GOPATH). In package list, I defined struct as follow:
type LinkedList struct {
head *node
size int
isFixed bool
}
I wanted to use this struct in other struct, so I attempted to do something like this,
type SomeType struct {
lst *LinkedList
}
But unfortunately, I got error that the type LinkedList is not defined. How can I use a struct that is defined in other package?
The LinkedList type is in the list namespace, so change your usage of the type to:
type SomeType struct {
lst *list.LinkedList
}

nested struct initialization literals

How can I do this:
type A struct {
MemberA string
}
type B struct {
A A
MemberB string
}
...
b := B {
MemberA: "test1",
MemberB: "test2",
}
fmt.Printf("%+v\n", b)
Compiling that gives me: "unknown B field 'MemberA' in struct literal"
How can I initialize MemberA (from the "parent" struct) when I provide literal struct member values like this?
While initialization the anonymous struct is only known under its type name (in your case A).
The members and functions associated with the struct are only exported to the outside after the
instance exists.
You have to supply a valid instance of A to initialize MemberA:
b := B {
A: A{MemberA: "test1"},
MemberB: "test2",
}
The compiler error
unknown B field 'MemberA' in struct literal
says exactly that: there's no MemberA as it is still in A and not in B. In fact,
B will never have MemberA, it will always remain in A. Being able to access MemberA
on an instance of B is only syntactic sugar.
The problem is with declaring the struct A in B. Please specify the name along with declaration, then it works.
package main
import "fmt"
type A struct {
MemberA string
}
type B struct {
MemA A
MemberB string
}
func main() {
b := B{MemA: A{MemberA: "test1"}, MemberB: "test2"}
fmt.Println(b.MemberB)
}

Resources