Ada-Rapporteur-Group / User-Community-Input

Ada User Community Input Working Group - Github Mirror Prototype
27 stars 1 forks source link

Explicitly constant return types #27

Open Richard-Wai opened 1 year ago

Richard-Wai commented 1 year ago

In some circumstances involving the return of composite types, it might be useful to exert more control over the use or modification of the returned object, beyond what the limited view can provide.

Problem:

One immediate example is a user-defined ADT (abstract data type), with a tree-like structure where nodes can themselves be tree-like structures of a different type.

Consider a root ADT type that has user-defined indexing that can potentially return another sub-tree type that also has user-defined indexing. If we have a constant view of a root ADT object, but we index to a sub-tree object, we will want the view of that returned object to be constant as well. Defining two distinct sub-tree types for each case is difficult because they cannot inherit from eachother due to the need to confirm the indexing aspects (since Ada 2022). This means that the returned sub-tree object would likely need to have Variable_Indexing defined, which would make what is supposed to be an immutable view of an ADT potentially partially mutable.

I suspect there might be other contexts where we want to return an object with immutability guarantees beyond this ADT example.

Proposal:

For functions returning a composite type, allow the optional provision of the constant keyword following the optional [aliased] keyword. Ergo,

In 6.1-12/2, we would change parameter_and_result_profile to be as follows:

parameter_and_result_profile ::= [formal_part] return [null_exclusion | constant] subtype_mark | [formal_part] return access_definition

The legality rules would require that subtype_mark denotes any composite type.

The static semantics would require that the target of such a function either be a constant object declaration, or an in-mode parameter, or the subject of a 'Access that is being assigned to an access to constant object or parameter.

Note that we would not need to modify rules around extended returns as we want the view of the returned object inside of the function to be potentially mutable.

This way we can have in the contract of a function retuning a composite object that the returned object shall remain immutable for its lifetime.

sttaft commented 1 year ago

I presume this is only relevant for limited, build-in-place types. For non-limited types, it seems pointless to prevent an update to the returned object, unless I am missing something. Also, when you mentioned the "aliased" keyword, I suspect you meant a null exclusion, though those only apply to non-composite (access) types, so it seems unlikely both would apply. Your BNF reflected this view, so it was only your English text which seemed a bit confused.

As far as an "aliased" keyword on a return statement, I was about to write up an issue for what that would mean, so perhaps you anticipated that! ;-)

Richard-Wai commented 1 year ago

Indeed it would apply to any composite type. The point is exactly that you want to enforce a contract with the user of a function that they cannot modify the returned object. I.e. you are forcing the user to assign the result to the declaration of a constant.

For example, I might want to provide a function that takes only an in of A'Class, and return an object of B'Class, where that B'Class object should remain read-only.

Again the idea here is that if you said "return constant B'Class" then you are only allowed to use it in an assignment to a constant, or to an in-mode parameter.