www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1869] New: Semantically returning an array from a funciton is difficult

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869

           Summary: Semantically returning an array from a funciton is
                    difficult
           Product: D
           Version: 1.026
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Keywords: spec
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: jason spashett.com


It is difficult to 'return' an array from a function. Static arrays cannot be
returned, presumably because arrays are akin to full class objects. This
sometimes  is a bit inconvenient when, for example one would like to assign to
a static array by calling a function. 

In contrast structs can be returned from a function easily, and in fact to
return an array one can wrap it in a struct. Other ways may include the use of
boxing, or returning a dynamic array, which becomes more complicated if it is
multi-dimensional. 

Currently this method seems the best solution, but requires a persistent object
allocation as opposed to using the stack (as in structs presumably):

/* Assume matrix is a class member, or static */
float[4][4] * toFloatArray4x4()
{
        return &matrix;
}

float v[4][4] = *m1.toFloatArray4x4();

Obviously arrays can also be passed in as parameters, but this denies one the
functional return like semantic which can often be useful.


-- 
Feb 25 2008
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #1 from shro8822 vandals.uidaho.edu  2008-02-25 15:46 -------
The reason that static arrays can't be returned is that they are pointers to
local variables. That is in reference to this code:
int[10] a;
return a;

however IIRC you can have a function return type int[4]:
int[4] fn(int i, int[4][4] j) { return j[i]; }

I guess I'm not realy understanding what your concern is. --
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #2 from jason spashett.com  2008-02-25 17:03 -------
(In reply to comment #1)
 The reason that static arrays can't be returned is that they are pointers to
 local variables. That is in reference to this code:
int[10] a;
return a;

however IIRC you can have a function return type int[4]:
int[4] fn(int i, int[4][4] j) { return j[i]; }

I guess I'm not realy understanding what your concern is.

Is this new in D 2.x ? I get main.d(813): Error: functions cannot return static array int[4u] with your example. My example is for a two dimensional array, which up until fairly recently was hard to initialise from a static array (until recently dmd 2.0 changelog) Is it the case therefore that dmd 2.x supports returning of static arrays? --
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #3 from shro8822 vandals.uidaho.edu  2008-02-25 17:21 -------
Hm. I'm almost sure I've done that before. And no, I use 1.0.

If my examples don't work, I think it should be considered a bug (in the design
if not the implementation).

On seconds though, you point out that a struct can be returned. This will
actually be done by value (returning a struct with an int[4] inside will copy
4*int.sizeof bytes) D might be interpreting returning int[4] in that way and
refusing (that could get real nasty with some template code computing n=1e6 or
some such).

If that is the case, why does it treat it as values on return and as references
on pass?


-- 
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #4 from jason spashett.com  2008-02-25 17:47 -------
(In reply to comment #3)
 Hm. I'm almost sure I've done that before. And no, I use 1.0.
 
 If my examples don't work, I think it should be considered a bug (in the design
 if not the implementation).
 
 On seconds though, you point out that a struct can be returned. This will
 actually be done by value (returning a struct with an int[4] inside will copy
 4*int.sizeof bytes) D might be interpreting returning int[4] in that way and
 refusing (that could get real nasty with some template code computing n=1e6 or
 some such).
 
 If that is the case, why does it treat it as values on return and as references
 on pass?
 

D is a bit like java and c# in that small intrinsic items like ints, floats are passed by value, the same is true of stucts. It's a trade off between efficiency and pass by value semantics I guess. An array, and a class are considered largeish things and so it's assumed you will want them to go 'though' by reference. In fact you can't pass an array by value even if you use the "in" keyword. In a way arrays work similarly in C and C++ except in those languages they are pointers and loose type information when you pass them in. The problem in D I seem to be encountering is that there is no nice, or convenient way of returning an array (the problem gets worse with multi dimensional arrays because you have to set them up and until recently in dmd 2.0 you couldn't initialize them in one go AFIK) I don't have to return an array, but it makes what I am trying to do a bit more clumsy. For example I can't pass into (OpenGL) glMatrixMultiply an array of float[16] by simply calling matrix.toFloat16() I must use a temporary variable, which is a slight pain. Or; I can use my 'pointer workaround' which is bit of a hack. --
Feb 25 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #5 from shro8822 vandals.uidaho.edu  2008-02-25 18:06 -------
That's about like I remembered.

If you don't mind the cast...

int* foo(int[4][4] j, int i) { return &(j[i]); }
cast(int[4])foo(a,i);


-- 
Feb 25 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=1869
 
 
 
 
 
 ------- Comment #5 from shro8822 vandals.uidaho.edu  2008-02-25 18:06 -------
 That's about like I remembered.
 
 If you don't mind the cast...
 
 int* foo(int[4][4] j, int i) { return &(j[i]); }
 cast(int[4])foo(a,i);

A cast is _never_ a viable solution. A cast says "undefined behavior"/"doing something the type system says I shouldn't be".
Feb 25 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #6 from andrei metalanguage.com  2008-02-25 18:59 -------
The right thing to do is to manipulate fixed-sized arrays by value, but there
are a number of consequent issues to solve, e.g. we wouldn't like this:

writeln("Hello, world!");

to copy the actual content of the string on the stack and over to the callee.
Walter is considering making all array constants bind to dynamically-sized
types by default, and to statically-sized types only when explicitly requested,
e.g.:

auto x = "Hello, world!" // x is string
char[$] y = "Hello, world!" // y is char[13]
char[auto] z = "Hello, world!" // z is char[13]

The syntax is not decided between y's and z's. (Only one at most will be
chosen.) The former is better because you can then write:

auto[$] w = "Hello, world!" // w is invariant(char)[13]

whereas auto[auto] would look awkward.


Andrei


-- 
Feb 25 2008
parent Derek Parnell <derek nomail.afraid.org> writes:
On Tue, 26 Feb 2008 00:59:18 +0000 (UTC), d-bugmail puremagic.com wrote:

 http://d.puremagic.com/issues/show_bug.cgi?id=1869
 
 ------- Comment #6 from andrei metalanguage.com  2008-02-25 18:59 -------
 The right thing to do is to manipulate fixed-sized arrays by value,

Why? Or in other words, define "The right thing" and "manipulate". I'm not disagreeing with you, just asking for clarification.
  but there
 are a number of consequent issues to solve, e.g. we wouldn't like this:
 
 writeln("Hello, world!");
 
 to copy the actual content of the string on the stack and over to the callee.
 Walter is considering making all array constants bind to dynamically-sized
 types by default, and to statically-sized types only when explicitly requested

Thank goodness. I've always thought that assuming string literals are fixed length arrays was a suboptimal choice. I like the [$] syntax too for declaring fixed length array literals. -- Derek (skype: derek.j.parnell) Melbourne, Australia 26/02/2008 12:06:37 PM
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #7 from shro8822 vandals.uidaho.edu  2008-02-25 19:05 -------
but that still doesn't solve the base issue: I want a function to return a
pointer to a chunk of memory that is 4 ints in a row (or it is that as best the
compiler can tell).

(Err. I hope that is understandable)


-- 
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #8 from andrei metalanguage.com  2008-02-25 19:24 -------
(In reply to comment #7)
 but that still doesn't solve the base issue: I want a function to return a
 pointer to a chunk of memory that is 4 ints in a row (or it is that as best the
 compiler can tell).
 
 (Err. I hope that is understandable)

I don't understand. Doesn't this work? int[4]* foo() { static int[4] x; return &x; } ? --
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #9 from shro8822 vandals.uidaho.edu  2008-02-25 22:26 -------
I don't think so; that is a pointer to a pointer to a string of 4 ints (or a
string of 4 pointers to ints, I can never parse those by eye) it has one too
many levels of indirection.


-- 
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #10 from andrei metalanguage.com  2008-02-25 22:48 -------
(In reply to comment #9)
 I don't think so; that is a pointer to a pointer to a string of 4 ints (or a
 string of 4 pointers to ints, I can never parse those by eye) it has one too
 many levels of indirection.

I'm completely lost. float[4]* has exactly one level of indirection. --
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #11 from shro8822 vandals.uidaho.edu  2008-02-25 23:11 -------
traditionally arrays are worked by pointer math. While the array is a segment
of memory, its manifestation in the code is as a pointer. So "i[2]" takes a
pointer adds an offset of 2 and does the IO. From this "int[4]*" will be a
pointer to something that can be used like a an array, e.i. it will be a
pointer to a somewhat hidden pointer.

IIRC back in C, the compiler didn't make any distinction between an array name
and a pointer. In fact they don't worry about what is the array and what is the
index. 

This actually works (or did at one point):

int i[10];
7[i] = 4;


-- 
Feb 25 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #12 from andrei metalanguage.com  2008-02-26 01:12 -------
(In reply to comment #11)
 traditionally arrays are worked by pointer math. While the array is a segment
 of memory, its manifestation in the code is as a pointer. So "i[2]" takes a
 pointer adds an offset of 2 and does the IO. From this "int[4]*" will be a
 pointer to something that can be used like a an array, e.i. it will be a
 pointer to a somewhat hidden pointer.

That is incorrect. There is no hidden pointer and no extra indirection. There is a confusion somewhere along the way, so please let me give an example: void main() { int a[4]; int[4]* b = &a; a[1] = 2; (*b)[1] = 3; } Say that the four ints in a start at address 1000. Then a is an immutable pointer with value 1000. Also, b is a rebindable pointer with value 1000. Dereferencing b takes you straight to the first element of a, not to some hidden pointer that in turn takes you to the first element of a. --
Feb 25 2008
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 26/02/2008, d-bugmail puremagic.com <d-bugmail puremagic.com> wrote:
  but that still doesn't solve the base issue: I want a function to return a
  pointer to a chunk of memory that is 4 ints in a row (or it is that as best
the
  compiler can tell).

int[] f() { return [1,2,3,4].dup; } or int[] f() { auto r = new int[4]; /* assign r's elements */ return r; } If you need to prove that the array is exactly four bytes long, do int[] f() out(r) { assert(r.length == 4); } body { ... } If you really, really need to return by value, do struct A(T, int N) { T[N] a; } A!(int,4) f() { A!(int,4) r; /* assign r.a */ return r; } Hopefully, one of these will suit your needs
Feb 25 2008
parent BCS <ao pathlink.com> writes:
Reply to Janice,

 On 26/02/2008, d-bugmail puremagic.com <d-bugmail puremagic.com>
 wrote:
 
 but that still doesn't solve the base issue: I want a function to
 return a pointer to a chunk of memory that is 4 ints in a row (or it
 is that as best the compiler can tell).
 

Hopefully, one of these will suit your needs

None of those do quite what I want (see comment #18 down at the bottom)
Feb 26 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #14 from jason spashett.com  2008-02-26 04:26 -------
Thanks for the comments, it's more or less as I suspected. The ways of
returning an arrays pointed out by Janice Caron and others seem to feel like a
'workaround' to me.

I don't quite understand why the code below does not (or cannot work). The pass
by reference semantics of arrays don't have to apply for function return do
they? It might create a special case though I suppose.


int[4][4] f()
{
    int a[4][4];
    return a;
}


-- 
Feb 26 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #15 from andrei metalanguage.com  2008-02-26 10:53 -------
(In reply to comment #14)
 Thanks for the comments, it's more or less as I suspected. The ways of
 returning an arrays pointed out by Janice Caron and others seem to feel like a
 'workaround' to me.
 
 I don't quite understand why the code below does not (or cannot work). The pass
 by reference semantics of arrays don't have to apply for function return do
 they? It might create a special case though I suppose.
 
 
 int[4][4] f()
 {
     int a[4][4];
     return a;
 }

This will work. We'll also pass arrays in by value, and will bind literals to dynamically-sized arrays. In response to Derek: this is the "right thing" because every type in D has the same copy semantics whether it sits inside a struct or not. Every type... except statically-sized arrays. --
Feb 26 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #16 from jason spashett.com  2008-02-26 11:08 -------
(In reply to comment #15)
...
 This will work. We'll also pass arrays in by value, and will bind literals to
 dynamically-sized arrays.
 
 In response to Derek: this is the "right thing" because every type in D has the
 same copy semantics whether it sits inside a struct or not. Every type...
 except statically-sized arrays. 
 

point. I should of posted to digitalmars.d for this sort of thing instead of raising this as a bug shouldn't I? --
Feb 26 2008
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=1869
 
 
 
 
 
 ------- Comment #16 from jason spashett.com  2008-02-26 11:08 -------
 (In reply to comment #15)
 ...
 This will work. We'll also pass arrays in by value, and will bind literals to
 dynamically-sized arrays.

 In response to Derek: this is the "right thing" because every type in D has the
 same copy semantics whether it sits inside a struct or not. Every type...
 except statically-sized arrays. 

point. I should of posted to digitalmars.d for this sort of thing instead of raising this as a bug shouldn't I?

digitalmars.d.learn, in fact. However, you wouldn't have gotten this useful feedback from Andrei over there, because he doesn't read (or at least reply to) the NG's. So it's hard to say you did the wrong thing here. --bb
Feb 26 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869





------- Comment #17 from shro8822 vandals.uidaho.edu  2008-02-26 12:57 -------
(In reply to comment #12)
 (In reply to comment #11)
 
 That is incorrect. There is no hidden pointer and no extra indirection. There
 is a confusion somewhere along the way, so please let me give an example:
 

are you talking C or D? I could have sworn that in C a "pointer to a fixed size array" (e.i. double indirection) was written as "int[4]*". If it isn't, how is it written? Oh. I think I just figured it out!: int[4] a; int[4]* i = &a; i points to the same point as a but has a different type *i is the same pointer as i but with the type of a and **i is the content. OK what I want to do is return *(&a), a type that is the same as "a" but is mutable. p.s. Darn I should check the by line before I post --
Feb 26 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869


andrei metalanguage.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|normal                      |enhancement




------- Comment #18 from andrei metalanguage.com  2008-02-26 13:09 -------
(In reply to comment #17)
 are you talking C or D?

Both.
 I could have sworn that in C a "pointer to a fixed size
 array" (e.i. double indirection) was written as "int[4]*". If it isn't, how is
 it written?

It is written like that, and there is no double indirection.
 Oh. I think I just figured it out!:
 
 int[4] a;
 int[4]* i = &a;
 
 i points to the same point as a but has a different type *i is the same pointer
 as i but with the type of a and **i is the content.

That is correct.
 OK what I want to do is return *(&a), a type that is the same as "a" but is
 mutable. 

You'd need to return a reference to a fixed-size array, which in C does not exist, in C++ is spelled int[4]&, and in D is spelled ref int[4] but so far only applies to function arguments. Note that neither would be mutable, so you seem to want something that is physically possible but can't be expressed in either of the three languages. I'm keeping this bug report as a request for returning arrays by value, but I guess it's duplicated with a couple others. --
Feb 26 2008
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1869


Don <clugdbug yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |clugdbug yahoo.com.au
         Resolution|                            |FIXED


--- Comment #20 from Don <clugdbug yahoo.com.au> 2009-11-26 08:02:23 PST ---
Fixed DMD2.036: fixed-length arrays are now passed by value.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Nov 26 2009