On 05/09/2021 12:31, James Harris wrote:
On 04/09/2021 18:04, Bart wrote:
On 04/09/2021 16:56, James Harris wrote:
...
For example, if s is a string then
f(s)
would pass the string's address and length
...
Both caller and callee would see s as a single object unless they
chose to break down the tuple with such as
s._ptr
s._len
Those string examples pretty much match Slices in my language.
That makes sense. It was largely because of slices that the issue arose.
I was looking into how to support potential copy-in, copy-out for arrays
(or parts thereof) so a pointer to the first element (as in C) would not
be enough. Length would also be required.
And that's handy because as you showed in your example code the pair (location, length) also works well as a slice, and a slice can be easy
for a programmer to append - e.g. with the [...] in
s[5..7]
So a slice would be a subarray which could also be considered to be an
array in its own right.
I should say that passing arrays as (location, length) and having the potential for copy-in, copy-out does not mean that arrays would always literally be copied. Such arrays or slices could often be passed by reference. However, the potential for copying would be there and the
callee would additionally be informed of the array length.
I should say that a slice is an explcit user-declated type in my language.
Regular arrays can be passed, nominally by value (it's normally done
with pointers) but they are fixed size so caller and callee both know
the length.
The language doesn't have a built-in way of representing dynamic arrays;
slices were one alternative to passing separate pointers and lengths.
(The dynamic language handles those of course, but by fairly heavyweight descriptors.)
It's a feature I haven't really used, so it's partly fallen into
disuse, but the following example works (s as a 'char* instead of
char[] doesn't work):
proc testfn(slice[]char s)=
println s, s.len, ref void(s.sliceptr)
end
proc start=
static []char s=z"one two three"
testfn("hello")
testfn(s)
testfn(s[5..7])
end
Do you allow the callee to modify s.len or even s.sliceptr and can a
callee /return/ a slice?
I don't think I allow that. But you can extract those components, modify
them and construct a new slice. To change the caller's copy of slice, it
needs to be a reference parameter to an actual slice object (not a
constructed one).
I think you said somewhere that you return a 2-tuple in two registers
but I cannot find that comment ATM.
They use the same handling as 128-bit numbers. A 64-bit value is
returned in register D0 (rax), and 128-bit ones in registers D1:D0
(don't know what D1 is in Intel terms, but it'll be one of the volatile
ones).
This program:
function fn(string s,t)string u= # string defined below
return u
end
proc start=
string a,b,c
c:=fn(a,b)
end
Generates this ASM (note that my register optimiser will only put or
keep 64-bit variables in registers; 128-bit ones are a little too
rarified for that):
t.fn:
fn.s = 16
fn.t = 32
fn.u = -16
push Dframe
mov Dframe, Dstack
sub Dstack, 16
mov [Dframe+16], D10
mov [Dframe+24], D11
mov [Dframe+32], D12
mov [Dframe+40], D13 ;-------------------------------------------------
mov D0, [Dframe+fn.u]
mov D1, [Dframe+fn.u+8] ;-------------------------------------------------
add Dstack, 16
pop Dframe
ret
t.start:
....
mov D10, [Dframe+start.a]
mov D11, [Dframe+start.a+8]
mov D12, [Dframe+start.b]
mov D13, [Dframe+start.b+8]
call t.fn
mov [Dframe+start.c], D0
mov [Dframe+start.c+8], D1
....
If slices can be returned should
they be new objects or should they be restricted to referring to parts
of existing objects?
Since slices are an explicit type of fixed size (16 bytes) they are
passed and returned by value:
type string = slice[]char # save some typing
function widen(string s)string t=
t:=(s.sliceptr, s.len+1)
return t
end
proc start=
string a:=("ABCDEFGH",3)
println a
println widen(a)
end
This displays ABC then ABCD. It's up to your code to ensure the string
they point to still exists.
I could have used:
string a:="ABC"
too (it will treat that as a:=("ABC", 3)) but my widening example
wouldn't have worked too well! Here's another way of returning a slice:
function left3(string s)string t=
return s[1..3]
end
This could be called as left3("ABCDEFGHI"), and returns "ABC" as a
slice. A bit too trivial though, as you can just do "ABCDEFGHI"[1..3].
A returned slice value could refer to an existing string or slice or
slice of slice etc, but it can refer to a newly allocated string.
At level I implement this, user-code needs to keep track of that.
(My 2-element slices can be used for allocated arrays that do not change
in size. Arrays that grow are more challenging. It could be done by
splitting the 64-bit length into a 32-bit length, and 32-capacity, but
then it also needs language support to check accesses are within bounds,
and to grow the arrays as needed.
A bit like the C++ vector type, but that uses a 196-bit descriptor,
which really needs handling by reference. But I decided that was a
little beyond the remit of my static language.)
The first two calls to testfn automatically turn the array (which has
a known size, probably why char* didn't work) into a slice object.
I guess char* does not and can not know the length.
It could assume a terminated string (when there are separate char and u8 types), and call strlen to determine the length for the slice.
Thinking out loud, as it were, are there logically at least two string
types in common use in programming: one dynamic and of variable-length,
the other an array of char where for some operations the array size is
fixed at or by run time?
Yes, there's three (at least):
* Fixed at compile-time
* Set at runtime, but fixed size, once allocated
* Set at runtime, and the size can change
Fixed ones including declarations like this:
[100]int A
[50]int B
Here, either A or B can be passed to a function taking a slice[]int
parameter.
Fixed ones also include short strings forming their own type; I mainly
used these for struct member types.
A callee which expected a read-only argument to be an array of char
could probably accept either type of string and it might be clearer how
a function was going to use a string for it to be declared as array of
char rather than a string of char.
Many options!
Yeah, too many.
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)