Arrays and Array-Slices...
So I am adding expansion of arrays. Optional.
Arrays:type
PBar = ^TBar;
TBar = record
Data: array[1..4] of integer;
Others: array[1..4] of PBar;
//MorePtr: PBar; // pointer to list of PBar, so MorePtr[0..9] will work
//More: array[1..2, 1..4] of PBar;
Next: PBar;
end;
var
MyBar: PBar;
begin
MyBar := new(PBar); MyBar^ := Default(TBar); with MyBar^ do begin Data[1] := 101; Data[2] := 102; end;
MyBar^.Next := new(PBar); MyBar^.Next^ := Default(TBar); with MyBar^.Next^ do begin Data[1] := 201; Data[2] := 202; end;
MyBar^.Next^.Next := new(PBar); MyBar^.Next^.Next^ := Default(TBar); with MyBar^.Next^.Next^ do begin Data[1] := 301; Data[2] := 302; end;
MyBar^.Others[1] := new(PBar); MyBar^.Others[1]^ := Default(TBar); with MyBar^.Others[1]^ do begin Data[1] := 111; Data[2] := 112; end;
MyBar^.Others[2] := new(PBar); MyBar^.Others[2]^ := Default(TBar); with MyBar^.Others[2]^ do begin Data[1] := 121; Data[2] := 122; end;
MyBar^.Others[3] := new(PBar); MyBar^.Others[3]^ := Default(TBar); with MyBar^.Others[3]^ do begin Data[1] := 131; Data[2] := 132; end;
MyBar^.Others[4] := new(PBar); MyBar^.Others[4]^ := Default(TBar); with MyBar^.Others[4]^ do begin Data[1] := 141; Data[2] := 142; end;
MyBar^.Next^.Others[1] := new(PBar); MyBar^.Next^.Others[1]^ := Default(TBar); with MyBar^.Next^.Others[1]^ do begin Data[1] := 211; Data[2] := 212; end;
MyBar^.Next^.Others[2] := new(PBar); MyBar^.Next^.Others[2]^ := Default(TBar); with MyBar^.Next^.Others[2]^ do begin Data[1] := 221; Data[2] := 222; end;
MyBar^.Next^.Others[3] := new(PBar); MyBar^.Next^.Others[3]^ := Default(TBar); with MyBar^.Next^.Others[3]^ do begin Data[1] := 231; Data[2] := 232; end;
MyBar^.Next^.Others[4] := new(PBar); MyBar^.Next^.Others[4]^ := Default(TBar); with MyBar^.Next^.Others[4]^ do begin Data[1] := 241; Data[2] := 242; end;
//MyBar^.Others[2]^.Others[1] := new(PBar); MyBar^.Others[2]^.Others[1]^ := Default(TBar); with MyBar^.Others[2]^.Others[1]^ do begin Data[1] := 211; Data[2] := 212; end;
//MyBar^.Others[2]^.Others[2] := new(PBar); MyBar^.Others[2]^.Others[2]^ := Default(TBar); with MyBar^.Others[2]^.Others[2]^ do begin Data[1] := 221; Data[2] := 222; end;
:f_(MyBar^, Next, Others)
Would normally return
Len=7: ((Data: (101, 102, 0, 0);Others: ($0000000000117570^: (), $00000000001175B0^: (), $00000000001175F0^: (), $0000000000117630^: ());Next: $00000000001174F0^: ();),
(Data: (201, 202, 0, 0);Others: ($0000000000117670^: (), $00000000001176B0^: (), $00000000001176F0^: (), $0000000000117730^: ());Next: $0000000000117530^: ();),
(Data: (301, 302, 0, 0);Others: (nil, nil, nil, nil);Next: nil;),
nil,
(nil, nil, nil, nil),
($0000000000117670^: (), $00000000001176B0^: (), $00000000001176F0^: (), $0000000000117730^: ()),
($0000000000117570^: (), $00000000001175B0^: (), $00000000001175F0^: (), $0000000000117630^: ()))
Or for "Data"
Len=7: ((Data: (101, 102, 0, 0);Others: ($0000000000117570^: (), $00000000001175B0^: (), $00000000001175F0^: (), $0000000000117630^: ());Next: $00000000001174F0^: ();),
(Data: (201, 202, 0, 0);Others: ($0000000000117670^: (), $00000000001176B0^: (), $00000000001176F0^: (), $0000000000117730^: ());Next: $0000000000117530^: ();),
(Data: (301, 302, 0, 0);Others: (nil, nil, nil, nil);Next: nil;),
nil,
(301, 302, 0, 0),
(201, 202, 0, 0),
(101, 102, 0, 0))
That is, in each case,
when the key returned an array, that array is include "as is".That is certainly good for "Data" (where you likely don't want each of the numbers to become a row of its own in the flatten-result).
For "Others" it depends on the use case.
Like, if you had the keys "Next" and "Previous", then you would only list "Next", because "Previous" should already be in the list.
So you may or may not want to specify the array as
<sort of key>.
You can select individual elements of an array (no ranges/slices => see below)
:f_(MyBar^, Next, Others[2], Others[4])
But if you want all keys, that can be a lot of work, and if the length is dynamic then it wont work that way at all.
So you will be able to do
:f_(MyBar^, Next, Others, [array])
:f_(MyBar^, Next, Others, [array=1])
:f_(MyBar^, Next, Others, [array=2])
The first do are the same. (default is "1").
Expand arrays down to the given nesting depth.
- Depth applies to directly nested arrays: MyBar^.More[1][2] (requires array=2 or higher)
- Depth starts over, if there are objects in between MyBar^.Others[1]^.Others[2] (fine with array=1 because Others[1] did return an object, not a nested array)
Array-slices:Array slices may be handled different...Internally Array slices need different handling anyway. So it comes at no cost to give separate control to the user. That way you could allow to expand slices, but not arrays, and then you could do (if implemented)
:f_(MyBar^, Next, Others[1..4], Data, [slice])
Which would expand "Others", but not "Data".
But then again, there is the
Question: Maybe slices should always be expanded?For that lets have a look how they work, if not expanded. (i.e. currently):
A slice produces an array result, which can be mapped. That is any operation on the array-result is performed on each entry in it.
- foo[1..4].bar => return an array containing only the field bar of each of the 4 (object/record) value from the array foo.
- :lenght(foo[1..4]) => returns an array containing the :length of each of the 4 (hopfully string/array) values from the array foo.
And then:
:_flatten(foo[1..4], Next)returns an array with 4 entries, each entry being one flattened array for each of the 4 value in foo.
But also: :_flatten(MyBar, Others[1..4])returns an array with 4 entries, each entry being one flattened array. The first flattened array is flattened using "Others[1]". The 2nd flattened array is flattened using "Others[2]". The 3rd ...
Question: Does that last example ever really make sense? (And if it does, does it so much that it should be default?)
IHMO, the first example (slice in the first param) could be sometimes useful, but probably in most cases wants to be flattened into ONE flattened result?
But the 2nd example (slice in the key) almost never (if ever) should return 4 results. It should flatten into one list.
Does that make sense? Or am I overlooking use cases?
Based on that, my current idea would be to have all slices inside a ":flatten" being flattened (rather than resulting in multiple separate flattened results).
If such behaviour should be override-able in future (not sure if it will), then there would be 2 ways.
- :flaten(a, b[1..2], c, [noslice])
- :flaten(a, :slice(b[1..2]), c) // wrap the key into an intrinsic that will make the slice not being flattened
Of course, if slices by default will not be flattened, then ":slice()" could mean, for this param include slices into ONE flatten result.
=> In any case, slices will not have a "depth", but be either all one way , or all the other way.
=> They will likely use something like ":slice()" and not "[noslice]". Because the latter has some complications for the implementation.
So some thought, and some fixes later...
It will be a syntax, not an option. It will come down to
1) The current Syntax defaults to multiple flatten, or integrated into one flatten.
2) What syntax? wrapper? :f_( a, :x(next[1..3]) )
The difference in result is, that
** multiple flatten for :f_( a, next[1..3])
returns a NESTED array with the 3 outer entries from the slice,
each holding ONE of the flattens
:f_( a, next[1]),
:f_( a, next[2]),
:f_( a, next[3])
** integrated one flatten for :f_( a, :x(next[1..3])
return on non-nested array
a.next[1],
a.next[1].next[1],
a.next[1].next[1].next[1],
...
a.next[1].next[2],
...
a.next[1].next[3],
...
a.next[2],
a.next[2].next[1],
...
a.next[3],
...
As for amending the syntax of the slice, I don't want to touch the [n..m] part itself.
That part is know by the FpDebug, but also by the IDE. If you have a watch "a[1..3]" in the watches window, and "unfold" it, then the IDE must be able to create the sub-watches; "a[1]", "a[2]", "a[3]"