A Go final values and read-only parameters/results propsoal

674 views
Skip to first unread message

T L

unread,
Feb 27, 2019, 11:54:50 AM2/27/19
to golang-dev
Hi all,

I made a proposal to let Go support final values and read-only parameters/results.

I have posted this proposal at some places to try to get some feedbacks, but unluckily I didn't get many.
So I post it here. Hope someone would give some criticisms and improvement ideas.

Thanks in advance.



Robert Griesemer

unread,
Feb 27, 2019, 4:25:36 PM2/27/19
to T L, golang-dev
Thanks for this post, but as you know we do have an actual proposal process. Better to start with an initial post there.

Also, please keep in mind that proposals that solve an acute and concrete problem in Go will have a much higher chance of success.

Thanks,
- gri

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ian Lance Taylor

unread,
Feb 27, 2019, 4:45:27 PM2/27/19
to Robert Griesemer, T L, golang-dev
On Wed, Feb 27, 2019 at 1:25 PM Robert Griesemer <g...@golang.org> wrote:
>
> Thanks for this post, but as you know we do have an actual proposal process. Better to start with an initial post there.
>
> Also, please keep in mind that proposals that solve an acute and concrete problem in Go will have a much higher chance of success.

This is based on https://golang.org/issue/29422. We recently closed
that issue, in part because it was very long, and I commented that it
would be helpful to produce a finalized version of the proposal and
then open a new issue for it. This e-mail was, I assume, an attempt
to finalize the proposal.

Ian

Ian Lance Taylor

unread,
Feb 27, 2019, 6:40:11 PM2/27/19
to T L, golang-dev
On Wed, Feb 27, 2019 at 8:54 AM T L <tapi...@gmail.com> wrote:
>
Personally, I don't like the notation T.fixed. I find it confusing
that ".fixed" can be used as a suffix on both types and expressions.
For a complex expression or type literal it's hard to understand
exactl what the ".fixed" applies to.

As far as I can tell "final" only applies to variables, so it seems
quite similar to "const" in https://golang.org/issue/6386. Since we
already have "const", I don't see the advantage of adding a new
keyword "final".

"fixed" is a type qualifier, which brings various disadvantages. It
leads to const-poisoning, only in this case it is fixed-poisoning, in
that "fixed" winds up scattered across the program, and then when you
discover that you have to modify a field you have to remove it out
everywhere. If a normal slice is assigned to a fixed slice, then the
underlying array can be modified using the normal slice, so a fixed
slice does not guarantee immutability.

Those are my first impressions of the current version.

Ian

T L

unread,
Feb 28, 2019, 12:36:48 AM2/28/19
to golang-dev


On Wednesday, February 27, 2019 at 6:40:11 PM UTC-5, Ian Lance Taylor wrote:
On Wed, Feb 27, 2019 at 8:54 AM T L <tapi...@gmail.com> wrote:
>
> I made a proposal to let Go support final values and read-only parameters/results.
> https://github.com/go101/immutable-value-proposal
>
> I have posted this proposal at some places to try to get some feedbacks, but unluckily I didn't get many.
> So I post it here. Hope someone would give some criticisms and improvement ideas.

Personally, I don't like the notation T.fixed.  I find it confusing
that ".fixed" can be used as a suffix on both types and expressions.
For a complex expression or type literal it's hard to understand
exactl what the ".fixed" applies to.

The ".fixed" notation looks really some weird at the beginning.
But I think it is an acceptable design.
It is best design for it I have found up to now.
Surely, it would be better if an alternative better design will be found.

The ".fixed" suffixes are always the last part of a type literal.
For example, "[]*T.fixed" always means "([]*T).fixed".
"[]*(T.fixed)" and "[](*T.fixed)" are both invalid interpretation.
The interpretation rule is the same for expressions.

 

As far as I can tell "final" only applies to variables, so it seems
quite similar to "const" in https://golang.org/issue/6386.  Since we
already have "const", I don't see the advantage of adding a new
keyword "final".



No, finals are not variables. Finals are the opposites of variables.
A value is either a variable or a final.
Currently, there are already some final values in Go, including declared function/method
values and all kinds of intermediate results, such as function returns,
operator operation evaluation results, explicit value conversion results, etc.

Maybe it is ok to view constants as a subset of finals.

I would admit this proposal is a combination of the proposals
This proposal provides an organic solution to compromise the two.

The current descriptions of the "about final, fixed, and immutable values"
section of this proposal is still not perfect. I will update it in a few hours as
the following shows

    "variable/final" and "normal/fixed" are two properties of a value,
    they corresponds "self_modifiable" and "ref_modifiable".
   
    A value is either a variable or a final.
    A value is either fixed or normal.

    Please note, although a value can't be modified through fixed values
    which are referencing it, it is possible to be modified through other
    normal values which are referencing it. From the view of a fixed
    value, all values referenced by it are final and fixed values.
   
    A fixed value itself may be modifiable it is not a final.
    Values referenced by a final may be modifiable if the final is not fixed.

    Data synchronizations might be still needed when concurrently reading
    a final value. But if the final value isn't referenced by any normal value,
    then concurrently reading it doesn't need data synchronization.
    In particular, all declared finals satisfy this requirement.

 
"fixed" is a type qualifier, which brings various disadvantages.  It
leads to const-poisoning, only in this case it is fixed-poisoning, in
that "fixed" winds up scattered across the program, and then when you
discover that you have to modify a field you have to remove it out
everywhere.  If a normal slice is assigned to a fixed slice, then the
underlying array can be modified using the normal slice, so a fixed
slice does not guarantee immutability.

Yes, the two points are both true.
For the second point, I would say this is more a feature than a problem.
And in fact, this proposal really support some true immutable values.
As above has mentioned, a final values without being referenced by
any normal values is a true immutable value. For example,
if we declared a variable as "var v = []int{1, 2, 3}.fixed", then the
elements of v are immutable. There are not (safe) ways to modify them.

For the fixed-poisoning problem, it is really hard to avoid.
The main intention of the fixed value concept is to support
read-only parameters and result. By change the parameters
of a function to fixed, the corresponding parameters of all other functions
called by this functionand passed with the fixed input parameter as arguments
also need to be changed to fixed.

However we can introducing fixed parameters eventually
(if this proposal is proved to be good). For example, we can firstly
modify the prototype of fmt.Print function as func (...interface{}.fixed).
No user code needs to be modified. It is just the parameter types of
several functions in the standard packages are needed to be changed.

BTW, this proposal really has a problem, it may cause "bytes.TrimXXX"
function to be split into several versions for normal and fixed arguments.
This needs the generics feature to be fixed.
So this proposal depends on the future generics feature to fully work.

T L

unread,
Feb 28, 2019, 9:35:58 AM2/28/19
to golang-dev


On Wednesday, February 27, 2019 at 5:25:36 PM UTC-4, gri wrote:
Thanks for this post, but as you know we do have an actual proposal process. Better to start with an initial post there.

Also, please keep in mind that proposals that solve an acute and concrete problem in Go will have a much higher chance of success.

Russ's doc: evaluation of read-only slices mentions some inefficiencies caused by lacking of read-only parameters/values.

I heard of some complaints about lacking of immutable package-level exported values from some forum threads.
But I can't find them back now.

And some immutable/read-only requests from Go issues:
 
It is hard to say the lacking of immutable/read-only values problem is acute,
but I think it is also hard to neglect it.
And immutable/read-only values can bring some benefits to Go:
* better doc imply by code
* better performance
* better security. (There are many levels of security. Package-level variable
  in std packages modified by malware 3rd party package may be not a
  high-level security problem, but it would be better to avoid some behavior
  from syntax level.)

T L

unread,
Mar 1, 2019, 2:35:13 PM3/1/19
to golang-dev
I add the last design part to allow partial read-only struct values.
A new notation "T.mutable" is added.
The notation can only be used to specify types for non-exported struct fields.
I'm not happy with this design now, it is just to make the proposal complete.

@Ian Lance Taylor
Would the notation "T:fixed" or "T::fixed" be better than "T.fixed", do you think?

Ian Lance Taylor

unread,
Mar 1, 2019, 4:48:14 PM3/1/19
to T L, golang-dev
There is nothing in Go that works anything like "T.fixed" or "T:fixed"
or "T::fixed". If we're going to add an entirely new concept to the
language, it needs to fit cleanly with the rest of the language. I
don't think using a suffix as a type qualifier is a clean fit.

Ian

T L

unread,
Mar 1, 2019, 10:55:54 PM3/1/19
to golang-dev
I understand.

The intention of such a "T.fixed" design is to let function prototypes look not discrete.
I think "func (T.fixed) S.fixed" is much better than "func (ro T) (ro S)".
Surely, it would be great if there are better alternatives.

T L

unread,
Mar 8, 2019, 12:15:38 PM3/8/19
to golang-dev
The v8 version is released.

In this version:
* partial read-only is removed, for it brings many complexities and causes
  some design flaws. Maybe partial read-only is an abnormal need.
* final values are changed to constants, and declared with "const".
  Constants (themselves) are always immutable values.
* fixed values are renamed to reader values.
  "Reader/writer" are called value roles now.
* support role parameters to avoid function declaration duplications.
* propose a way to indicate immutable byte slices at run time.

Now, the proposal becomes Go 1 compatible.

T L

unread,
Apr 15, 2019, 8:37:31 AM4/15/19
to golang-dev
I plan to re-open an issue for this proposal.
The new version v9 discards the partial read-only feature.

robert engels

unread,
Apr 16, 2019, 2:29:47 AM4/16/19
to T L, golan...@googlegroups.com
One comment, the syntax of using both final and :reader is annoying, and I believe unnecessary.

You can use final in both places, ie:

final var x int // x is final

var x final []int // x is a slice with final elements

final var x final []int // x is final and references a slice with final elements

with the latter marking two the elements as being final.

Or something similar - the idea being that the proposed syntax isn’t very Go like….

T L

unread,
Apr 16, 2019, 8:49:22 AM4/16/19
to golan...@googlegroups.com
Yes, there is much room to improve the syntax of this proposal.

The main intention of the ":reader" tail is to avoid there are too many token in function parameter and result list.
For example, I think

func (param1 Ta:reader) (result1 Tx:reader)

has a better readability than

func (param1 final Ta)(result1 final Tx)

And "final" indicates immutability, but some reader and read-only values are not immutable at all.

Another amusing point is the ":reader" value tail and "reader." method head can be merged together.

One drawback of the ":reader" tail is it is a little long.
Maybe it can be shortened as ":r",
and we can require role parameter names must be integers, such as "::1",
to avoid some function prototypes become too long.

Manlio Perillo

unread,
Apr 16, 2019, 10:53:49 AM4/16/19
to golang-dev

On Monday, April 15, 2019 at 2:37:31 PM UTC+2, T L wrote:
I plan to re-open an issue for this proposal.
The new version v9 discards the partial read-only feature.



The paper use the names isolated, immutable, readable and writeable.

What about adding the qualification at the end, e.g.
var x int immutable

Placing it at the end does not require immutable to be a keyword.
In alternative:
var x int(immutable) 

with a syntax similar to the one proposed for generics.


Regards
Manlio
 

T L

unread,
Apr 17, 2019, 2:59:50 AM4/17/19
to golang-dev
I was not aware of the two. This current proposal is evolved from the old proposal.

The pdf says "objects may not be mutated via a read-only reference, and field reads from
read-only references produce read-only references"
This is really the same as the read-only concept in this proposal.
The difference is that this proposal differentiates "reader values" from "read-only values".
A reader value might be not read-only.

About the syntax, I think the "v:reader" and "T:reader" notations look much less discrete,
which is better for readability.
Reply all
Reply to author
Forward
0 new messages