You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There has already been many read-only types related proposals.
But I feel they are too complicated to destroy the simplicity of Go.
So here I try to make a simpler one.
I propose to add a type literal modifier, @, which means assignment sign = (The literal choice is not the core of this proposal, it can be designed in a different style.).
A read-only type with a foundation type T can be represented as @T, which means values of @T can only be used as source values and can't be used as destination values.
A value of a read-only type must be bound to (a copy of) of another value.
If it is a variable, the binding happens when it is declared.
This means a read-only value is addressable and can be taken address.
But (the direct part of) a read-only value can never be modified (after the value is declaration).
[update 4]:
A value of type @T can always be assigned to a value of type T, the reason is in the assignment process, a value of type @T is copied to the T value.
A value of type T can be assigned to a value of type @T, but only when the @T value is declared. In other words, values of @T can be implicitly converted to type T, and vice versa. (conversion != assignment)
What prevents a value of a source type from being assigned to a value of a destination type is whether or not the source type has a more restricted base/element type than the destination type.
The read-only in this proposal means that, for example, if the base type of a pointer value is read-only, then compilers will forbid modifying the value referenced by the pointer through the pointer, but the value referenced by the pointer can be modified through other pointers referencing the value, or the value can even be modified directly. Surely, if the type of a value is read-only, then there are no ways to modify the value. It is just that mutable values sometimes can be viewed as read-only values, but read-only values will never be viewed as mutable values.
One example:
varx @int=123varp*@intp=&x*p=789// error: the value referenced by p is immutablefmt.Println(p) // okfmt.Println(*p) // okvarp2*intp2=p// error: type mismatchp=p2// ok
Another example:
varbook= @struct {
pagesinttitlestring
} {
pages: 256,
title: "Go 101",
}
varp=&book// the type of p is *@struct {pages int; title string}varpa=&book.pages// the type of pa is *@intvarpb=&book.string// the type pb is *@stringvar_=*p// okvar_=*p.pages// okbook.pages=300// error: book is an immutable value*pa=300// error: the value referenced by pa is immutable
In fact, @struct {pages int; title string} and @struct {pages @int; title @string} are equivalent. The same, @[N]T and @[N]@T are equivalent.
struct {pages @int; title string} is not a valid type literal.
[N]@T is not a valid type literal.
Strings can be viewed as read-only byte containers.
vars="abc"varp=&s[0] // ok. The type of p is *@byte.fmt.Println(p) // okvar_*byte=p// error: type mismatch
Slices:
varlangs= @[]@string {"C", "Go"}
langs[1] ="C++"// error: elements of langs are immutablelangs=nil// error: langs is immutablevarprimes= @[]int {2, 3, 5}
primes[0] =7// okprimes=nil// error: primes is immutablevarbls= []@bool {false, true}
bls[0] =false// error: elements of bls are immtablebls=nil// okvarss= []string{"abc", "mno", "xyz"}
langs=ss[:2] // okss=langs[:1] // error: type mismatch
The meaning of the @ modifier is a little different for map types.
A value of type map[@K]T means no new keys are allowed to be appended into the map value.
A value of type map[@K]@T means no new enries are allowed to be appended into the map value.
Type map[K]@T is equivalent to type map[@K]@T
For channel types: chan @int and chan int are equivalent. chan <-@int and chan <-int are equivalent. <-chan @int and <-chan int are equivalent. This means when a value is received from a chan <-@int channel, the type of the value can be viewed as either @int or int. But for the deterministic in reflection functions and compatibility, its type should be viewed as int. ([update 2]: For reflection purpose, chan @int and chan int should not be viewed as equivalent types.)
The method set of T is a super set of @T. The method set of *@T is a super set of @T. The method set of *T is a super set of *@T.
In implementations, the proposal needs an extra bit stored in a pointer value to indicate the value referenced by the pointer is immutable. For 64-bit archs, this is not a big problem, but it may be a drawback for 32-bit archs. Besides this drawback, this proposal may cause a small overhead for pointer operations. (no these drawbacks after thinking for awhile, for the read-only info is stored with types instead of values.)
[update 1]
For most scenarios, whether or not the dynamic type of an interface value is read only is not important. But for reflection purpose, making the difference is needed. So the read-only info will be kept in the dynamic type info stored in an interface value.
varx @intvaryintvariinterface{} =x_=i.(int) // panic (or not panic. Either design decision is ok, I think.)_=i.(@int) // oki=y_=i.(int) // ok_=i.(@int) // panic (or not panic. Either design decision is ok, I think.)
[update 2]: see above channel section.
[update 3]
For functions, it is a nonsense to make function results read only. In other words, though syntax doesn't forbid read-only results, but in practice, read-only results are almost totally useless, for their final values will be always zero values. Function results should be always not read only. It is a nonsense to make function parameters and results read only. The reason is arguments and returns of function called are always copied. But if a parameter or a result is of a container (or pointer) type, the read-only info for its element type (or base type) is important.
varf0func([]@int) []@boolvarf1func([]int) []@boolvarf2func([]@int) []boolvarf3func([]int) []boolf0=f1// error: parameter types mismatchf1=f0// okf0=f2// okf2=f0// error: result types mismatchf0=f3// error: parameter types mismatchf3=f0// error: error: result types mismatchf1=f2// okf2=f1// error: both parameter and result types mismatchf1=f3// okf3=f1// error: result types mismatchf2=f3// error: parameter types mismatchf3=f2// ok
For clarity purpose, using read-only parameters and results should be forbidden.
(In fact, read-only parameters and results of a function are not totally non-sense, they are just non-sense for callers of the function. They are still meaningful in the function internal. In other words, in the API docs of a function, none of the parameters and results should present as read-only. Function type func (@T1) @T2 should be equivalent to function type func (T1) T2.)
BTW, in fact, a function declaration can be viewed as a read-only function variable declaration:
funcfoo(T1) T2 {
...
}
is equuvalent to
varfoo= @func(T1) T2 {
...
}
[update 4]: see one of the beginning paragraphs.
The text was updated successfully, but these errors were encountered:
The @ is just syntax, it can be anything else. It has many same points as #22876 and #29192, but it also have many detailed differences from those two.
There has already been many read-only types related proposals.
But I feel they are too complicated to destroy the simplicity of Go.
So here I try to make a simpler one.
I propose to add a type literal modifier,
@
, which meansassignment sign =
(The literal choice is not the core of this proposal, it can be designed in a different style.).A read-only type with a foundation type
T
can be represented as@T
, which means values of@T
can only be used as source values and can't be used as destination values.A value of a read-only type must be bound to (a copy of) of another value.
If it is a variable, the binding happens when it is declared.
This means a read-only value is addressable and can be taken address.
But (the direct part of) a read-only value can never be modified (after the value is declaration).
[update 4]:
A value of type
@T
can always be assigned to a value of typeT
, the reason is in the assignment process, a value of type@T
is copied to theT
value.A value of type
T
can be assigned to a value of type@T
, but only when the@T
value is declared.In other words, values of(conversion != assignment)@T
can be implicitly converted to typeT
, and vice versa.What prevents a value of a source type from being assigned to a value of a destination type is whether or not the source type has a more restricted base/element type than the destination type.
The read-only in this proposal means that, for example, if the base type of a pointer value is read-only, then compilers will forbid modifying the value referenced by the pointer
through the pointer
, but the value referenced by the pointer can be modified through other pointers referencing the value, or the value can even be modified directly. Surely, if the type of a value is read-only, then there are no ways to modify the value. It is just that mutable values sometimes can be viewed as read-only values, but read-only values will never be viewed as mutable values.One example:
Another example:
In fact,
@struct {pages int; title string}
and@struct {pages @int; title @string}
are equivalent. The same,@[N]T
and@[N]@T
are equivalent.struct {pages @int; title string}
is not a valid type literal.[N]@T
is not a valid type literal.Strings can be viewed as read-only
byte
containers.Slices:
The meaning of the
@
modifier is a little different for map types.map[@K]T
means no new keys are allowed to be appended into the map value.map[@K]@T
means no new enries are allowed to be appended into the map value.map[K]@T
is equivalent to typemap[@K]@T
For channel types:
([update 2]: For reflection purpose,chan @int
andchan int
are equivalent.chan <-@int
andchan <-int
are equivalent.<-chan @int
and<-chan int
are equivalent. This means when a value is received from achan <-@int
channel, the type of the value can be viewed as either@int
orint
. But for the deterministic in reflection functions and compatibility, its type should be viewed asint
.chan @int
andchan int
should not be viewed as equivalent types.)The method set of
T
is a super set of@T
. The method set of*@T
is a super set of@T
. The method set of*T
is a super set of*@T
.In implementations, the proposal needs an extra bit stored in a pointer value to indicate the value referenced by the pointer is immutable. For 64-bit archs, this is not a big problem, but it may be a drawback for 32-bit archs. Besides this drawback, this proposal may cause a small overhead for pointer operations.(no these drawbacks after thinking for awhile, for the read-only info is stored with types instead of values.)[update 1]
For most scenarios, whether or not the dynamic type of an interface value is read only is not important. But for reflection purpose, making the difference is needed. So the read-only info will be kept in the dynamic type info stored in an interface value.
[update 2]: see above channel section.
[update 3]
For functions,
it is a nonsense to make function results read only. In other words, though syntax doesn't forbid read-only results, but in practice, read-only results are almost totally useless, for their final values will be always zero values. Function results should be always not read only.It is a nonsense to make function parameters and results read only. The reason is arguments and returns of function called are always copied. But if a parameter or a result is of a container (or pointer) type, the read-only info for its element type (or base type) is important.For clarity purpose, using read-only parameters and results should be forbidden.
(In fact, read-only parameters and results of a function are not totally non-sense, they are just non-sense for callers of the function. They are still meaningful in the function internal. In other words, in the API docs of a function, none of the parameters and results should present as read-only. Function type
func (@T1) @T2
should be equivalent to function typefunc (T1) T2
.)BTW, in fact, a function declaration can be viewed as a read-only function variable declaration:
is equuvalent to
[update 4]: see one of the beginning paragraphs.
The text was updated successfully, but these errors were encountered: