How to define recursive type alias in Rust? - rust

So in Rust, I can define recursive type using enum like this:
enum Trie {
Child(HashMap<char, Box<Trie>>)
}
However this is a little bit verbose, considering that this enum has only one member.
May I know how to make it simpler? Let's say using type alias like this?
// This code does not compile in rustc 1.55.0
type Trie = HashMap<char, Box<Trie>>;

Using a single field struct compiles:
struct Trie(HashMap<char, Box<Trie>>);

Related

Why do we need to define the generic type with the function name other than the parameter signatures in Rust?

Going over the generic types chapter of the official Rust book, I noticed that we have to define the generic function as follows:
fn largest<T>(list: &[T]) -> T {
My doubt is: why add <T> right after largest? We don't do that for non-generic functions such as: fn largest(list: &[i32]) -> i32.
They mean two different (and equally valid) things
fn largest<T>(list: &[T]) -> T
This says "largest is a function that, for any type T, takes a slice of T and returns a T". On the other hand,
fn largest(list: &[T]) -> T
This function says "largest takes a slice of T and returns a T", where T is some specific type in scope. That is, this second definition assumes there's something of the form
struct T {}
or some other type declaration, alias, or import in scope right now, and largest only works for that type. Note that T is a horrible name for a specific type, but Rust doesn't care about good names. As far as Rust is concerned, T is a perfectly valid type. So is ndscjkdbhsgey, but please don't name your structs that either. We need the <T> to tell Rust "this is not a specific type name; it's a variable, and I'm choosing to call it T".
Because you have to create the generic type T. i32 is a predefined type while T is one that only exists within the context of that function and you have to define it like a variable for the compiler. It does not have to be T and you could have made the function definition be fn largest<U>(list: &[U]) -> U.
I'd say the <T> syntax introduces the type T in scope so it can be used for parameter types and return type. If you didn't mark the function with <T> how would it know what T is? It would rely on the type being visible already which is the case for the non-generic function you provided - i32 is imported by default.
For the same reason we write <T> after generic implementations. For example impl<T> SomeGenericStruct<T>. If you didn't mark the implementation, or in the case of your question, your function, as a generic with the <T> syntax, which is also required of lifetimes such as <&'a T>, then the compiler wouldn't treat T as a generic.

Is it possible to use functions on Rust's constant generics

So say I'm writing a wrapper type for the array.
struct Array<const L: usize, T> {
raw: [T;L]
}
And I have some function that mutates the length of the array wrapper, say the function is concatenation:
impl<const L: usize, T> Array<L, T> {
fn concat<const L2: usize>(self, other: Array<L, T>) -> Array<{L + L2}, T> {todo!();}
}
When I try to compile this code, the rust compiler gets extremely mad. Thinking it might have something to do with adding types corresponding to implementing multiple, traits, i tried multiplication instead of addition, which also didn't work.
I know that rust can evaluate some expressions at compile time, is this just a case where that isn't allowed, or am I missing something?
When I try to compile this code, the rust compiler gets extremely mad. [ā€¦] I know that rust can evaluate some expressions at compile time, is this just a case where that isn't allowed, or am I missing something?
You say that the compiler gets mad at you, but have you considered listening at what it was telling you?
Plugging your code into the playground, the first error is a trivial showstopper of
error: type parameters must be declared prior to const parameters
--> src/lib.rs:1:30
|
1 | struct Array<const L: usize, T> {
| -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const L: usize>
so it kind-of doesn't seem to because that's trivial to fix.
Now fixing that we get to the meat of the issue:
= help: const parameters may only be used as standalone arguments, i.e. `L`
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
that seems to explain the entirety of the thing: what's currently enabled in Rust is the
Const generics MVP
MVP as in minimum viable products aka the smallest featureset which can be useful, and what that translates to is explained in the introductory blog post.
The first limitation is
Only integral types are permitted for const generics
which is fine here because you're using integral types, but the second limitation is
No complex generic expressions in const arguments
What is a complex generic expression? Anything outside of:
A standalone const parameter.
A literal (i.e. an integer, bool, or character).
A concrete constant expression (enclosed by {}), involving no generic parameters.
What you're trying to do does not work (outside of nightly with both const_generics and const_evaluatable_checked enabled) because you're writing constant expressions involving at least one generic parameter, which is not part of the MVP.

What are the differences between the multiple ways to create zero-sized structs?

I found four different ways to create a struct with no data:
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
struct C(()); // unit-valued tuple struct
struct D; // unit struct
(I'm leaving arbitrarily nested tuples that contain only ()s and single-variant enum declarations out of the question, as I understand why those shouldn't be used).
What are the differences between these four declarations? Would I use them for specific purposes, or are they interchangeable?
The book and the reference were surprisingly unhelpful. I did find this accepted RFC (clarified_adt_kinds) which goes into the differences a bit, namely that the unit struct also declares a constant value D and that the tuple structs also declare constructors B() and C(_: ()). However it doesn't offer a design guideline on why to use which.
My guess would be that when I export them with pub, there are differences in which kinds can actually be constructed outside of my module, but I found no conclusive documentation about that.
There are only two functional differences between these four definitions (and a fifth possibility I'll mention in a minute):
Syntax (the most obvious). mcarton's answer goes into more detail.
When the struct is marked pub, whether its constructor (also called struct literal syntax) is usable outside the module it's defined in.
The only one of your examples that is not directly constructible from outside the current module is C. If you try to do this, you will get an error:
mod stuff {
pub struct C(());
}
let _c = stuff::C(()); // error[E0603]: tuple struct `C` is private
This happens because the field is not marked pub; if you declare C as pub struct C(pub ()), the error goes away.
There's another possibility you didn't mention that gives a marginally more descriptive error message: a normal struct, with a zero-sized non-pub member.
mod stuff {
pub struct E {
_dummy: (),
}
}
let _e = stuff::E { _dummy: () }; // error[E0451]: field `_dummy` of struct `main::stuff::E` is private
(Again, you can make the _dummy field available outside of the module by declaring it with pub.)
Since E's constructor is only usable inside the stuff module, stuff has exclusive control over when and how values of E are created. Many structs in the standard library take advantage of this, like Box (to take an obvious example). Zero-sized types work in exactly the same way; in fact, from outside the module it's defined in, the only way you would know that an opaque type is zero-sized is by calling mem::size_of.
See also
What is an idiomatic way to create a zero-sized struct that can't be instantiated outside its crate?
Why define a struct with single private field of unit type?
struct D; // unit struct
This is the usual way for people to write a zero-sized struct.
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
These are just special cases of basic struct and tuple struct which happen to have no parameters. RFC 1506 explains the rational to allow those (they didn't used to):
Permit tuple structs and tuple variants with 0 fields. This restriction is artificial and can be lifted trivially. Macro writers dealing with tuple structs/variants will be happy to get rid of this one special case.
As such, they could easily be generated by macros, but people will rarely write those on their own.
struct C(()); // unit-valued tuple struct
This is another special case of tuple struct. In Rust, () is a type just like any other type, so struct C(()); isn't much different from struct E(u32);. While the type itself isn't very useful, forbidding it would make yet another special case that would need to be handled in macros or generics (struct F<T>(T) can of course be instantiated as F<()>).
Note that there are many other ways to have empty types in Rust. Eg. it is possible to have a function return Result<(), !> to indicate that it doesn't produce a value, and cannot fail. While you might think that returning () in that case would be better, you might have to do that if you implement a trait that dictates you to return Result<T, E> but lets you choose T = () and E = !.

Is there a more succinct way to use an enum especially when it only has primitive types?

I'm using an enum for polymorphism in Rust. I need to have a vector that can have integers or floating point values in it:
enum Value {
Float(f32),
Int(i32),
}
let vec = Vec::<Value>::new();
vec.push(Value::Int(0));
vec.push(Value::Float(1.0));
Is there a more succinct way to do this, particularly when you're only using primitive types?
No, there is not.
There are tricks to reduce the amount of code:
There's no need to specify the type of the vector.
You could construct the vector all at once.
You could import the enum variants.
fn main() {
use Value::*;
let vec = vec![Int(0), Float(1.0)];
}
it mostly feels strange that I'm effectively just renaming the primitive types
That's just an artifact of your program. For example, there's no real difference to the computer between your enum and this one:
enum MagicSpell {
Multiplier(f32),
NumberOfStomachs(i32),
}
However, the semantics (a.k.a. the names) are highly different.

How can I create Haskell-like functional dependencies

Background: I'm using the nalgebra library and I want to create a structure that represents a multivariate normal distribution. The number and row type is uniquely determined by a square matrix type, so I want to write something like this:
#[allow(non_snake_case)]
pub struct Multivarš’©<M: SquareMat<N, V>> {
Ī¼: V,
Ī£: M,
}
If I was using Haskell, I would specify a functional dependency between M and N and V. What's the best way to do this in Rust?
While Haskell has two things to express such relationship between types, fundeps and associated types, Rust has only the latter. Traits in Rust can contain type members which are assigned with concrete values at the implementation site, and the compiler considers them uniquely identified by the combination of type parameters of the trait (including Self). So you need to define SquareMat trait like this:
trait SquareMat {
type N;
type V;
...
}
impl SquareMat for SomeStruct {
type N = Four;
type V = f64;
...
}
And then this trait can be used like this:
#[allow(non_snake_case)]
pub struct Multivarš’©<M: SquareMat> {
Ī¼: M::V,
Ī£: M,
}
If you don't control SquareMat, well, then you're out of luck - you cannot define a functional dependency at the trait usage site, only at the trait declaration site, just like in Haskell.

Resources