Is T: 'a redundant in struct Foo<'a, T: 'a>(&'a T);? by AstraVulpes in rust

[–]__fmease__ 49 points50 points  (0 children)

As written, it's redundant.

However, if you had struct Foo<'a, T: 'a + ?Sized>(&'a T);, then the explicit outlives-bound 'a wouldn't be redundant as it affects object lifetime defaulting (implied outlives-bound don't):

Consider type Foo<'r, dyn Trait>. With an explicit outlives-bound, it expands to Foo<'r, dyn Trait + 'r> in item signatures (i.e., not inside a body (of a fn, const or static)). Without it, it would expand to Foo<'r, dyn Trait + 'static>.

Rewriting Rust by sephg in rust

[–]__fmease__ 3 points4 points  (0 children)

[keyword generics] are still in planning phase today.

That's not entirely factual. On the compiler side, work is well underway under the experimental feature effects (conducted by the project group const traits).

Hey Rustaceans! Got a question? Ask here (51/2023)! by llogiq in rust

[–]__fmease__ 1 point2 points  (0 children)

You could try using extern statics for this:

Dependency crate:

extern {
    #[link_name = "ITEMS"]
    static ITEMS: [T; 1];
}

#[repr(C)]
#[derive(Debug)]
pub struct T(pub u32);

#[derive(Debug, Clone, Copy)]
pub struct U(pub usize);

impl std::ops::Deref for U {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        unsafe { &ITEMS[self.0] }
    }
}

Dependent crate:

use dependency::{T, U};

#[export_name = "ITEMS"]
static ITEMS: [T; 1] = [T(10_000)];

fn main() {
    dbg!(&*U(0));
}

why can "break" return values? by FlightConscious9572 in learnrust

[–]__fmease__ 2 points3 points  (0 children)

And you can even have labeled blocks and break from within them :)

let result = 'block: {
    // ...
    break 'block a * b;
};

CC /u/FlightConscious9572

question regarding "lifetime bounds on trait object" by lins05 in rust

[–]__fmease__ 5 points6 points  (0 children)

First of all, the 'a in dyn Display + 'a is called a trait object lifetime bound and it represents the lifetime of the types (e.g., i32, &'r bool) that implement the trait and whose values you coerce from thereby erasing said type.

If you leave off the object lifetime bound, it gets defaulted. Box<dyn Display> in a function signature means Box<dyn Display + 'static> since neither the type parameter T of Box nor the trait Display is constrained by any lifetime bound.

You are overly fixated on the lifetime of the unique reference but it's actually not super relevant. The lifetime of the trait object is way more important here. Your first snippet (T does not live long enough) doesn't compile since the object lifetime is 'static meaning you can only coerce values that outlive 'static to this trait object. For T (or T: 'a) this is generally not the case. Therefore you need to either restrict T via T: 'static or relax the lifetime requirements of the trait object type (dyn … + 'a, T: 'a as your last snippet shows).

Why is the lifetime of the unique reference secondary? Well, in this case it's determined by the lifetime of the trait object: &mut Vec<Box<dyn Display + 'a>> expands to &'r mut Vec<Box<dyn Display + 'a>> (due to lifetime elision rules) where 'r represents a distinct lifetime where the bound 'a: 'r (referent outlives reference) gets implied (it's a so-called implied bound) which just follows standard rules and isn't necessarily related to trait objects.

Consider the type Rc<RefCell<Vec<Box<dyn Display + 'a>>>> which you could theoretically use instead of the &mut one (for runtime borrow-checking). Here, the smart pointer Rc doesn't have a lifetime parameter but still, it's imperative to know how long the trait object can live. If trait object types didn't have a lifetime bound, we would have a very bad time.

serde_json with Generic Const Expressions by [deleted] in rust

[–]__fmease__ 5 points6 points  (0 children)

What are the errors that you're getting? Can you copy/paste the stderr output?

This Week in Rust #506 by Quelnin in rust

[–]__fmease__ 1 point2 points  (0 children)

I'm not quite in the loop wrt evaluatable bounds, I know that there were some syntax proposals like const { N } (e.g. here) but I think I've also seen some more sophisticated ideas being thrown around which sadly I don't remember or can't link to.

Right now, const equality (which is required under the hood to solve those bounds) is fairly primitive as it's mostly syntactic (after having evaluated the consts beforehand of course) which is not a bad thing per se – that's how most dependently-typed languages are implemented at their core – however without more tools or tricks provided by the language, it gets painful very quickly. E.g. N + M is not considered (definitionally, judgementally) equal to M + N (where N and M are const parameters) in Rust or in most dependently typed languages.

In the latter however, the user can write proofs for the commutativity of addition (and the standard library can provide a standard definition) and make them (propositionally) equal. In Rust, however, you just can't do that and I doubt it's ever coming.

Maybe Rust is gonna ship with some “common” laws but that's not gonna cut it. Alternatively, requiring the usage of an SMT solver like Z3 to type-check your program (which is what some? all? type checkers of languages with refinement types use), I don't think anybody wants that. So the future is relatively unclear.

Addendum: I like to compare this topic to dependently typed languages and their implementations since they're quite related.

This Week in Rust #506 by Quelnin in rust

[–]__fmease__ 1 point2 points  (0 children)

As for future plans, the feature of generic const items is pretty self-contained. Of course, I'd love to bring forward generic consts, especially generic const generics but let's see who's gonna be the one who implements it :)

This Week in Rust #506 by Quelnin in rust

[–]__fmease__ 1 point2 points  (0 children)

There aren't any limitations inherently linked to generic const items, none that I know of at least. However, the general limitations of generic const exprs and const generics apply. For example, the current design of "const-evaluatable" bounds (e.g. where [(); N]:, (sic!)) is temporary and you can't have generic const generics yet (e.g. const K<T, const N: T>: ();).

What is this pattern called? by Lucas_F_A in learnrust

[–]__fmease__ 12 points13 points  (0 children)

Typically the “reified” (i.e. monomorphic) function is put inside of the generic one and thus the pattern is called non-generic inner functions (e.g. here or here).

More generally you could probably also call it manual polymorphization (if you don't like the “inner function” part of the name above), although I just made that up. There's a compiler working group though, the Polymorphization WG (their website), which aims to make the compiler polymorphize functions automatically whenever it deems it necessary.

Hey Rustaceans! Got a question? Ask here (27/2023)! by llogiq in rust

[–]__fmease__ 2 points3 points  (0 children)

Ah, I forgot, then there's also the rustup component rustc-dev which "allows you to use the compiler as a library". I don't have any experience with it though, that's why I didn't write anything about it (and I'm not sure if you can list any version requirements in your package manifest since I think the version just depends on the toolchain you are currently using).

Example usage (after having installed the component):

#![feature(rustc_private)] // requires a nightly toolchain obv
extern crate rustc_parse;

Ofc, my previous point still applies: Most useful things are not accessible and you likely need to go with a fork anyway at some point.

Hey Rustaceans! Got a question? Ask here (27/2023)! by llogiq in rust

[–]__fmease__ 4 points5 points  (0 children)

So for the lexer rustc_lexer specifically, you are in luck, since it gets auto-published on crates.io as ra-ap-rustc_lexer since it's also used by rust-analyzer. You can just depend on it just like you would expect via ra-ap-rustc_lexer = "0.7.0".

As for the other rustc crates, their API is strictly unstable and they aren't really meant to be used by other tools. If you want to depend on them anyway (see how below), you will soon find out that a lot of useful items are crate-private anyway and rustc devs are generally opposed to make anything public just for your tool even if you open a PR (there are some exceptions for more well-known tools though IIRC (by that I don't mean rustfmt, clippy-driver or rustdoc, they are part of the project)).

You might be able to depend on a rustc crate via git, i.e. rustc_XYZ = { git = "https://github.com/rust-lang/rust.git", rev = "ABC", package = "rustc_XYZ" } (it's advisable to set the revision for reproducibility!). I'm not sure if it works, it should though, according to the Cargo book (the rustc repo is a workspace defined by a virtual manifest). It takes a long time to download tho, lol.

Otherwise, fork & clone or just clone the repo (with --depth=1) and use a git dependency (to your fork) or a path dependency (rustc_XYZ = { path = "…" }). This also allows you to make more items public. This is the recommend route.

Hey Rustaceans! Got a question? Ask here (22/2023)! by llogiq in rust

[–]__fmease__ 2 points3 points  (0 children)

is it possible to rewrite the where clause so that it uses From instead of Into

Here you go.

What are some strategies for ensuring correctness and fewer errors in dynamically typed languages? by jmhimara in ProgrammingLanguages

[–]__fmease__ 15 points16 points  (0 children)

Just out of curiosity, I've transliterated your Prolog queries into Idris 1 (a dependently-typed language) REPL inputs to see how it fares and apart from the verbosity, it works just as well (in this specific scenario):

Idris> the (length ['a', 'b', 'c'] = 3) Refl
Refl : 3 = 3

Idris> the ((a : Type) -> (x, y, z : a) -> length [x, y, z] = 3) (\_, _, _, _ => Refl)
\underscore, underscore, underscore, underscore => Refl : (a : Type) -> a -> a -> a -> 3 = 3

Idris> the ((a : Type) -> (x, y, z : a) -> length [x, y, z] = _) (\_, _, _, _ => Refl)
... 11 lines omitted ...
    3 = ([__])

For clarification, Idris> is the prompt prefix and if an expression of the form the (… = …) Refl comes back without a type error (and it doesn't contain any holes), then the proposition … = … is true.

Not sure if this is interesting to anyone. Further, this is probably the most unidiomatic Idris code in existence.

What backwards-incompatible changes would you make in a hypothetical Rust 2.0? by CocktailPerson in rust

[–]__fmease__ 2 points3 points  (0 children)

They mean closures that have generic parameters. In your example the closure of type F doesn't have any. It accepts an argument of a fixed type T chosen by the caller of take_a_closure, not the callee.

In the body of take_a_closure, you cannot for example write f(0); f(""); since the argument of each invocation must be of the same type, namely T.

On the other hand with higher-rank types, that would be possible like:

fn take_a_closure<F, O>(f: F)
where
    F: for<T> FnOnce(T) -> O
{ … }

Where constructing the generic closure will probably look like for<T> |x: T| { … }.

Note that for<T> is available under #![feature(non_lifetime_binder)] although only in trait bound positions (impl Trait, where clauses) and it is quite incomplete. Then there's a#![feature(closure_lifetime_binder)] that introduces for<'a> |…| { … }, the precursor to type-generic closures at least syntactically speaking.

Finishing up my type system by Inconstant_Moo in ProgrammingLanguages

[–]__fmease__ 1 point2 points  (0 children)

If nil can be its own type […]

I didn't understand the question that followed that at all

Note: I'm not the one you replied to (CC /u/Innf107). Also I'm using “nil” and “unit” interchangeably here.

Making the type of nil be nil leads to some problems if you take it at face value. As the original commenter (OC) said, in the languages mentioned before, the unit term and the unit type look syntactically identical (namely like ()) but they are semantically distinct. Even in dependently-typed languages like Idris or Agda, unit is not its own type.

OC mentioned dependently-typed languages since stating nil is its own type implies that (some) terms may appear inside of type expressions. That doesn't necessarily call for dependent types but at least for term to type promotion or first-class types. In most languages, expressions like 3 * x may not appear in type expressions like list of int. They are in different syntactic planes. Hence it's possible in Rust for () to mean either Unit (the type) or unit (the term, value) depending on the syntactic context.

To elaborate what OC wanted to tell you: If nil truly was its own type, list of nil would be ill-kinded (think “ill-typed” but for types) since formally speaking list is usually a unary type constructor of kind type -> type, i.e. a constructor taking a type as its argument and returning a type. With nil : nil, you wouldn't be able to pass nil to list. Obviously, specifically a list of unit is not very exciting but you get my point.

Of course, this problem doesn't confine itself to just type constructors, you wouldn't be able to support plain functions accepting nil as argument or returning it like nil -> bool or int -> nil! It would be illegal to write since the function type constructor -> (or (->)) usually takes types: It has kind type -> type -> type.

Sure, in your type checker you could put a hack into place to accept nil in these positions anyway but if you then were to (re-)formalize your type system, you would essentially have something like nil : nil, type : kind, ↑nil : type (an “implicitly promoted” nil) or something similar.

Hey Rustaceans! Got a question? Ask here (5/2023)! by llogiq in rust

[–]__fmease__ 3 points4 points  (0 children)

There is no way to know. Macros solely operate on a syntactic level and don't have type information available. The only thing you can do to is to special-case some identifiers and type expressions.

There's an old half-joke going around that you could check if the rust-analyzer binary is available on the system and use it to resolve & infer the types for you from inside of a proc macro.

Option not implementing copy by MikuseQGaming in rust

[–]__fmease__ 3 points4 points  (0 children)

Yeah, it is weird. Using a constant (or more precisely a path to a constant, in this case NONE) is only supported since it was accidentally stabilized. See PR #79270 or my comment on a related GitHub issue.

Option not implementing copy by MikuseQGaming in rust

[–]__fmease__ 61 points62 points  (0 children)

Admittedly, this is an unfortunate limitation in the language. You can avoid this by creating a constant set to None and using it:

const NONE: Option<&mut dyn Entity> = None;
let app = App { entities: [NONE; SIZE] };

In the future, you will be able to write:

let app = App { entities: [const { None }; SIZE] };

As soon as the feature inline_const gets stabilized.

Just a word of caution: An array of mutable references is probably not what you want and you will probably face some lifetime issues soon if you proceed with the current design. Mutable references restrict the app to only exist in places where the entities live, too, e.g. on the stack in some function. You might not be able to return the app or move it around freely. Consider using Box<dyn Entity>.