why cant functions return arrays

D

Dik T. Winter

> It would be the same for arrays, arrays would be needed to be the same
> size.
>
> But then, since size information is always discarded when passing an
> array to a function, this would be difficult to achieve.
>
> What I wanted to emphasize is that the whole handling of arrays
> is completely crazy in C.

Perhaps it is crazy, but at that time it was a far better solution than
was current in Pascal. (Arrays of different size have a different type,
so it was not possible to write a routine that had as parameter an array
of arbitrary size.)
 
S

Shirsoft

Hi guys,

Could anyone please point out what is wrong with my proposed solution.
Please bear with me if my solution sounds incorrect.



Why are the following declarations invalid in C?
int f()[];
int f()[10];
It would be great if anyone could also explain the design decision
for such a language restricton.
Where would the array get temporarily stored? Who would be responsible
for freeing it?
In a stack-based machine that mixes parameters and control, the
information for the called routine is already on the stack by the time
the hypothethical return array is created. As the return array could
be of any size, the caller cannot know how much space to reserve
"under" the stack frame for the called routine. Therefor the called
routine would either have to somehow insert the space for the array
"above" the stack frame for the routine itself (so that it still
exists when the routine returns), or else the called routine would
have to return an address of the array. If it returns an address of
the array, the address cannot be that of an automatic variable in
the called routine, as after the call those automatic variables
become inaccessible. It can't use a static variable because it doesn't
know the maximum size. So the only way to make that work would be
to malloc() an array to store the data into, store the data, and
return the pointer to the malloc'd area. But then what's the contract
about who frees the array? If you require that the calling routine
-automatically- frees the array, then you add noticable complexity
to the language. If you require that the calling routine -explicitly-
free the array, then you have no more expressive power than you
already have available by making the return type a pointer and returning
the pointer to a malloc'd area.

I & Sanjay had this discussion on the returning array by functions.
Lets say that the language allowed 2 things.
1. Return array from a function by just copying the address of the
first element.
2. Creating array aliases like regular variables.

What would be wrong with the following code then:

int[] func2(int a[]);
void func1()
{
int a[5];
int &b[]=func2(a);//b is some sort of an alias to the returned type}

int[] func2(int a[])
{
//do something
return a;

}
 
H

Hallvard B Furuseth

Bartc said:
(...)
int f()[10];
(...)
foo() { int *a; ... { ... a = f(); ... } }
*a is a pointer to int. f() returns an array of int. So there is a type
mismatch and this should not compile, and the problem would not arise. I
don't think you can reasonably expect an array returned by a function to
'decay' to a pointer in the same way as a normal array.

No, I don't expect that - because the language forbinds "int f()[10]".
However, yes I do expect "a = <expression of type array of int>" to be
treated the same way regardless of where that expression comes from.
If it did not, just what should the program be allowed to do with it?

Well, it could be assigned to an array:

*a=f(); where a already points to a suitable space. Or possibly:

If you mean "int *a;", this is a type error (assigning an array to an
int) and I like compilers who warn me about that.

If a is declared as int (*a)[10], fine. That's just a case of allowing
array assignment. You can argue for or against that. Arguments against
is that it can be limited or confusing due to the normal "decay to
pointer" feature, and also that passing an array by value can be a much
huger operation than it looks like when you are used to that what
actually gets passerd is the pointer.
int b[10];
b=f();

Same again.
Or it could be passed directly to another function that takes arrays
of the same size:
g(f());

That may require that the program first copies the array to a temporary
array in the caller's stack. So again, once it's there, what else is
the program allowed to do with the temporary? E.g.:
Would &f() be OK? *&f()? f()[0]? &f()[0]?

Another point - g(f()) would be an error if a prototype of g() was not
in scope. Then the compiler would not know that g() was expecting
an array rather than a pointer to the first element. So that answers
why it was not in K&R C - it did not have prototypes.

Current C does, but this feature would introduce another point where
calls with and without prototype would differ - and which could not
be fixed by casting the argument to the righe type.
Actually, adding such a new type of array wouldn't be that much of a
problem. But the special interaction between newarrays and pointers
wouldn't exist in the same way as for ordinary arrays.

They wouldn't anyway, due to the problem with g(f()) above. With
regular "decay-to-pointer" arrays, that call works fine with or without
a prototype for g.

Defining this in terms of how functions work is the wrong approach. It
makes things unnecessarily murky.

OTOH with such a non-decaying array type, we'd have that type clearly
spelling out the semantics of such array objects. Which is what types
are _for_. Jacob said he used operator overloading to make such an
array - and unless I misunderstood, what he made was a type.
So setting up dynamic arrays and indexing them as though they were fixed
arrays would not be possible.

I dunno. C99 supports variable-length arrays. But what you are
suggesting also seems to be passing fixed-length arrays around, so I
don't quite see your point.
So I don't see such newarrays being popular with C
aficionados. Especially as these arrays would have to be a fixed size
so would have the same limitations as early Pascal.

A new array type needs something extra, and that would need to be
flexible bounds, or bounds that are passed around with the array. But
then, this would be taking C to a slightly different level.

Yes. There are plenty of features it'd be nice to add to C. The
problem is to choose between them, and to find ten people who agree on
which features would be good and which would be bad. C99 was an attempt
at that, and has been less than successful so far.
 
B

Bartc

Default User said:
How do you figure?

The fact that Shirsoft top-posted a reply to his own post, or my assertion
about special rules?

The special rules are just my opinion. |After all, someone may have intended
to post ABCD, but first posts BCD then A>BCD, there's not much difference.
But messing around with someone else's article is different.

(And top-posting doesn't bother me in the slightest)

-- Bartc
 
B

Bartc

Shirsoft said:
Why are the following declarations invalid in C?
int f()[];
int f()[10];
It would be great if anyone could also explain the design decision
for such a language restricton.

Where would the array get temporarily stored? Who would be responsible
for freeing it?
I & Sanjay had this discussion on the returning array by functions.
Lets say that the language allowed 2 things.
1. Return array from a function by just copying the address of the
first element.
2. Creating array aliases like regular variables.

What would be wrong with the following code then:

int[] func2(int a[]);
void func1()
{
int a[5];
int &b[]=func2(a);//b is some sort of an alias to the returned type
}
int[] func2(int a[])
{
//do something
return a;
}

It looks like you allow functions to return (pointers to) arrays of
arbitrary size. In that case you need a mechanism for returning the length
of the array.

If you are pushing around pointers to arrays instead of the arrays
themselves, there might be the problem of memory management when such an
array is modified, destroyed, or goes out of scope; there might be another
pointer to the same array. You are mixing manual memory handling with
automatic handling, that will give problems.

In general C doesn't like hidden or automatic pointers to things, the
language is designed to be transparent. (Although I'm aware there are
extensions that do this sort of thing, and more.)

Your ideas are good. But to implement properly is difficult: a totally new
array type is needed, which is a 3-part value (a,b,c), and it is this value
that is passed around and returned. (a is pointer to the elements, b is the
length, c is some magic required to fix the memory problem). With the
ability to index and so on (and perhaps take slices of, while we're at it!).

It needs a *lot* of compiler support, the arrays take up more space than
regular ones, and could be a little slower. And breaks the rule about
transparency.

-- Bartc
 
D

Default User

Bartc said:
The fact that Shirsoft top-posted a reply to his own post, or my
assertion about special rules?

Yes.
The special rules are just my opinion. |After all, someone may have
intended to post ABCD, but first posts BCD then A>BCD, there's not
much difference. But messing around with someone else's article is
different.

I'm not following. It doesn't have anything do with "messing around".
The reason for not top-posting is that it makes things difficult to
read, and has lots of unnecessary text. Why was that a special case?




Brian
 
R

Richard

Default User said:
I'm not following. It doesn't have anything do with "messing around".
The reason for not top-posting is that it makes things difficult to
read, and has lots of unnecessary text. Why was that a special case?




Brian

Why do you think people want you to harass and net nanny? You need to
listen to Heathfield - your posts are nothing but noise. You are not in
charge - let people learn by doing. They don't need you providing your
"expertise" in posting techniques. They have "Chuck" for that.
 
S

sanjay.vasudevan

Keith said:
Why are the following declarations invalid in C?

int f()[];
int f()[10];

It would be great if anyone could also explain the design decision
for such a language restricton.

Handling arrays as first-class types and objects turns out to be a
non-trivial language design problem.

As others have mentioned, C didn't originally allow structures to be
assigned, passed as arguments, or returned as function results.
Adding this functionality wasn't much of a problem, partly because all
structures of a given type are the same size. The only really new
thing was that some operations required copying arbitrarily large (but
fixed) amounts of data, possibly by implicitly invoking memcpy() or
something like it.

A major for arrays is that array names are usually converted to
pointers; defining the syntax for first-class array objects and values
without breaking existing code would be difficult.

Also, arrays of a given type can usefully have different sizes.

Let's assume that we can work around the existing code problem by
defining a new kind of array, one that doesn't decay to a pointer.

Assume that f is a function that returns an array of int. Presumably
you'd want to be able to do something like this:

int arr[100];
arr = f();

What if f returns an array of 90 ints? Or 200? Do you reject it at
compile time? If so, you have to decide when writing the f *exactly*
how many elements it's going to return; that's far less flexible than
C's current (admittedly unwieldy) mechanisms. Or do you reject it
during execution? If so, how? Do you introduce an exception
mechanism? Do you just say it's undefined behavior? Or do you copy
just part of the array?

The following code gives a type mismatch error:
int a[90];
int (*b)[100];
b = &a;

do


Regardless of what syntax you use to express them, arrays are
fundamentally special in ways that other types are not. C's current
way of dealing with that complexity is not pretty, but it works.

Having said all that, you could disallow the assignment and allow
array-returning functions to be used in initializers:

int arr[] = f();

That could probably be quite useful *if* you could manage to define it
without breaking existing code.

--
Keith Thompson (The_Other_Keith) (e-mail address removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
S

sanjay.vasudevan

Keith said:
Why are the following declarations invalid in C?

int f()[];
int f()[10];

It would be great if anyone could also explain the design decision
for such a language restricton.

Handling arrays as first-class types and objects turns out to be a
non-trivial language design problem.

As others have mentioned, C didn't originally allow structures to be
assigned, passed as arguments, or returned as function results.
Adding this functionality wasn't much of a problem, partly because all
structures of a given type are the same size. The only really new
thing was that some operations required copying arbitrarily large (but
fixed) amounts of data, possibly by implicitly invoking memcpy() or
something like it.

A major for arrays is that array names are usually converted to
pointers; defining the syntax for first-class array objects and values
without breaking existing code would be difficult.

Also, arrays of a given type can usefully have different sizes.

Let's assume that we can work around the existing code problem by
defining a new kind of array, one that doesn't decay to a pointer.

Assume that f is a function that returns an array of int. Presumably
you'd want to be able to do something like this:

int arr[100];
arr = f();

What if f returns an array of 90 ints? Or 200? Do you reject it at
compile time? If so, you have to decide when writing the f *exactly*
how many elements it's going to return; that's far less flexible than
C's current (admittedly unwieldy) mechanisms. Or do you reject it
during execution? If so, how? Do you introduce an exception
mechanism? Do you just say it's undefined behavior? Or do you copy
just part of the array?

The following code gives a type mismatch error:
int a[90];
int (*b)[100];
b = &a;

doesnt this mean that there exists a restriction on array address
assignment based on size.
so, we cud allow functions to return arrays(as a first-class type) of
known size (althogh as u mentioned, this is quite restrictive) and
allow assigning only to same size arrays.

of course "int f()[];" neednt be allowed.

and this treatment as a first-class type would break existing code.

-sanjay
 
K

Keith Thompson

Keith Thompson wrote: [...]
Assume that f is a function that returns an array of int. Presumably
you'd want to be able to do something like this:

int arr[100];
arr = f();

What if f returns an array of 90 ints? Or 200? Do you reject it at
compile time? If so, you have to decide when writing the f *exactly*
how many elements it's going to return; that's far less flexible than
C's current (admittedly unwieldy) mechanisms. Or do you reject it
during execution? If so, how? Do you introduce an exception
mechanism? Do you just say it's undefined behavior? Or do you copy
just part of the array?

The following code gives a type mismatch error:
int a[90];
int (*b)[100];
b = &a;

doesnt this mean that there exists a restriction on array address
assignment based on size.

Yes. int[90] and int[100] are two distinct types; that's the problem.

It's actually not that much of a problem in C as it currently exists,
because we have other ways of working with arrays of arbitrary length:
we typically work with a pointer to the first element and some
programmer-defined technique of tracking the length. Which means that
it's entirely up to the programmer to make sure array lengths match
when they need to.
so, we cud allow functions to return arrays(as a first-class type) of
known size (althogh as u mentioned, this is quite restrictive) and
allow assigning only to same size arrays.

Right, and IMHO it wouldn't be worth it, because it would be so
inflexible.

<OT>
In Ada, you can declare an array type that leaves the dimensions
unspecified. By specifying the dimensions, you create a *subtype*.
All subtypes of the same type are compile-time compatible, but
operations are checked at run time. The languages operations are
sufficiently powerful (including passing arbitrary arrays as
parameters with full type checking, returning arbitrary arrays from
functions, and a built-in array slicing operation) to make this
workable. I don't believe something like this could be added to C
without altering the feel of the language.
of course "int f()[];" neednt be allowed.

and this treatment as a first-class type would break existing code.

Yes.
 
J

James Dow Allen

Why are the following declarations invalid in C?
int f()[];
int f()[10];
I happen to think it was a good choice.  For about 30 years now you
have been able to pass and return fixed-size arrays by value by
wrapping them in a structure.

Of course. The ease with which arrays can be embedded in
structures (and vice versa), as well as the fact that C's
elegant syntax depends on the "peculiar" relationship
of pointer and array means, IMHO, that the views of
OP and Mr. navia imply gross failure to understand and
appreciate C.

As a trivial example, I'm sure I'm not the only one who's
decided to replace, for some "good" reason,
char *foo;
in some context with
char foo[BAZ];
The code which uses foo typically requires almost
no changes! How do you achieve that with Bastardized-C ?

To accept the views of OP and navia we'd have to
agree that changing
int foo[10];
to
struct { int foo[10]; };
is too burdensome for the programmer.
Programmers so easily emburdened would do well
do redirect their queries to
alt.fetish.cobol
or some other ng.language_for_lightweights.

James
 
R

Richard

Jack Klein said:
Why are the following declarations invalid in C?

int f()[];
int f()[10];

It would be great if anyone could also explain the design decision
for such a language restricton.

Regards,
Sanjay

There is no reason. It is just a design mistake of the language.

That is, in the opinion of the very opinionated Jacob Navia.

I happen to think it was a good choice. For about 30 years now you
have been able to pass and return fixed-size arrays by value by
wrapping them in a structure.

So you feel a workaround is a good choice? Nonsense.
 
R

Richard

James Dow Allen said:
(e-mail address removed) wrote:
Why are the following declarations invalid in C?
int f()[];
int f()[10];
I happen to think it was a good choice.  For about 30 years now you
have been able to pass and return fixed-size arrays by value by
wrapping them in a structure.

Of course. The ease with which arrays can be embedded in
structures (and vice versa), as well as the fact that C's
elegant syntax depends on the "peculiar" relationship
of pointer and array means, IMHO, that the views of
OP and Mr. navia imply gross failure to understand and
appreciate C.

"Mr Navia". Someone is setting Heathfield up here.
As a trivial example, I'm sure I'm not the only one who's
decided to replace, for some "good" reason,
char *foo;
in some context with
char foo[BAZ];
The code which uses foo typically requires almost
no changes! How do you achieve that with Bastardized-C ?

Bastardized C? Where did Jacob suggest bastardized anything? Possibly
you're referring to Klein's wrapping array in a struct solution?
To accept the views of OP and navia we'd have to
agree that changing
int foo[10];
to
struct { int foo[10]; };
is too burdensome for the programmer.

Where does this end? You seem to to think that any form of ugly kludge
is OK when used to put Jacob down.
Programmers so easily emburdened would do well

This post has Heathfield sockpuppet written all over it.
do redirect their queries to
alt.fetish.cobol
or some other ng.language_for_lightweights.

James

Or maybe alt.religious.idiot ?
 
J

jacob navia

James said:
(e-mail address removed) wrote:
Why are the following declarations invalid in C?
int f()[];
int f()[10];
I happen to think it was a good choice. For about 30 years now you
have been able to pass and return fixed-size arrays by value by
wrapping them in a structure.

Of course. The ease with which arrays can be embedded in
structures (and vice versa), as well as the fact that C's
elegant syntax depends on the "peculiar" relationship
of pointer and array means, IMHO, that the views of
OP and Mr. navia imply gross failure to understand and
appreciate C.

As a trivial example, I'm sure I'm not the only one who's
decided to replace, for some "good" reason,
char *foo;
in some context with
char foo[BAZ];
The code which uses foo typically requires almost
no changes! How do you achieve that with Bastardized-C ?

This is precisely the problem.
Since you can do easily this kind of hack, size information
must be discarded when passing an array into another function.

#include <stdio.h>
int fn(int tab[45])
{
printf("sizeof(tab)=%d\n",sizeof(tab));
}

int main(void) { int tab[45]; fn(tab); }

I get sizeof(tab) =4

I get the size of a int pointer, even if I explicitely
specified the size of the array.

This makes checking array bounds impossible in C.
To accept the views of OP and navia we'd have to
agree that changing
int foo[10];
to
struct { int foo[10]; };

This will not even compile!
You missed the name of the structure. You have to give
a name to all the different array sizes!
is too burdensome for the programmer.
Programmers so easily emburdened would do well
do redirect their queries to
alt.fetish.cobol
or some other ng.language_for_lightweights.

This arrogant point of view tries to sell us a work
around as a feature.

And obviously it is *SO EASY* that geniuses like you
can't get it right! :)
 
K

Kenny McCormack

Richard Heathfield said:
The problem faced by Richard Riley and his fellow trolls is that a lot of
articles posted in this newsgroup express opinions similar to mine. There

Or you're just lying. Occam's razor, and all that.
 
R

Richard

Or you're just lying. Occam's razor, and all that.

And a lot of people blatantly do not agree with Heathfield who is, to be
honest, so full of himself I am astonished his head can fit through the
door. It's funny how one is a troll when one says "Hey, there's no need
to be so rude and obnoxious". He appears to have made a career out of
it though from what I can gather in this group. A more thoroughly
unpleasant character would be hard to pinpoint in this or other
technical news groups.
 
S

soscpd

Hello List

Not particulary to anyone, but...

Any possibility to change the standard and return arrays? If yes, what
is the path to accomplish that? If no, what is the purpose of this
thread? Global trolling? Some place to put everything off? If yes,
please, call-me back here asap. I have a lot to say too.

Regards
Rafael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top