www.digitalmars.com         C & C++   DMDScript  

D - Miscellaneous comments on D

reply "psheer AT icon DOT co DOT za" <nospam nospam.com> writes:
I hope some of these are useful:::

1.
A major limitation of C code is not being able to return
more than one argument from a function. For instance,
the stack would easily be able to handle functions like:
	int, float, char* foo ()
	{
		return 1, 3.1416, "pi";
	}
which is preferable to
	int foo (float *result1, char **reault2)
	{
		*result1 = 3.1416;
		*result2 = "pi";
		return 1;
	}
(or evan preferable to declaring an intermediate struct)
This notation reduces code size enormously. Then (like python):
	int r;
	float val;
	char *descr:
	r, val, descr = foo ();


2.
"there appears to be practically no other use for __FILE__ and __LINE__"

These can be passed to functions to get tracebacks. I hope D is not
considering dropping them as they are essential IMO.

3.
I think that source files should be only UTF8 because:
	- UTF8 supports 20 bit characters.
	- UTF8 is exactly ASCII when there are no
		international characters (the usual case).
	- Its better to have only one format

4. A D to C translator?

5. "if a new errno value is added to the runtime system, the old code
can not properly display a meaningful error message"

This is scarcely true: strerror() ???


-paul

-- 
Paul Sheer Consulting IT Services . . . Tel . . . +27 21 761 7224
Linux development, cryptography,  recuitment,  support,  training
http://www.icon.co.za/~psheer . . . . http://rute.sourceforge.net
L I N U X . . . . . . . . . . . .  The Choice of a GNU Generation
Aug 18 2001
parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"psheer AT icon DOT co DOT za" <nospam nospam.com> wrote in message
news:9llhvs$d42$1 digitaldaemon.com...
 I hope some of these are useful:::

 1.
 A major limitation of C code is not being able to return
 more than one argument from a function. For instance,
 the stack would easily be able to handle functions like:
 int, float, char* foo ()
 {
 return 1, 3.1416, "pi";
 }
 which is preferable to
 int foo (float *result1, char **reault2)
 {
 *result1 = 3.1416;
 *result2 = "pi";
 return 1;
 }
 (or evan preferable to declaring an intermediate struct)
 This notation reduces code size enormously. Then (like python):
 int r;
 float val;
 char *descr:
 r, val, descr = foo ();

Agreed. I think this is a much better idea than in, out and inout parameters. Given something like this: int a,b,x; a,b = myfunc(x); it's obvious the role that a,b and x play, whereas with in, out & inout the call looks like: int a,b,x; myfunc(a,b,x); // or a = myfunc(b,x); This is definitely an improvement over the current D spec. Peter.
Aug 18 2001
parent reply Grobbins <grobbins badaddress.znet.com> writes:
 I think this is a much better idea than in, out and inout
 parameters.  Given something like this:
 int a,b,x;
 a,b = myfunc(x);
 it's obvious the role that a,b and x play

While multiple return parameters seem elegant, you end up with code that is harder to read and maintain. Consider int,int,int,int CountAnimals(); which is called numCats,numDogs,numFerrets,numGoats = CountAnimals(); Without parameter names attached to the output values in the declaration, it's hard to know if I've picked up the return values correctly. Greg Robbins
Aug 18 2001
next sibling parent reply Russ Lewis <russ deming-os.org> writes:
Grobbins wrote:

 While multiple return parameters seem elegant, you end up with code that
 is harder to read and maintain.  Consider

   int,int,int,int CountAnimals();

 which is called

   numCats,numDogs,numFerrets,numGoats = CountAnimals();

 Without parameter names attached to the output values in the
 declaration, it's hard to know if I've picked up the return values
 correctly.

Right. It is possible (though ugly) to return structures or classes which are aggregates of your various return types. I do hope that D (unlike C) will allow you to return an array (don't see in the spec if it defines if you can or not). This would make a lot of sense with the self-awareness that D arrays have. Consider these possible declarations: int[] foo(); // returns an array of ints, unknown size int[3] foo(); // returns an array of ints, guaranteed to be 3 long. might throw an exception if function tried to return something else
Aug 18 2001
next sibling parent reply "Walter" <walter digitalmars.com> writes:
Russ Lewis wrote in message <3B7EE227.D011607E deming-os.org>...
I do hope that D (unlike C)
will allow you to return an array (don't see in the spec if it defines if
you can or not).  This would make a lot of sense with the self-awareness
that D arrays have.

Yes, it works in D.
Consider these possible declarations:

int[] foo();   // returns an array of ints, unknown size

Yes.
int[3] foo();   // returns an array of ints, guaranteed to be 3 long.

throw an exception if function tried to return something else

I hadn't thought of that case.
Aug 18 2001
parent reply "Bradeeoh" <bradeeoh crosswinds.net> writes:
int[3] foo();   // returns an array of ints, guaranteed to be 3 long.

throw an exception if function tried to return something else

I hadn't thought of that case.

it, but it seems to me if a function returns an integer, you should place a restriction on what range of integer it returns. If it returns a unicode character, you shouldn't limit it to ascii characters. If it returns a "fooObject", you shouldn't limit it to a "fooObject" with various data members. If it returns an integer array, you shouldn't limit the parameters of the array you get back. Especially since D's arrays have that WONDERFULLY useful extra information coded in such as array length, I say return a generic integer array, and if the function caller needs it to be of length 3, it's easy enough for them to check it via int[].length. I don't know what specifically about this bothers me, but for some reason I shudder whenever I think about it. Almost like "boolean foo(){ return true; }" being declared as "true foo(){ return; }" or "true foo(){ return true; }" That's just my two cents. Any other thoughts? -Brady
Aug 18 2001
parent reply Russ Lewis <russ deming-os.org> writes:
Bradeeoh wrote:

 If it returns an integer array, you shouldn't limit the parameters of the
 array you get back.

 Especially since D's arrays have that WONDERFULLY useful extra information
 coded in such as array length, I say return a generic integer array, and if
 the function caller needs it to be of length 3, it's easy enough for them to
 check it via int[].length.

 I don't know what specifically about this bothers me, but for some reason I
 shudder whenever I think about it.  Almost like "boolean foo(){ return
 true; }" being declared as "true foo(){ return; }" or "true foo(){ return
 true; }"

In my view, it's a design distinction between "return an array of values" (that might have any number of values) and "return three integers". Consider a new strtoul(): int[2] strtoul(char *str,int base) In this D implementation, return[0] returns the value you wanted, and return[1] is analogous to the endPtr parameter of C's strtoul. In this case, return[1] will return how many characters were consumed. It would not make any sense, in this function, to return any more or less than 2 values.
Aug 18 2001
parent reply "Bradeeoh" <bradeeoh crosswinds.net> writes:
 In my view, it's a design distinction between "return an array of values"

 might have any number of values) and "return three integers".  Consider a

 strtoul():

 int[2] strtoul(char *str,int base)

 In this D implementation, return[0] returns the value you wanted, and

 is analogous to the endPtr parameter of C's strtoul.  In this case,

 will return how many characters were consumed.  It would not make any

 this function, to return any more or less than 2 values.

Point taken, however, I'm still not convinced that an array of length 2 of integers should be treated any differently than a general array of integers. Another way of describing my problem with it is this - if you're going to allow functions to return int[2], then are you also going to allow these returned values to be stored in a var referencing a dynamic array? A few problems possibly come to mind. ie - int[2] a; // creates a static array analogous to c arrays a = strtoul( char *str, int base ); // valid, since we're storing an int[2] in an int[2].....? int[] b; // creates a dynamic array, with length data and is garbage collectable b = strtoul( char *str, int base ); // valid? b is an int[], not an int[2] - is this okay? int[4] c; c = strtoul( char *str, int base ); // error? or no? whose to say? I guess, what I'm trying to say, is that this type of return value would, in effect, be introducing a (near) infinite number of array types that may or may not have to be type checked to keep in the spirit of the language. Seems like implementing this would either cause us to A - require an extended, rigid semantic definition of how all this works and B - extra work in the compiler dealing with the basic possibilities. -Brady
Aug 18 2001
parent "jacob navia" <jacob jacob.remcomp.fr> writes:
"Bradeeoh" <bradeeoh crosswinds.net> wrote in message
news:9lnene$1flr$1 digitaldaemon.com...
 In my view, it's a design distinction between "return an array of


 (that
 might have any number of values) and "return three integers".  Consider


 new
 strtoul():

 int[2] strtoul(char *str,int base)


This can be easily written as typedef struct _strtoulReturnValue { long result; int CharactresUsed; } StrToUlReturn; Then you access the result with r = strtoul("978"...); r.CharactersUsed what is clearer than int r[2]= strtoul("123"...); r[1] Those absolute indexes, so necessary sometimes aren't in this example well choosen. Arrays haven't got named fields, more appropiate for a function result. Of course int r[1024*768] = CopyScreen(); is a better example for an application of arrays being returned from functions.
Aug 20 2001
prev sibling parent reply "Brent Schartung" <bschartung home.com> writes:
Just use contracts; that's what they're there for.  The contract will
specify that the returned array should have three elements, and the code
will (!)be commented to describe the returned contents.  Keep it simple!


 Consider these possible declarations:

 int[] foo();   // returns an array of ints, unknown size
 int[3] foo();   // returns an array of ints, guaranteed to be 3 long.

 throw an exception if function tried to return something else

Aug 19 2001
parent Charles Hixson <charleshixsn earthlink.net> writes:
Brent Schartung wrote:
 Just use contracts; that's what they're there for.  The contract will
 specify that the returned array should have three elements, and the 
 code will (!)be commented to describe the returned contents.  Keep 
 it simple!

Contracts would handle it, but an exception might be easier to recover from. Also, if one is going to assign the return value of a function to an array, it might be just as well if one could be sure that it wouldn't overfill the array. Ships docked[5]; -- only room to tie up 5 ships try { docked = pilot_log(today); ... } catch trafficJam (msg) { ... }
Aug 21 2001
prev sibling next sibling parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"Grobbins" <grobbins badaddress.znet.com> wrote in message
news:grobbins-2176AA.11503918082001 news.digitalmars.com...
 I think this is a much better idea than in, out and inout
 parameters.  Given something like this:
 int a,b,x;
 a,b = myfunc(x);
 it's obvious the role that a,b and x play

While multiple return parameters seem elegant, you end up with code that is harder to read and maintain. Consider int,int,int,int CountAnimals(); which is called numCats,numDogs,numFerrets,numGoats = CountAnimals(); Without parameter names attached to the output values in the declaration, it's hard to know if I've picked up the return values correctly.

Okay, that's a fair point. I can think of a couple of declaration formats that might fix that issue: (int cats, int dogs, int ferrets, int goats) countAnimals() { ... } or countAnimals() returns (int cats, int dogs, int ferrets, int goats) { .... } I prefer the latter. Anyone else really like it? Hate it? I still think that in: a,b = myfunc(x); It is much clearer what role the variables are taking as input or results from the function as compared to the in, out, inout approach. Peter.
Aug 18 2001
parent reply "Bradeeoh" <bradeeoh crosswinds.net> writes:
 countAnimals() returns (int cats, int dogs, int ferrets, int goats)
 {
     ....
 }


 I prefer the latter.  Anyone else really like it?  Hate it?

That is intriguing. Definately clear, and it could be reasonably useful. I have a couple of nitpicks, one major and one minor. Major - what is the formal return type of this function? I notice you just wrote - countAnimals() returns (int.......goats) there is nothing before the function name. Granted, the return type is implicitly 4 integers, but I think one of the things (possibly) holding this feature back is that 4 integers is neither a primitive data type, nor a class/struct/union type. It's just.... 4... different primitive data types. If you can give a formal, simple definition as to the return type of the function, it may be worth looking into and could end up being something incredibly useful. ;) The minor nitpick - A number of ways to do this just ran through my head, but I noticed you haven't touched on the point at all - what is the syntax of return the values within the function? I'm sure you're thinking something as simple as "return (cats,dogs,ferrets,goats);" but, of course, that may also not be as simple as it seems.... ;) -Brady
Aug 18 2001
next sibling parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"Bradeeoh" <bradeeoh crosswinds.net> wrote in message
news:9lnd7k$1eh8$1 digitaldaemon.com...
 countAnimals() returns (int cats, int dogs, int ferrets, int goats)
 {
     ....
 }


 I prefer the latter.  Anyone else really like it?  Hate it?

That is intriguing. Definately clear, and it could be reasonably useful.

 have a couple of nitpicks, one major and one minor.  Major - what is the
 formal return type of this function?  I notice you just wrote -
 countAnimals() returns (int.......goats)

 there is nothing before the function name.  Granted, the return type is
 implicitly 4 integers, but I think one of the things (possibly) holding

 feature back is that 4 integers is neither a primitive data type, nor a
 class/struct/union type.  It's just.... 4... different primitive data

 If you can give a formal, simple definition as to the return type of the
 function, it may be worth looking into and could end up being something
 incredibly useful.  ;)

Hi There Bradeeoh (wassat then? :-) ). I'm not too sure what the problem is. I do see that 4 ints is not a primitve data type (or struct) but I don't see why that should be an issue. Are you thinking that this might provide a problem for the stack frame? I don't see why - we have lists of parameters, lists of return types should be too hard. Have I misunderstood your point?
 The minor nitpick - A number of ways to do this just ran through my head,
 but I noticed you haven't touched on the point at all - what is the syntax
 of return the values within the function?

 I'm sure you're thinking something as simple as "return
 (cats,dogs,ferrets,goats);" but, of course, that may also not be as simple
 as it seems....  ;)

Hey, I'm keen on being enlightened - what are the problems you see? I *was* thinking "return(cats,dogs,ferrets,goats);" for the return syntax - it would be illegal to return more or less than the stated number of values just as it is illegal to call a function w/o the correct number of parameters. Feel free to expand on the idea / issues. Peter.
Aug 19 2001
next sibling parent "psheer AT icon DOT co DOT za" <nospam nospam.com> writes:
In article <9lo1e0$1r4e$1 digitaldaemon.com>, "kaffiene"
<kaffiene xtra.co.nz> wrote:
 "Bradeeoh" <bradeeoh crosswinds.net> wrote in message
 news:9lnd7k$1eh8$1 digitaldaemon.com...

 have a couple of nitpicks, one major and one minor.  Major - what is
 the formal return type of this function?  I notice you just wrote -
 countAnimals() returns (int.......goats)


 I'm not too sure what the problem is.  I do see that 4 ints is not a
 primitve data type (or struct) but I don't see why that should be an
 issue. Are you thinking that this might provide a problem for the stack
 frame?  I don't see why - we have lists of parameters, lists of return
 types should be too hard.
 

i also don't see the problem. this is easy even to translate into C: you just create a temporary structure with four members in it. In fact, its precisely because one has to do this so often, that it should be part of the language in the first place: ala Python. I do agree that the names of the return values should be part of the declaration. We can extend this further. The C declaration for read(), int read (int fd, char *buf, int size); should REALLY be: (bytes_done_or_error int) read (int fd, char *buf, int size); /* (pick a notation you like) */ if you think about it, its ridiculous that, in C, the function declaration should describe everything that the function is passed, but not what it returns!!! Imagine the other extreme: header files containing: int read (int, char *, int); which is legal ANSI C (sic). -paul -- Paul Sheer Consulting IT Services . . . Tel . . . +27 21 761 7224 Linux development, cryptography, recuitment, support, training http://www.icon.co.za/~psheer . . . . http://rute.sourceforge.net L I N U X . . . . . . . . . . . . The Choice of a GNU Generation
Aug 19 2001
prev sibling parent reply "Bradeeoh" <bradeeoh crosswinds.net> writes:
 Hi There Bradeeoh (wassat then? :-) ).

 I'm not too sure what the problem is.  I do see that 4 ints is not a
 primitve data type (or struct) but I don't see why that should be an

 Are you thinking that this might provide a problem for the stack frame?  I
 don't see why - we have lists of parameters, lists of return types should

 too hard.

 Have I misunderstood your point?

I guess the problem I'm seeing, especially as I'm not able to describe it well, is just a matter of how I "feel" about it. I just cringe when I see it, but I cannot explain why. The points you and others makes about it's ease of implementation, etc, are well taken. So, to just say what Walter has said about a few other features that are up for debate, it just doesn't "feel right". :) I will gracefully bow out in my debate on this topic. :) I can make one solid point on the subject, however - I don't deny for a second this feature could be useful, but if it's chosen to be implemented, be very careful on the syntax chosen, as it could potentially turn out looking quite messy. :) -Brady
Aug 19 2001
parent reply "psheer AT icon DOT co DOT za" <nospam nospam.com> writes:
 
 I guess the problem I'm seeing, especially as I'm not able to describe
 it well, is just a matter of how I "feel" about it.  I just cringe when
 I see it, but I cannot explain why.  The points you and others makes
 about it's ease of implementation, etc, are well taken.
 
 So, to just say what Walter has said about a few other features that are
 up for debate, it just doesn't "feel right".  :) I will gracefully bow
 out in my debate on this topic. :)
 
 I can make one solid point on the subject, however - I don't deny for a
 second this feature could be useful, but if it's chosen to be
 implemented, be very careful on the syntax chosen, as it could
 potentially turn out looking quite messy.  :)
 

yeah, i understand exactly. none-the-less, the uglyness of trying to return multiple values has crudded up C for long enough. So this is a problem that REALLY needs fixing. Another reason for multiple return values is simply this: in assembler, the compiler pushes multiple arguments onto the stack whenever it does a function call. The return value is pushed onto the stack at the end of the function call. C arbitrarily chose to limit the number of return pushes to 1, even though the number of calling pushes could be many. (Am i correct here?). This limitation has infected all development to date. The read() function call CLEARLY returns two values: an error code, and the number of bytes. These are two conceptually different things. To roll them into one value is the ugliest thing i can think of. And yet every API tries to work around this limitation instead of extending the language in a very simple way. Imagine the elegance of being able to trust the return value of a read() call without having to check if it is -1 before-hand ?! Instead, we create extra conditionals in the calling code AND extra conditionals in the function code. All because we are trying to squeeze into the limitation of single return values. -paul -- Paul Sheer Consulting IT Services . . . Tel . . . +27 21 761 7224 Linux development, cryptography, recuitment, support, training http://www.icon.co.za/~psheer . . . . http://rute.sourceforge.net L I N U X . . . . . . . . . . . . The Choice of a GNU Generation
Aug 19 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
psheer AT icon DOT co DOT za wrote:
 none-the-less, the uglyness of trying to return multiple values has
 crudded up C for long enough. So this is a problem that REALLY
 needs fixing.
 
 Another reason for multiple return values is simply this: in assembler,
 the compiler pushes multiple arguments onto the stack whenever it does
 a function call. The return value is pushed onto the stack at the end
 of the function call.   C arbitrarily chose to limit the number of return
 pushes to 1, even though the number of calling pushes could be many.
 (Am i correct here?).

Well, back when I still cared what the code coming out of a compiler looked like (1987-1992?), most compilers I was familiar with returned values in the "most temporary" register: (E)AX on x86, D0 on 68K, etc. -- not on the stack. Is returning a struct really so ugly? struct ReturnValue { bool success; int errno; // or perhaps "enum EErrno errno" int value; }; ReturnValue read( int fd, char* buf, size_t size ); // hmm, can you access a member of the result of a function call? if (!read( filedesc, buffer, size ).success) { printf("read failed, sucks to be you...\n" ); } This assumes that a lot of functions can use this common return value structure, but I think that's reasonable: it tells whether or not the function succeeded, why it failed if it failed, and what/how much it accomplished if it succeeded. You could roll the bool and the errno together, or make the bool a method instead of a datum: bool success( void ) { errno == EErrno_NoError; } -RB
Aug 20 2001
parent reply "Richard Krehbiel" <rich kastle.com> writes:
"Russell Bornschlegel" <kaleja estarcion.com> wrote in message
news:3B81DC85.7321FD3E estarcion.com...
   // hmm, can you access a member of the result of a function call?
   if (!read( filedesc, buffer, size ).success)
   {
      printf("read failed, sucks to be you...\n" );
   }

I just tested this, and it compiled and worked. typedef struct multi { int a, b, c; } M; M sub(void) { M a; a.a = 1; a.b = 2; a.c = 3; return a; } int main(int argc, char *argv[]) { M res; if((res = sub()).a == 1) printf("OK, %d, %d, %d\n", res.a, res.b, res.c); return 0; }
Aug 21 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Richard Krehbiel wrote:
 
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B81DC85.7321FD3E estarcion.com...
   // hmm, can you access a member of the result of a function call?
   if (!read( filedesc, buffer, size ).success)
   {
      printf("read failed, sucks to be you...\n" );
   }

I just tested this, and it compiled and worked. [snip example]

In C, no less! Will wonders never cease. (What compiler was that, by the way?) So, I repeat the question: is returning a struct from a commonly used library routine such an ugly construct that we need to come up with a better way to handle the return of multiple values from a function? -RB
Aug 21 2001
next sibling parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"Russell Bornschlegel" <kaleja estarcion.com> wrote in message
news:3B82917B.FB34BD40 estarcion.com...
 Richard Krehbiel wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B81DC85.7321FD3E estarcion.com...
   // hmm, can you access a member of the result of a function call?
   if (!read( filedesc, buffer, size ).success)
   {
      printf("read failed, sucks to be you...\n" );
   }

I just tested this, and it compiled and worked. [snip example]

In C, no less! Will wonders never cease. (What compiler was that, by the way?) So, I repeat the question: is returning a struct from a commonly used library routine such an ugly construct that we need to come up with a better way to handle the return of multiple values from a function?

You cannot guarantee that all fields of a struct are populated. You have to have different structs for different kinds of functions, making the number of types you have to learn to use system functions much larger (plus this multiplies per user function which has a different struct return type) And YES it is *UGLY* =) Peter.
Aug 21 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
kaffiene wrote:
 
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.
 You have to have different structs for different kinds of functions, making
 the number of types you have to learn to use system functions much larger
 (plus this multiplies per user function which has a different struct return
 type)

This point is granted; you can define your APIs in such a way that the number of return-struct types is minimized, however.
 And YES it is *UGLY* =)

Well, I'm not thrilled with: numCats,numDogs,numFerrets,numGoats = CountAnimals(); ...either. I think the parser would want at least some sort of marker around the return list, also, something like: [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); {numCats, numDogs, numFerrets, numGoats} = CountAnimals(); (numCats, numDogs, numFerrets, numGoats) = CountAnimals(); <numCats, numDogs, numFerrets, numGoats> = CountAnimals(); [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); `numCats, numDogs, numFerrets, numGoats` = CountAnimals(); \numCats, numDogs, numFerrets, numGoats\ = CountAnimals(); Eeech. -RB
Aug 21 2001
next sibling parent "Sheldon Simms" <sheldon semanticedge.com> writes:
Im Artikel <3B82E1F6.851406A estarcion.com> schrieb "Russell Bornschlegel"
<kaleja estarcion.com>:

 kaffiene wrote:
 
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly used
 library routine such an ugly construct that we need to come up with a
 better way to handle the return of multiple values from a function?


Give it a constructor.
 You have to have different structs for different kinds of functions,
 making the number of types you have to learn to use system functions
 much larger (plus this multiplies per user function which has a
 different struct return type)

This point is granted; you can define your APIs in such a way that the number of return-struct types is minimized, however.
 And YES it is *UGLY* =)

Well, I'm not thrilled with: numCats,numDogs,numFerrets,numGoats = CountAnimals(); ...either. I think the parser would want at least some sort of marker around the return list, also, something like: [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); {numCats, numDogs, numFerrets, numGoats} = CountAnimals(); (numCats, numDogs, numFerrets, numGoats) = CountAnimals(); <numCats, numDogs, numFerrets, numGoats> = CountAnimals(); [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); `numCats, numDogs, numFerrets, numGoats` = CountAnimals(); \numCats, numDogs, numFerrets, numGoats\ = CountAnimals(); Eeech.

I dunno. In the following: (cats, dogs, ferrets, goats) = CountAnimals(zoo, pound, farm, petshop); Why is the parenthesis-bounded list of returned variables uglier than the parenthesis-bounded list of function arguments? -- Sheldon Simms / sheldon semanticedge.com
Aug 21 2001
prev sibling next sibling parent reply Russ Lewis <russ deming-os.org> writes:
Russell Bornschlegel wrote:

 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

Remember that in D structs are NOT classes, so they don't have constructors or other member functions. You can define default initializers for all of the members, though.
Aug 21 2001
parent reply Russell Bornschlegel <kaleja estarcion.com> writes:
Russ Lewis wrote:
 
 Russell Bornschlegel wrote:
 
 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

Remember that in D structs are NOT classes, so they don't have constructors or other member functions. You can define default initializers for all of the members, though.

/me rolls eyes Sorry. Make the return type a class. -RB
Aug 21 2001
parent "kaffiene" <kaffiene xtra.co.nz> writes:
"Russell Bornschlegel" <kaleja estarcion.com> wrote in message
news:3B82FFBA.BB5CB70D estarcion.com...
 Russ Lewis wrote:
 Russell Bornschlegel wrote:

 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

Remember that in D structs are NOT classes, so they don't have


 other member functions.  You can define default initializers for all of


 members, though.

/me rolls eyes Sorry. Make the return type a class.

then you can't guarantee that the class has a constructor for user functions which implement this pattern
Aug 21 2001
prev sibling next sibling parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"Russell Bornschlegel" <kaleja estarcion.com> wrote in message
news:3B82E1F6.851406A estarcion.com...
 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

You can guarantee the struct has initialisers (or constructors if D had them for structs) on user functions. The compiler can guarantee a binding for returned values from *all* functions.
 You have to have different structs for different kinds of functions,


 the number of types you have to learn to use system functions much


 (plus this multiplies per user function which has a different struct


 type)

This point is granted; you can define your APIs in such a way that the number of return-struct types is minimized, however.
 And YES it is *UGLY* =)

Well, I'm not thrilled with: numCats,numDogs,numFerrets,numGoats = CountAnimals(); ...either. I think the parser would want at least some sort of marker around the return list, also, something like: [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); {numCats, numDogs, numFerrets, numGoats} = CountAnimals(); (numCats, numDogs, numFerrets, numGoats) = CountAnimals(); <numCats, numDogs, numFerrets, numGoats> = CountAnimals(); [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); `numCats, numDogs, numFerrets, numGoats` = CountAnimals(); \numCats, numDogs, numFerrets, numGoats\ = CountAnimals();

No - a compiler can do: a,b = myfunc(x); No problem at all - there is no reason you have have markers around the return list. Peter.
Aug 21 2001
next sibling parent reply Russ Lewis <russ deming-os.org> writes:
kaffiene wrote:

 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82E1F6.851406A estarcion.com...
 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

You can guarantee the struct has initialisers (or constructors if D had them for structs) on user functions. The compiler can guarantee a binding for returned values from *all* functions.
 You have to have different structs for different kinds of functions,


 the number of types you have to learn to use system functions much


 (plus this multiplies per user function which has a different struct


 type)

This point is granted; you can define your APIs in such a way that the number of return-struct types is minimized, however.
 And YES it is *UGLY* =)

Well, I'm not thrilled with: numCats,numDogs,numFerrets,numGoats = CountAnimals(); ...either. I think the parser would want at least some sort of marker around the return list, also, something like: [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); {numCats, numDogs, numFerrets, numGoats} = CountAnimals(); (numCats, numDogs, numFerrets, numGoats) = CountAnimals(); <numCats, numDogs, numFerrets, numGoats> = CountAnimals(); [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); `numCats, numDogs, numFerrets, numGoats` = CountAnimals(); \numCats, numDogs, numFerrets, numGoats\ = CountAnimals();

No - a compiler can do: a,b = myfunc(x);

Actually, the compiler will mis-recognize that as a compound statement: a , b = myfunc(x);
Aug 21 2001
parent reply "kaffiene" <kaffiene xtra.co.nz> writes:
"Russ Lewis" <russ deming-os.org> wrote in message
news:3B82EEBD.BAB2CA67 deming-os.org...
 kaffiene wrote:

 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82E1F6.851406A estarcion.com...
 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

You can guarantee the struct has initialisers (or constructors if D had


 for structs) on user functions.  The compiler can guarantee a binding


 returned values from *all* functions.

 You have to have different structs for different kinds of functions,


 the number of types you have to learn to use system functions much


 (plus this multiplies per user function which has a different struct


 type)

This point is granted; you can define your APIs in such a way that the number of return-struct types is minimized, however.
 And YES it is *UGLY* =)

Well, I'm not thrilled with: numCats,numDogs,numFerrets,numGoats = CountAnimals(); ...either. I think the parser would want at least some sort of marker around the return list, also, something like: [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); {numCats, numDogs, numFerrets, numGoats} = CountAnimals(); (numCats, numDogs, numFerrets, numGoats) = CountAnimals(); <numCats, numDogs, numFerrets, numGoats> = CountAnimals(); [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); `numCats, numDogs, numFerrets, numGoats` = CountAnimals(); \numCats, numDogs, numFerrets, numGoats\ = CountAnimals();

No - a compiler can do: a,b = myfunc(x);

Actually, the compiler will mis-recognize that as a compound statement: a , b = myfunc(x);

What I am saying is that you can write a compiler to recognise that - have you ever used yacc or bison? Peter.
Aug 21 2001
parent Russ Lewis <russ deming-os.org> writes:
kaffiene wrote:

 "Russ Lewis" <russ deming-os.org> wrote in message
 news:3B82EEBD.BAB2CA67 deming-os.org...
 kaffiene wrote:

 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82E1F6.851406A estarcion.com...
 kaffiene wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B82917B.FB34BD40 estarcion.com...
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

You can guarantee the struct has initialisers (or constructors if D had


 for structs) on user functions.  The compiler can guarantee a binding


 returned values from *all* functions.

 You have to have different structs for different kinds of functions,


 the number of types you have to learn to use system functions much


 (plus this multiplies per user function which has a different struct


 type)

This point is granted; you can define your APIs in such a way that the number of return-struct types is minimized, however.
 And YES it is *UGLY* =)

Well, I'm not thrilled with: numCats,numDogs,numFerrets,numGoats = CountAnimals(); ...either. I think the parser would want at least some sort of marker around the return list, also, something like: [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); {numCats, numDogs, numFerrets, numGoats} = CountAnimals(); (numCats, numDogs, numFerrets, numGoats) = CountAnimals(); <numCats, numDogs, numFerrets, numGoats> = CountAnimals(); [numCats, numDogs, numFerrets, numGoats] = CountAnimals(); `numCats, numDogs, numFerrets, numGoats` = CountAnimals(); \numCats, numDogs, numFerrets, numGoats\ = CountAnimals();

No - a compiler can do: a,b = myfunc(x);

Actually, the compiler will mis-recognize that as a compound statement: a , b = myfunc(x);

What I am saying is that you can write a compiler to recognise that - have you ever used yacc or bison? Peter.

No, I haven't used either, though from what I've heard they're very good. Sorry to misunderstand - I thought that you meant that it would be an easy addition to the language as-is.
Aug 21 2001
prev sibling parent "kaffiene" <kaffiene xtra.co.nz> writes:
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

You cannot guarantee that all fields of a struct are populated.

Give it a constructor.

You can guarantee the struct has initialisers (or constructors if D had

 for structs) on user functions.  The compiler can guarantee a binding for
 returned values from *all* functions.

oops! that should have been "... cannot guarantree the struct has initialisers..." sorry =) Peter.
Aug 21 2001
prev sibling parent reply Teemu Hirsimaki <Teemu.Hirsimaki hut.fi> writes:
Russell Bornschlegel <kaleja estarcion.com> writes:

 Well, I'm not thrilled with:
 
    numCats,numDogs,numFerrets,numGoats = CountAnimals();

For example, if we are calling CountAnimals inside a member function, and want to set the return values in miscellanous member variables, it will be quite clumsy to make a seperate class the return values. I like the Perl way: (foo, bar) = func(); This would be very useful. -- Teemu Hirsimäki
Aug 22 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
Teemu Hirsimaki wrote:
 
 Russell Bornschlegel <kaleja estarcion.com> writes:
 
 Well, I'm not thrilled with:

    numCats,numDogs,numFerrets,numGoats = CountAnimals();

For example, if we are calling CountAnimals inside a member function, and want to set the return values in miscellanous member variables, it will be quite clumsy to make a seperate class the return values. I like the Perl way: (foo, bar) = func(); This would be very useful. -- Teemu Hirsimäki

It's also nicer when you want the returned data in certain variables ratherthan a struct. Less copying than. ret_t ret = func(); foo = ret.f; bar = ret.b; Dan
Aug 25 2001
parent reply Florian Weimer <Florian.Weimer RUS.Uni-Stuttgart.DE> writes:
Dan Hursh <hursh infonet.isl.net> writes:

 (foo, bar) = func();


 It's also nicer when you want the returned data in certain variables
 ratherthan a struct.  Less copying than.
 
 ret_t ret = func();
 foo = ret.f;
 bar = ret.b;

The problem with the first approach is the following: It is not clear if you have to write: (write_end, read_end) = Create_Pipe(); Or: (read_end, write_end) = Create_Pipe(); In general, I don't think it's a good idea to trade readability for terseness. -- Florian Weimer Florian.Weimer RUS.Uni-Stuttgart.DE University of Stuttgart http://cert.uni-stuttgart.de/ RUS-CERT +49-711-685-5973/fax +49-711-685-5898
Aug 25 2001
parent reply Dan Hursh <hursh infonet.isl.net> writes:
Florian Weimer wrote:
 
 Dan Hursh <hursh infonet.isl.net> writes:
 
 (foo, bar) = func();


 It's also nicer when you want the returned data in certain variables
 ratherthan a struct.  Less copying than.

 ret_t ret = func();
 foo = ret.f;
 bar = ret.b;

The problem with the first approach is the following: It is not clear if you have to write: (write_end, read_end) = Create_Pipe(); Or: (read_end, write_end) = Create_Pipe(); In general, I don't think it's a good idea to trade readability for terseness.

And it's clearer when it's: Create_Pipe(write_end, read_end); Or: Create_Pipe(read_end, write_end); I guess I'd really like the ability to choose between returning a list of values to a set of variables, an array, or a struct with the correct members. They are all useful sometimes, but not of them feel right in all cases. This is mostly aesthetics though. Weather it's function return values though or function parameters you still have to know what order they are. (Unless we use named parameters. That doesn't look likely.) At least with you two examples it would be easier to tell what is input and what is output. The function name just becomes a glorified infix operator between a list of input values (on the right) and output locations (on the left). Of course, as soon as you do this sort of syntax, someone will ask for the ability to overload based on return list types. Suddenly you would have to keep track of calling context or some such thing. I would be nice, but against the D way of doing things. Dan
Aug 25 2001
parent Florian Weimer <Florian.Weimer RUS.Uni-Stuttgart.DE> writes:
Dan Hursh <hursh infonet.isl.net> writes:

 In general, I don't think it's a good idea to trade readability for
 terseness.

And it's clearer when it's: Create_Pipe(write_end, read_end); Or: Create_Pipe(read_end, write_end);

Some people prefer: Create_Pipe (Write_End => Write_End_Var, Read_End => Read_End_Var); (Named parameter associations, 'Write_End' is the name of the formal parameter in the declaration of 'Create_Pipe'). ;-) -- Florian Weimer Florian.Weimer RUS.Uni-Stuttgart.DE University of Stuttgart http://cert.uni-stuttgart.de/ RUS-CERT +49-711-685-5973/fax +49-711-685-5898
Aug 27 2001
prev sibling parent reply Christophe de Dinechin <descubes earthlink.net> writes:
It's not ugly, but it's infrequent enough that most compilers generate
inefficient code for that. Hence people don't use it. Catch 22.

Typically, you get a lot of extra copies while returning a struct (at
least one, sometimes 2). LX tries to solve that with the "result"
pseudo-variable.

Christophe

Russell Bornschlegel wrote:

 Richard Krehbiel wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B81DC85.7321FD3E estarcion.com...
   // hmm, can you access a member of the result of a function call?
   if (!read( filedesc, buffer, size ).success)
   {
      printf("read failed, sucks to be you...\n" );
   }

I just tested this, and it compiled and worked. [snip example]

In C, no less! Will wonders never cease. (What compiler was that, by the way?) So, I repeat the question: is returning a struct from a commonly used library routine such an ugly construct that we need to come up with a better way to handle the return of multiple values from a function? -RB

Aug 22 2001
next sibling parent "Richard Krehbiel" <rich kastle.com> writes:
"Christophe de Dinechin" <descubes earthlink.net> wrote in message
news:3B841E54.D4D364A9 earthlink.net...
 Russell Bornschlegel wrote:
 So, I repeat the question: is returning a struct from a commonly
 used library routine such an ugly construct that we need to come
 up with a better way to handle the return of multiple values from
 a function?

It's not ugly, but it's infrequent enough that most compilers generate inefficient code for that. Hence people don't use it. Catch 22. Typically, you get a lot of extra copies while returning a struct (at least one, sometimes 2). LX tries to solve that with the "result" pseudo-variable.

GCC also offers that extension. struct bigstruct func(void) return bs { bs.a = 0; // ... whatever... return; } When I first saw that, I wondered if the compiler could optimize-away the extra copying away. I recall that Lattice C for the Amiga ASM calling conventions specified that to call a function which returns a struct, the caller passes in the address where the function should place the struct. The called function could build the return value right there (using the "result" spec, or by compiler optimization). And in fact, the compiler may have optimized "struct T a; a = func();" by calling func() giving a pointer to a, resulting in *no* struct copying. -- Richard Krehbiel, Arlington, VA, USA rich kastle.com (work) or krehbiel3 home.com (personal)
Aug 23 2001
prev sibling parent "Walter" <walter digitalmars.com> writes:
The DM compiler doesn't do extra copies.

Christophe de Dinechin wrote in message <3B841E54.D4D364A9 earthlink.net>...
It's not ugly, but it's infrequent enough that most compilers generate
inefficient code for that. Hence people don't use it. Catch 22.

Typically, you get a lot of extra copies while returning a struct (at
least one, sometimes 2). LX tries to solve that with the "result"
pseudo-variable.

Christophe

Russell Bornschlegel wrote:

 Richard Krehbiel wrote:
 "Russell Bornschlegel" <kaleja estarcion.com> wrote in message
 news:3B81DC85.7321FD3E estarcion.com...
   // hmm, can you access a member of the result of a function call?
   if (!read( filedesc, buffer, size ).success)
   {
      printf("read failed, sucks to be you...\n" );
   }

I just tested this, and it compiled and worked. [snip example]

In C, no less! Will wonders never cease. (What compiler was that, by the way?) So, I repeat the question: is returning a struct from a commonly used library routine such an ugly construct that we need to come up with a better way to handle the return of multiple values from a function? -RB


Oct 10 2001
prev sibling parent reply Christophe de Dinechin <descubes earthlink.net> writes:
Another issue with that is: what happens if you use it as a function argument
(that is, f(g()), where g() return 4 things)? Does this give 4 arguments to
f(), or is it simply forbidden?

Christophe

Bradeeoh wrote:

 countAnimals() returns (int cats, int dogs, int ferrets, int goats)
 {
     ....
 }


 I prefer the latter.  Anyone else really like it?  Hate it?

That is intriguing. Definately clear, and it could be reasonably useful. I have a couple of nitpicks, one major and one minor. Major - what is the formal return type of this function? I notice you just wrote - countAnimals() returns (int.......goats) there is nothing before the function name. Granted, the return type is implicitly 4 integers, but I think one of the things (possibly) holding this feature back is that 4 integers is neither a primitive data type, nor a class/struct/union type. It's just.... 4... different primitive data types. If you can give a formal, simple definition as to the return type of the function, it may be worth looking into and could end up being something incredibly useful. ;) The minor nitpick - A number of ways to do this just ran through my head, but I noticed you haven't touched on the point at all - what is the syntax of return the values within the function? I'm sure you're thinking something as simple as "return (cats,dogs,ferrets,goats);" but, of course, that may also not be as simple as it seems.... ;) -Brady

Aug 20 2001
parent "kaffiene" <kaffiene xtra.co.nz> writes:
"Christophe de Dinechin" <descubes earthlink.net> wrote in message
news:3B80D256.4DC6BEE8 earthlink.net...
 Another issue with that is: what happens if you use it as a function

 (that is, f(g()), where g() return 4 things)? Does this give 4 arguments

 f(), or is it simply forbidden?

There are two obvious answers - either allow it only if the number of return values from g() matches the number of parameters to f() or disallow it on principle. You could argue that there are pros and cons each way. I don't think it matters much as long as the compiler knows which one it's doing ;-) Peter.
 Bradeeoh wrote:

 countAnimals() returns (int cats, int dogs, int ferrets, int goats)
 {
     ....
 }


 I prefer the latter.  Anyone else really like it?  Hate it?

That is intriguing. Definately clear, and it could be reasonably


 have a couple of nitpicks, one major and one minor.  Major - what is the
 formal return type of this function?  I notice you just wrote -
 countAnimals() returns (int.......goats)

 there is nothing before the function name.  Granted, the return type is
 implicitly 4 integers, but I think one of the things (possibly) holding


 feature back is that 4 integers is neither a primitive data type, nor a
 class/struct/union type.  It's just.... 4... different primitive data


 If you can give a formal, simple definition as to the return type of the
 function, it may be worth looking into and could end up being something
 incredibly useful.  ;)

 The minor nitpick - A number of ways to do this just ran through my


 but I noticed you haven't touched on the point at all - what is the


 of return the values within the function?

 I'm sure you're thinking something as simple as "return
 (cats,dogs,ferrets,goats);" but, of course, that may also not be as


 as it seems....  ;)

 -Brady


Aug 20 2001
prev sibling parent reply "Angus Graham" <agraham_d agraham.ca> writes:
"Grobbins" <grobbins badaddress.znet.com> wrote:

 I think this is a much better idea than in, out and inout
 parameters.  Given something like this:
 int a,b,x;
 a,b = myfunc(x);
 it's obvious the role that a,b and x play

While multiple return parameters seem elegant, you end up with code that is harder to read and maintain. Consider int,int,int,int CountAnimals(); which is called numCats,numDogs,numFerrets,numGoats = CountAnimals(); Without parameter names attached to the output values in the declaration, it's hard to know if I've picked up the return values correctly.

Then why not int numCats, int numDogs, int numFerrets, int numGoats CountAnimals() { if(m_ThisPlaceIsAPound) { numCats = 10; numDogs = 13; numFerrets = 1; numGoats = 0; return; } else if(m_ThisPlaceIsAPettingZoo) { numCats = 0; numDogs = 0; numFerrets = 1; numGoats = 3; return; } numCats = 0; numDogs = 0; numFerrets = 0; return; // compile time error: not all paths initialize 'numGoats' } What am I missing here? Angus Graham
Aug 20 2001
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Angus Graham wrote:
 ...
 What am I missing here?
 
 Angus Graham
 

But is it useful? In D there are in/out parameters to functions. It's useful for a function to return one value, so that it can be processed in a stream of arithmetic or inheritance. For multiple values? They would seem to clog up this process unless tuples are a part of the language. Use an array return value instead.
Aug 21 2001
parent "Angus Graham" <agraham_d agraham.ca> writes:
"Charles Hixson" <charleshixsn earthlink.net> wrote

 Angus Graham wrote:
 ...
 What am I missing here?

 Angus Graham

But is it useful?

Not less useful than i/o parameters
 In D there are in/out parameters to functions.

Which suffer from the problem stated above - you can't tell from looking at a call which is which. I suggest not having both, but replacing i/o params with this system.
 It's useful for a function to return one value, so that it can be
 processed in a stream of arithmetic or inheritance.  For multiple
 values?  They would seem to clog up this process unless tuples are a
 part of the language.  Use an array return value instead.

I wouldn't be in favour of tuples, but you could still use one of the multiple return values in arithmetic operations: In c, the ',' operator evaluates its args left to right and takes on the value of the right operand. Multiple arguments returned from functions would be "comma'd" just as if you had written them out with the regular comma operator. Thus: ERROR e; int items; items = (e, items = row->get_items()) + 1; would add 1 to the int returned by row->get_items() and retrieve an error as a bonus. items = row->get_items() + 1; would do the same thing, except the error would be put a temporary, not assigned anywhere and lost. You could pass the result to a function that takes only one argument: row->set_items(row->get_items() + 1); Angus Graham
Aug 21 2001