For flexibility as I said, people would have the choice of the spot for mut
place. Actually mut is allowed in expression but in the form of &mut
. My proposal would be parallel to that.
&mut
in an expression is quite different from mut
in a pattern. &mut
creates a exclusive reference, and mut
allows a binding to be changed. Theyâre only analogous in the sense that they allow changes to happen, but it doesnât go much farther than that. They allow totally different kinds of changes.
Basically adding syntax to the language itself is expense, not income, though it often(usually?) can be justified by being more usable/idiomatic/expresive/etc. So âmore flexibleâ canât be a reason to add a syntax to the language. At least, itâs not an enough basis to persuade people in this forum.
Iâm just proposing to allow place flexibility of
mut
.
...okay. To be honest, at this point I'm still not even sure what you're suggesting. On the one hand you're saying that you're "just allowing mut
to appear in more places." On the other hand, it looks like you're trying to introduce some concept of a "mut
Type" or something. (at least, that would seem to be the level of complexity needed just to make even the simplest edge cases work)
There's no point in arguing when I don't even understand what I'm arguing against. So please help us understand your proposal. Here's a bunch of simple yes/no questions. Please answer them according to how your proposal is intended to work.
// 1a. Is this valid syntax?
// 1b. If so, is y mutable?
let (x, y) = (3, mut 3);
// 2. Does this compile?
let tuple = (3, mut 3);
// 3a. Does this compile?
// 3b. If so, are x and y mutable?
let (x, y) = mut (3, 3);
// 4a. Is this valid syntax?
// 4b. Is y mutable?
let f = |x| x;
let y = f(mut 2);
// 5a. Is this valid syntax?
// 5b. If so, is y mutable?
let f = |x| mut x;
let y = f(2);
// 6. Is y mutable?
let x = mut 3;
let y = x;
Edit: removed question 7.
With this and the several other similar threads youâve opened: What problem are you trying to solve?
Rust, as a language, is very amenable to proposals for potential language improvements. However, someone making such a proposal needs to explain the problem theyâre trying to solve, and why the existing language doesnât solve the problem (or doesnât do so effectively enough).
In doing so, such a proposal should also demonstrate a clear understanding of how the language already works, at least in the area in question, in order to motivate a change to how it works.
Many syntax proposals, for instance, get pushback of the form âyou could do this with a macroâ, and itâs up to the proposer to explain why that doesnât suffice.
In the case of this and several other proposals youâve made recently, there seems to be an underlying theme of some kind of frustration youâre having, perhaps between the Rust language and the way youâre trying to use it, along with (intentional) differences in behavior between Rust and other programming languages. Thatâs fairly normal, especially when learning the language. However, rather than making an array of proposals for how Rust could behave differently, you might consider seeking some help with the difficulties youâre encountering with Rust and with potential solutions or mental models that might make your path easier. For instance, you might try Rustâs friendly IRC channels.
I donât have any problems, I am just suggesting proposals that could lead rust better and easier as well as being more wide spread in programming world. I would like people to use rust for example instead of go. Thatâs what Iâm trying to achieve.
Not "somebody".
@medozs I'm not sure why you expected people to like this proposal when they didn't like var
. But, really, it has the same problem; it doesn't fit with the way Rust's pattern-matching system works, and it doesn't seem to improve things. It doesn't even make the code shorter! At least var
had that going for it.
Do you have any evidence that micro-scale syntax flexibility actually does make programming languages more successful? Because I think the widespread success of Python is evidence that it's not required.
No, there arenât any new types. Itâs just equivalent to let mut a = value
but with mut
is moved to expression. The behavior stays the same.
// 1a. Is this valid syntax? // 1b. If so, is y mutable? let (x, y) = (3, mut 3);
a. Yes, b. Yes
// 2. Does this compile? let tuple = (3, mut 3);
A. Yes
// 3a. Does this compile? // 3b. If so, are x and y mutable? let (x, y) = mut (3, 3);
a. Yes, b. Yes
// 4a. Is this valid syntax? // 4b. Is y mutable? let f = |x| x; let y = f(mut 2);
a. No, b. No
// 5a. Is this valid syntax? // 5b. If so, is y mutable? let f = |x| mut x; let y = f(2);
a. No, b. No
// 6. Is y mutable? let x = mut 3; let y = x;
A. No
Me and others here in this forum are just making suggestions and ideas, itâs up to you guys concerned to evaluate and discuss such proposals.
(As a quick aside: the use of &
in patterns is in fact the right choice, because patterns arenât operators, but they are constructs that mimic the structure / type of the values they are matching. Therefore, if reference types are spelled &T
, and references are obtained using &value
, then reference patterns should also be spelled &inner_pattern
. Itâs similar in principle to how you write Some(inner_value)
in a pattern, instead of using is_some()
and unwrap()
, hopefully.
Patterns destructure values (as opposed to composing them), so if you are thinking in terms of operators, it might often seem they work âbackwardsâ. However, thatâs just a result of their nature: they are more or less duals, in a Haskellian sense, to value and type constructors such as enum variants and references.)
To be more specific, this means the syntax âshould have beenâ this:
let a = &Some(1);
match a {
&Some(*x) => {}
}
That is, exactly as it is today, with &
-in-expressions and &
-in-patterns having opposite meanings, but with ref
replaced with *
.
(I suspect one reason we didnât get that is that it would lead to things like *mut x
, which looks an awful lot like a raw pointer type. Itâs also just kind of confusing because neither &
nor *
are quite value constructors the way Some
is.)
neither
&
nor*
are quite value constructors the way Some is.
That's true, however type-level &
is a type constructor, a function from a type to a type. For all types T
, there is a corresponding reference type &T
. This doesn't work with dereferencing, though: there's no type-level *
. Don't be confused by the same syntax of type-level &
and value-level &
, they are very different beasts! I was talking about the type-level constructs only.
Incidentally, this is why I don't think *
in patterns would have been a good idea. It doesn't match the structure of an expression, because it simply can't â given the lack of a type-level *
operation.
Not quite the same. If you had 'destructuring' *
, the meaning of mut
would have to be different, since *
would be a structural element rather than a binding modifier. Right now, if you wanted a mutable-binding-of-reference-to-the-slot, you would write mut ref x
, which makes the binding ref x
mutable. However, if you wrote mut *x
, the mut
would no longer be applying to the binding, it would apply to the slot corresponding to *x
, making mut *x
equivalent to ref mut x
. To get a mutable binding, mut
would have to be applied directly to the binding, like *mut x
. With a ref
binding modifier, the meaning of incantations involving both ref
and mut
are essentially arbitrary, and I guess it made sense not to force people to read them inside out the way you do with structural pattern elements. After all, you're constructing a binding rather than deconstructing a value at that stage.
Just because I didn't quite take your meaning immediately, the type level operation corresponding to Some(_)
is Option<_>
. At first I thought you meant that the type-level operation has to have the same syntax as the value operation, which of course doesn't work in general. That it happens to line up for &
is the exception rather than the rule, which is what threw me off when I first read your comment.
Of course, you could create a type-level operation:
type Dereffed<T> = <T as Deref>::Target;
But yeah, if we limit ourselves to canonical types rather than arbitrary aliases, then it's very clear that &
adds structure while *
removes it. If you think of patterns as destructuring, then reversing *
is undestructuring. Thus, it doesn't fit with everything else (though it does have a clear meaning in the more general logic of matching: matching *x
to y
makes x = &y
).
Yeah, sorry, I should probably have been more clear about that. (Also, re-reading my own comment, I see I did mention value-level &
, I shouldnât have brought it up probably.) Yes, there certainly is a correspondence between *
and destructuring, as you wrote.
Itâs not so much what you wrote, itâs that my brain took a wrong turn while reading it, so I figured Iâd share my experience with the class
Comparison between &mut
and mut
&mut
placement:
- Can come as let pattern:
let ref mut a = ..
- Can come as type pattern:
..:&mut ..
- Can come as value expression:
..=&mut ..
mut
placement:
- Can come as let pattern:
let mut a = ..
- Can come as type pattern:
?
- Can come as value expression:
?
ref mut
in patterns is not the same a &mut
. In fact, theyâre opposites.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.