Ada-Rapporteur-Group / User-Community-Input

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

delta aggregate with array slices #113

Open evanescente-ondine opened 1 week ago

evanescente-ondine commented 1 week ago

(Version 2): Several times I've found myself in an expression wanting to update an array with part of an another array. But the only way I found was creating a new object by iterating over one object.

pragma Extensions_Allowed (all);
procedure Test2 is
    type ATT is array (Positive range 1..<>) of Integer;
    FirstObject: ATT := [for I in 1..22 => 1];
    SecondObject: ATT := [2,3,4,9];
begin
-- proposition 1
    FirstObject := (@ with delta (for I in 4..6 => SecondoObject(I-3)));
-- proposition 2
    FirstObject := (@ with delta @[4..6] => Secondobject(1..3));
end Test2;

My proposal is at least to allow for iterated component associations as an object of Δ-expressions. That would avoid the tedious computations of ranges that come with concatenating arrays. Now the only way to update (part of) an array with (part of) another in situ, are slices:

FirstObject(4..6) := SecondObject(1..3);

I want to bring that very natural construct, into expressions. Proposition 1 is illegal because Δ-expressions only take array component associations. It's the closest to what exists. But proposition 2 would mirror more directly slices assignment and would not imply or involve iterating over the array.

ARG-Editor commented 1 week ago

Ummm, I'm not sure what you're trying to do here.

ThirdObject := [for A of FirstObject => A] & SecondObject;

This is the same as: ThirdObject := FirstObject & SecondObject; so you must have meant something else. I don't want to guess what.

Randy.
ARG-Editor commented 1 week ago

Probably should have said more.

Several times I've found myself in an expression wanting to update an array with part of an another array.

That's precisely the purpose of a delta aggregate. Why doesn't it work for you?

ThirdObject := FirstObject with delta (1..3) => SecondObject;

There's no aggregate here (that would require some brackets enclosing at least the keywords), and I have no idea what this is supposed to do.

evanescente-ondine commented 1 week ago

I updated it. Hope it's clearer this time around.

ARG-Editor commented 1 week ago

Thanks.

It seems to me that you want a new kind of aggregate choice that allows an object of the same array type, presumably with a range for the choice. Otherwise, it would work the same as any similar array aggregate choice. Indeed, the choice itself isn't different (we already allow ranges in choices), only the resolution/meaning of the expression is. We would want whatever we do to work in both array and array delta aggregates, and probably also in indexed container aggregates.

I don't much like the idea of messing up the choice syntax, since it isn't the choice that really is getting changed. My idea would be to use the underused "array" keyword to mark that the expression is an array rather than an individual component. For your example, that would look like: FirstObject := (@ with delta 4..6 => array Secondobject(1..3)); You could use that in a regular array aggregate as well: FirstObject := (4..6 => array Secondobject(1..3), 1 => 2, others => 10);

We'd probably want to restrict the choice_list to a single item (not others, of course), and the array object would have to match the length of the choice (that would be a runtime check in general, since the array object could be a slice with dynamic bounds, and the choice itself could be dynamic in some cases). The array object would have to be of the same type as the aggregate as a whole, so the components would necessarily have the right subtype. As you noted, the bounds of the array object would slide as needed.

I think we need a keyword or some other syntax to mark this change, as we are changing the meaning (especially the resolution) drastically. For these "array" choices, the expression is evaluated only once, while in the usual case they are evaluated once per component. Knowing the ARG, there could be quite a number of syntax suggestions.

This does seem to make aggregates more useful in some cases, and I can't think of any semantic problems with the idea. It would probably be easier to implement than Issue #105 (it would be limited to the one part of aggregate evaluation that I was able to figure out how to share!). Probably someone should write up a formal proposal.

evanescente-ondine commented 1 week ago

FirstObject := (@ with delta 4..6 => array Secondobject(1..3)); FirstObject := (4..6 => array Secondobject(1..3), 1 => 2, others => 10);

Yes ! Yes !!! Exactly what I meant. The compiler would detect if the expression i static, and if it is, do away with runtime checks. To me the issue with ICAs, is that they can break apart objects meant to remain units. They only make sense when creating new collections from indexes. I can imagine some overhead for arbitrarily complicated components and large arrays/containers.

Probably also in indexed container aggregates.

I always wanted a user-defined slicing, to align containers' semantics on arrays. Some want a Slice operation, but what I mean is MyContainer(1..4). With this the proposal here would work as well. But you meant something else I assume.