Could you please add a new Syntax?

When dereferencing, I think it would be easier to write and read code if the Rust team used 'value.&' as a synonym for the existing '*value' keyword.

Also, could you add 'sudo' as a synonym for the 'unsafe' keyword?

I think sudo is more intuitive than unsafe, so it would be helpful for writing code.

"sudo" is short for "superuser do". The unsafe keyword has nothing to do with superuser priviledges, all code is allowed to call unsafe APIs.

7 Likes

Is it possible to make pointer dereference syntax like 'value.&' possible?

:sweat_smile::sweat_droplets:

So we are going to have another syntax for dereferencing?

The answer is basically no.

The proper process for language changes is to submit an RFC (see Propose a change to the language - The Rust Language Design Team)

However in your case I believe this falls under Frequently Requested Changes - The Rust Language Design Team so it is extremely unlikely that such a change would be considered worthwhile.

That said, I'm personally interested in where postfix operators could be useful for new languages, the postfix await in async rust was a success, so for a new experimental language it seems worth exploring this further.

4 Likes

Note that Pascal used postfix operation for dereferencing half-century ago and it was much easier to use it than dereference in C.

It's a pity that Rust had to use ugly C style (even if it was right decision, definitely but the resulting syntax is still ugly).

I got my start programming with Borland Delphi that came on a CD with a computer magazine when I was a young teenager. I don't miss the Pascal syntax though, begin and end is too verbose. Using sigils for that was the right approach (though I don't agree with curly braces due to how awkward they are to type on the Swedish keyboard layout). Or even better, make the language indentation sensitive like Python and Haskell.

I can't say I remember what the deref operator was in Pascal.

1 Like

It was caret. So you would write Foo^.Bar without any ambiguity. C++ had to introduce -> and Rust went with Deref… both are significantly more complicated and hard to use, because they are not universal, sometimes you still need to use *Foo and explosion of parens.

At least it's readable. Endless piles of parens that you get from the *Foo syntax are PITA, even if Rust eliminated the worst problem by removing the dreadful spiral rule (which was possible to do because C++ suffered so much from that crazyness that C++11 already had a way to declare return function after it's name).

I agree that given the constraint (make it appealing to C++ developers) Rust syntax is good, but compared to other, more readable languages… oh, well, we could have had worse.

2 Likes

I don't like this ... It's very easy to refactor Rust in an editor and just format on save. With indentation-sensitive languages you have to be really careful when you want to, say, guard a block of code with a condition.

Are begin and end really that verbose? It just seems like a stylistic choice (and using end if, end while etc has some arguable advantages). Just like we use struct instead of record ... because C is supposedly cooler than Pascal?

2 Likes

On case it satisfies your psychic requirement you could write value.deref() and chain from there; I can't remember if you have to use std::ops::Deref;

no playground as I'm on my phone

1 Like

Having worked with C++ for over a decade: Yes, Rust syntax is reasonably good and just fades into the background for the most part (ahem turbofish...).

I don't find C or C++ hard to parse on this low syntax level except for declaration of function pointers (which truly is hell, use typedefs liberaly to help mitigate). On a higher semantic level some of the template stuff can also be really hard to parse of course.

That said, I also used many other languages over the years: Python, Erlang, Bash, sed, awk, Prolog, dabbled in Haskell, tried out Scheme, etc.

I don't think any of those are obviously superior to the C style syntax. They all have various quirks in different ways.

  • Erlang has unparalleled pattern matching, including at the top level of function declarations, but the usage of ,.; is rather awkward (same goes for Prolog which Erlang is inspired from). Syntax is serviceable apart from that.
  • Can't say that I'm a fan of Scheme/Lisps (many cool ideas, worth learning to broaden your horizons, not a daily driver). Too many parantheses to keep track visually.
  • Python's syntax is also perfectly serviceable (and I rather like meaningful indentation. Being able to put an else on a for loop is terrible though. The issues with Python are mostly on other layers than the syntax though (lack of mandatory types, overly dynamic, slowness).
  • Never learned enough Haskell to have much of an opinion.
  • Bash and shells in general are not a good model for a general purpose language, and have a lot of awkwardness in their syntax. Very good for interactive one liners though.
  • Sed and Awk are DSLs and work for their purpose. Not really relevant for a general purpose language.

To me it seems that all of these (with the exception of Lisps and Bash) are perfectly reasonable syntaxes with tradeoffs / small warts here and there. In other words, syntax is nothing to get hung up over, it just fades into the background after a while. I think the more interesting distinctions are on higher levels than syntax.

The problem of deref is not that you need to write it, in fact you don't need to write anything, most of the time, which is perfect… when it works. When it doesn't work you are still stuck with *Foo and bazillion parens. Same with ->.

Pascal-style postfix dereference stays readable no matter what.

Sure. Even modern Pascal have quirks. Language readability depends on how it resolves ambiguities very much. Lisp solved that issue with bazillion parens and Forth with ordering of operands. Both work fine for parser, both awful for human.

Pascal solved it by carefully designing grammar to make sure it's easy to parse by both humans and computers. Rust is worse, but I would still prefer turbofish over C++-born abomination like .template operator()<Foo>(bar) any day of the week.

1 Like

I think you missed their point. When auto-deref doesn't work, you can still use .deref(), which is Pascal-style postfix dereferencing.

Is this true? *x is a place expression, but isn't x.deref() a value expression?

And I think you missed mine.

When auto-deref doesn't work (and I need to dereference something manually) 9 times out of 10 it's because I have some kind of pointer which doesn't have Deref implemented for it.

How, pray tell, can I call something that doesn't exist?

That's true, I hadn't considered that. And I suppose it also doesn't give you a value, only another reference.

The only time that's true is with raw pointers (no other type is dereferencable but without Deref), in which case I consider the extra syntax acceptable, perhaps even desirable.

To be clear, I've always wished a little that Rust had more postfix operators, including deref. But I think methods are a good, if somewhat imperfect compromise.

2 Likes

Extra syntax would have been desirable, maybe, hard to read syntax less so. You are dealing with code that's already hard to write correctly, the last thing that you need there is hard to read syntax.

Alas, that ship sailed long ago.

After a quick start with BASIC and assembly, I properly learned with Pascal. It was a great language for learning to program at the time, but I agree with you the syntax was somewhat verbose and rigid. Python's presentation is indeed quite clean, but I suspect that the choices made in Pascal were in part due to the limitation of compilers at the time and the inheritance from ALGOL, which went through a very tortuous design process.

The pointers were a little awkward by today's standards: you defined them with a prefix circumflex accent (or caret):

var next: ^integer;

but you used a postfix notation to access them:

next := @arr[0];       // take the address of the 1st item
next^ := next^ + 1;    // increment item's value
inc(next);             // next item

With records, you could use the alias next->field instead of next^.field, which is sort of visually more expressive but introduced a possible ambiguity of style and some confusion when you learned (which I noticed in a few of my poor classmates :sweat_smile:).

The declaration and the expression are quite symmetrical, so it's elegant, but taking the pointer to a value uses another symbol in prefix position, which seems a little strange.

Rust uses another symmetry in the symbols instead of the position, which I find clearer, while C uses a mirroring in the declaration vs the expression and a symbol symmetry in the expression, so that's well balanced too.

The dereference syntax proposed here, however, is quite confusing and illogical. As for sudo, it loses the proper meaning of unsafe to introduce another one which is incorrect in this context.

That one is easy to explain, though: the very ability to take address was an extension added later, it wasn't part of the original design. It was added many years later and with obvious influence of C, thus it used similar syntax.

Original version of Pascal had not such operator at all, it had the ability to “pass the value by reference”, instead.