'r&' - coherent and minimal raw pointer syntax

Analogous to the raw identifier syntax r#ident, but for raw pointers, which doesn't cause dissonance with the dereference use of *. This allows * to be part of a pattern syntax.

  • *const Tr&T
  • *mut Tr&mut T
  • ref t*t
  • ref mut t*mut t

This pattern can be disambiguated in place of types: cannot be used in an expression, as it looks like a bitand operation to the compiler.

Related RFCs

1 Like

Be aware of this potential syntactic ambiguity. The following program already compiles today:

#[allow(non_camel_case_types)]
type r<'a> = &'a bool;

const T: bool = true;

fn main() {
    println!("{}", &true as r&T);
}

If r&T changes to mean *const T, this would break.

error[E0573]: expected type, found constant `T`
 --> src/main.rs:7:31
  |
7 |     println!("{}", &true as r&T);
  |                               ^ help: a type alias with a similar name exists: `r`
9 Likes

Lightning fast..! Thank you so much for that investigation!

Here I'm pretty much sure that

  1. people expect type cast expressions to associate way weaker, at least than bitwise operations,
  2. don't write as many type casts in the middle of other arithmetic operations as they will mind parenthesise them one by one, (or with the help of tools,) and
  3. favour the more understandable/less dissonant use of symbols.

As this is going to be almost always an immediate compile error, I think we can focus on compiler diagnostics and nicer error messages, if we want this syntax.

While I agree that the current raw pointer syntax is bad and that using stars in patterns would be great, I am not fond of using a prefix to solve the issue.

The prefix notation goal is to provide a local change to the normal Rust syntax rules. It is necessary in the case of raw identifiers to allow normally invalid identifiers, or for raw strings literals to change the delimiter behavior. But raw pointers are still pretty normal types, they do not require a special syntax to work.

Instead of making raw pointers even more special, I would turn them into regular types :

  • *const TPtr<T>
  • *mut TPtrMut<T>

It would complete the big sigil removal that happened before 1.0, when ~T has been replaced by Box<T> and @T has been replaced by Rc<T> .

If I am not mistaken, the only special thing about raw pointers is that they can only be dereferenced in unsafe blocks. So Ptr would have to implement some kind of UnsafeDeref trait that works exactly like Deref, but only in unsafe context.

8 Likes

Note that we already have an unstable &raw syntax for creating raw pointers which doesn't suffer from the ambiguities of r&

I do agree through that ref in patterns is pretty weird and * would be better for the "patterns are the inverse of expressions" mindset.

4 Likes

These are very different meanings of "raw". Raw identifiers and raw strings both tell the lexer "when reading this you should keywords/escape-characters, but after reading it you hand it to the parser like it was a regular identifier/string".

Raw pointers, on the other hand, have little to do with the lexer. Other than having a special syntax, of course - but they could just have well have been a generic type RawPtr<T>. The rawness is about the type, not the syntax.

2 Likes