D - Multiple returns / was: x, y, z = 0
- Christian Schüler (12/12) May 29 2002 I'm moving this discussion to a new thread.
- Pavel Minayev (8/10) May 29 2002 And how do you want this to be implemented? Lua is a bytecode
- Russ Lewis (13/14) May 29 2002 I keep forgetting about those!
- Christian Schüler (40/43) May 29 2002 Yes, that's the point. I was thinking about it how such a feature could ...
- Pavel Minayev (22/35) May 29 2002 D does not use the C calling convention (not always, at least). So
- anderson (37/74) May 30 2002 I think it's a cool idea,
- Pavel Minayev (3/4) May 30 2002 No, and I hope it never will.
- anderson (3/7) May 31 2002 Can you explain your POV? I apparently missed it.
- Pavel Minayev (6/11) May 31 2002 Function overloading based on return type is a complex, hardly predictab...
- anderson (6/18) Jun 01 2002 But if one can use out to imitated it, why not use the same rules for th...
- Pavel Minayev (22/24) Jun 01 2002 Out arguments cannot be typecasted:
- anderson (5/29) Jun 02 2002 the
- anderson (3/5) Jun 02 2002 Sorry I ment
- Pavel Minayev (8/10) Jun 02 2002 Yes. I don't want to perform a cast each time I assign a value returned
- anderson (16/26) Jun 02 2002 I hate to keep this subject up, but have you considered explicit
- anderson (15/15) Jun 02 2002 (Just fixed some grammar)
- Pavel Minayev (5/10) Jun 03 2002 Then, this should be applied to parameter overloading, for consistency.
- anderson (17/22) Jun 03 2002 I agree, that way you know instantaly that something has been overloaded...
- Pavel Minayev (19/19) Jun 03 2002 Just a thought to extend the idea further.
- anderson (54/73) Jun 03 2002 I was thinking along the same lines, but I couldn't get it into words an...
- anderson (11/91) Jun 03 2002 Fix
- Pavel Minayev (27/54) Jun 03 2002 triggered,
- Sean L. Palmer (16/30) Jun 03 2002 I kind of like this use of explicit. Would it be better than this?
- Walter (8/16) Jun 12 2002 What Pavel's referring to are the default integral promotion rules, whic...
- Karl Bochert (31/50) May 30 2002 Compared to what else the compiler must do, this seems trivial.
- Pavel Minayev (5/7) May 30 2002 Not really. I guess those guys were just too lazy to cover this
- Christian Schüler (59/111) May 30 2002 I thought that the caller would leave the space on the stack to hold the
- Pavel Minayev (5/14) May 31 2002 Yes, you've convinced me... it's all simplier than I thought. Practicall...
- Martin M. Pedersen (11/17) May 30 2002 Hi,
- Pavel Minayev (10/16) May 30 2002 C
- Walter (5/11) Jun 13 2002 C
I'm moving this discussion to a new thread. What about multiple return values, like in LUA: --- LUA code begin --- function foo() return 1, 2, 3 end a, b, c = foo() function bar( x, y, z ) return x + y + z end sum = bar( foo() ) --- LUA code end ---
May 29 2002
Pavel Minayev wrote:BTW, out-parameters are supposed to exist for such cases =)I keep forgetting about those! Hey Walter, is there any way to omit an out parameter? Of course, inout parameters are required...but there any way to skip an out parameter? I'd hate to make a temp variable whenever there was an out parameter I didn't use. This would probably require the compiler to declare a temporary for you on the stack, and pass that as the out parameter...but better the compiler than me, I always say! :) -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]May 29 2002But I don't think you can easily do it in a language which compiles to native code.Yes, that's the point. I was thinking about it how such a feature could be implemented. Let's suppose you can declare a function to have multiple returns in a compiled language (like C or D): int, int, int foo() { return 1, 2, 3; } If this function was to be compiled into assembler, it would leave, on the stack, three integers. There's basically nothing wrong with that, as the caller is responsible for cleaning up the stack, and, through the function prototype, it is known at compile time what return values a function leaves. (Think as an alternative that the function foo() would have returned a structure containing 3 integers, pretty legal in C++). Now suppose that the assignment operator = is a function that can take an arbitrary number of parameters, not just one. Let's suppose the assignment operator is declared as: inline operator =( ... ) That is, the assignment operator can take any number of parameters, from the stack. If there is written: int a, b, c; a, b, c = foo(); the assignment operator takes the 3 values from the stack that the function foo() has left, assigning them to a, b and c. The compiler would have to make sure, at compile time, that the number and the types of the arguments match. Of course, in the final implementation when the language is optimized, things doesn't take the detour via the physical stack, but this view is helpful in understanding whats going on. With this in mind, the forwarding of multiple return values as function parameters is a no-brainer: int bar( int x, int y, int z ) { return x + y + z; } int sum = bar( foo() ); The function bar() takes three parameters, which must be pushed onto the stack before calling the function. Instead of pushing single arguments, they could pretty much be left behind from the call to the function foo(). Again the compiler will check at compile time from the prototypes that everything matches together. Thoughts, anyone?May 29 2002I think it's a cool idea, I staying away from the ASM part. int, int, int a() { ... return x,y,z; } interprate the same as int a(int out c, int out d) { ... return x,y,z; //for all out params } interprate which would interparte to int a(int out c, int out d) { ... c = y; d = z; return x; } or alternativly make it the same as doing, {int a, int b , int c} a() { ... return {x,y,z}; } If speed is a concern users can just use the single version (but they'd probably end up using one of the later algorithms anyways) , because speed is not an issue in all parts of a problem. PS - Does D allow for overloading of return types? "Pavel Minayev" <evilone omen.ru> wrote in message news:ad4djm$8na$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:ad5clq$1jm8$1 digitaldaemon.com...PS - Does D allow for overloading of return types?No, and I hope it never will.May 30 2002"Pavel Minayev" <evilone omen.ru> wrote in message news:ad5kma$2bro$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:ad5clq$1jm8$1 digitaldaemon.com...Can you explain your POV? I apparently missed it.PS - Does D allow for overloading of return types?No, and I hope it never will.May 31 2002"anderson" <anderson firestar.com.au> wrote in message news:ad9bos$12oh$1 digitaldaemon.com...Function overloading based on return type is a complex, hardly predictable feature, especially in a Cish weak type environment used by D. I think it adds more confusion than benefits. And, after all, one may always use out parameters to imitate it...Can you explain your POV? I apparently missed it.PS - Does D allow for overloading of return types?No, and I hope it never will.May 31 2002But if one can use out to imitated it, why not use the same rules for the return type? Why do we need to use workarounds to do the same thing? I would be inclined to agree with you if your argment was stronger. "Pavel Minayev" <evilone omen.ru> wrote in message news:ad9qlf$1iue$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:ad9bos$12oh$1 digitaldaemon.com...outFunction overloading based on return type is a complex, hardly predictable feature, especially in a Cish weak type environment used by D. I think it adds more confusion than benefits. And, after all, one may always useCan you explain your POV? I apparently missed it.PS - Does D allow for overloading of return types?No, and I hope it never will.parameters to imitate it...Jun 01 2002"anderson" <anderson firestar.com.au> wrote in message news:adag2i$e2q$1 digitaldaemon.com...But if one can use out to imitated it, why not use the same rules for the return type? Why do we need to use workarounds to do the same thing?Out arguments cannot be typecasted: void foo(out short n); void foo(out byte n); ... int n; foo(n); // error! You cannot cast it to short, or do something else like that. Function wants a short oR byte, and you have to provide it a short or byte. Ambiguity is impossible. Now, if we had overloading based on return arguments, we'd have this: short foo(); byte foo(); ... int n; n = foo(); // which version is called? A headache for both the compiler (to find out such cases), and the developer. Okay, so this case is simple, but call to foo() might have happened in a complex expression, and due to the weak nature of D type system, many type conversions could happen, so it is hard to tell the desired type for the return value of foo() at some point.Jun 01 2002"Pavel Minayev" <evilone omen.ru> wrote in message news:adak4l$j29$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:adag2i$e2q$1 digitaldaemon.com...theBut if one can use out to imitated it, why not use the same rules forOk, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak return types?return type? Why do we need to use workarounds to do the same thing?Out arguments cannot be typecasted: void foo(out short n); void foo(out byte n); ... int n; foo(n); // error! You cannot cast it to short, or do something else like that. Function wants a short oR byte, and you have to provide it a short or byte. Ambiguity is impossible. Now, if we had overloading based on return arguments, we'd have this: short foo(); byte foo(); ... int n; n = foo(); // which version is called? A headache for both the compiler (to find out such cases), and the developer. Okay, so this case is simple, but call to foo() might have happened in a complex expression, and due to the weak nature of D type system, many type conversions could happen, so it is hard to tell the desired type for the return value of foo() at some point.Jun 02 2002Sorry I ment Ok, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak typing for return?Ok, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak return types?Jun 02 2002"anderson" <anderson firestar.com.au> wrote in message news:adck5l$2mun$1 digitaldaemon.com...Ok, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak typing for return?Yes. I don't want to perform a cast each time I assign a value returned by a double function to int. BTW, this applies not only to the return statement, but to the entire system. It's not Java, and it's another reason why I like D. ... now if we only didn't need cast to assign a void* pointer to something else (like in C) ...Jun 02 2002I hate to keep this subject up, but have you considered explicit overloading? With explicit overloading, the function used will default to the default function, unless an explicit one has been defined specifically for that type. ie double sqrt(int val) {}; explicit float sqrt(int val) {}; explicit int sqrt(int val) {}; Therefore if a short is given, it will default to the double method, but if a float is given it will use the explicit type. The programmer can optimise the float and int methods for better performance. Of cause there are some disadvantages of this to true overloading (having do explicit more types), but It kind meets halfway. "Pavel Minayev" <evilone omen.ru> wrote in message news:adcv46$31cl$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:adck5l$2mun$1 digitaldaemon.com...Ok, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak typing for return?Yes. I don't want to perform a cast each time I assign a value returned by a double function to int. BTW, this applies not only to the return statement, but to the entire system. It's not Java, and it's another reason why I like D. ... now if we only didn't need cast to assign a void* pointer to something else (like in C) ...Jun 02 2002(Just fixed some grammar) I hate to keep this subject going, but have you considered explicit overloading? With explicit overloading, the function used will use the default function, unless an explicit one has been defined specifically for that type. ie double sqrt(int val) {}; explicit float sqrt(int val) {}; explicit int sqrt(int val) {}; Therefore if a short is given, it will default to the double method, but if a float is given it will use the explicit type. The programmer can optimise the float and int methods for better performance. Of cause there are some disadvantages of this to true overloading (having do explicit for more types), but it kind'a meets halfway.Jun 02 2002"anderson" <anderson firestar.com.au> wrote in message news:adeqr9$8lt$1 digitaldaemon.com...I hate to keep this subject going, but have you considered explicit overloading? With explicit overloading, the function used will use the default function, unless an explicit one has been defined specifically for that type.Then, this should be applied to parameter overloading, for consistency. But in this form, it is possible. I guess you've convinced me, now you should do the same to Walter... =)Jun 03 2002"Pavel Minayev" <evilone omen.ru> wrote in message news:adf70n$o09$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:adeqr9$8lt$1 digitaldaemon.com... Then, this should be applied to parameter overloading, for consistency.I agree, that way you know instantaly that something has been overloaded and there's no ambiguity. Also I don't think it would cause many hard ackes in porting overloads because the compiler would report an error. Then the programmer would simply had explicit to the overloads, and in the odd cases where D casting coversion is differn't, they'd simply add another explicit. Perhaps a different term/keyword then "explicit" (I'm fine with explicit). Any suggestions? Here are mine: overload explic oload, (but I don't like, overl)But in this form, it is possible. I guess you've convinced me, nowThanks, I do think overloading can be a rather powerful tool in reducting libary complexity.you should do the same to Walter... =)You seem to be the best at that! ;) (Not that I'm asking you to do anything.)Jun 03 2002Just a thought to extend the idea further. What if it would be possible to tell the compiler, arguments of which type does this function expect. The syntax could be something like this: long abs(long cast(byte, short, int) n); extended abs(extended cast(float, double) n); These two lines declare _two_ abs() functions, one taking a long argument, another takes extended. However, for types byte, short and int, first version is called (and argument is cast to long), and for float and double, the second version is called. This is essentially the same as if there was a set of overloaded functions: long abs(long n); long abs(int n) { return abs(cast(long) n); } long abs(short n) { return abs(cast(long) n); } long abs(byte n) { return abs(cast(long) n); } Only shorter, and the compiler might decide not to use inline wrappers, but to resolve ambiguity just by looking at the list of possible types for each argument. What do you think? P.S. The same could be applied to return type as well...Jun 03 2002I was thinking along the same lines, but I couldn't get it into words and you brought it up. I think it's an excellent idea. The only problem I can see with this is that we don't want to make the programmer go to have to type to much to overload. What about these problems to solve, Declared in module 1 long abs(long cast(byte, short, int) n); Declared in module 2 extended abs(extended cast(int ,float, double) n); So I suppose in this situtation a complier error message would be triggered, if two overloads shared the same type. But a better Idea would be to use module 2 for the int in it's local space. It'd also be good to have an alternative method to save on typing extended abs(extended allbut(int) n); //Would do everything except int values Extending some of my orignal ideas. If a function is deleared without a in built cast it becomes default. You can overwrite (not overload) a default function for local use (like you can already). You cannot however overwrite a default function twice in the same local space. If a function contains the cast word then it is explictly saying to overload those values. You can overwrite (not overload) a cast function for local use. You cannot however overwrite a cast for the same types function twice in the same local space. ie 1 -Wrong Module 1 long abs(long n); (default function) //OK works in local space long abs(int n); (default function) //ERROR, cannot overwrite must cast ie 2 -Correct Module 1 long abs(long n); //(default function) //OK works in local space Module 2 long abs(int n); //(default function) //OK works in local space ie 3 Module 1 long abs(long n); //(default function) //OK works in local space Module 2 long abs(int n); //(default function) long abs(int cast(int, long) n); //(cast function) long abs(int cast(int, double) n); //ERROR, ambiguus choice available ie 3 Module 1 long abs(long n); //(default function) //OK works in local space long abs(int cast(int, double) n); //OK works in local space Module 2 long abs(int n); //(default function) long abs(int cast(int, long) n); //(cast function) You get the idea though. That's my solution to that problem, you may have already though of that far ahead of me. So of course using your method (which I happen to like), does make things more tricky. "Pavel Minayev" <evilone omen.ru> wrote in message news:adfleq$175n$1 digitaldaemon.com...Just a thought to extend the idea further. What if it would be possible to tell the compiler, arguments of which type does this function expect. The syntax could be something like this: long abs(long cast(byte, short, int) n); extended abs(extended cast(float, double) n); These two lines declare _two_ abs() functions, one taking a long argument, another takes extended. However, for types byte, short and int, first version is called (and argument is cast to long), and for float and double, the second version is called. This is essentially the same as if there was a set of overloaded functions: long abs(long n); long abs(int n) { return abs(cast(long) n); } long abs(short n) { return abs(cast(long) n); } long abs(byte n) { return abs(cast(long) n); } Only shorter, and the compiler might decide not to use inline wrappers, but to resolve ambiguity just by looking at the list of possible types for each argument. What do you think? P.S. The same could be applied to return type as well...Jun 03 2002"anderson" <anderson firestar.com.au> wrote in message news:adg33m$1m4h$1 digitaldaemon.com...I was thinking along the same lines, but I couldn't get it into words and you brought it up. I think it's an excellent idea.Fix The only problem I can see with this is that we don't want to give the programmer a typing overload.What about these problems to solve, Declared in module 1 long abs(long cast(byte, short, int) n); Declared in module 2 extended abs(extended cast(int ,float, double) n); So I suppose in this situtation a complier error message would betriggered,if two overloads shared the same type. But a better Idea would be to use module 2 for the int in it's local space. It'd also be good to have an alternative method to save on typing extended abs(extended allbut(int) n); //Would do everything except int values Extending some of my orignal ideas. If a function is deleared without a in built cast it becomes default. You can overwrite (not overload) a default function for local use (like youcanalready). You cannot however overwrite a default function twice in thesamelocal space. If a function contains the cast word then it is explictly saying tooverloadthose values. You can overwrite (not overload) a cast function for local use. You cannot however overwrite a cast for the same types function twice in the same local space. ie 1 -Wrong Module 1 long abs(long n); (default function) //OK works in local space long abs(int n); (default function) //ERROR, cannot overwrite must cast ie 2 -Correct Module 1 long abs(long n); //(default function) //OK works in local space Module 2 long abs(int n); //(default function) //OK works in local space ie 3 Module 1 long abs(long n); //(default function) //OK works in local space Module 2 long abs(int n); //(default function) long abs(int cast(int, long) n); //(cast function) long abs(int cast(int, double) n); //ERROR, ambiguus choice available ie 3 Module 1 long abs(long n); //(default function) //OK works in local space long abs(int cast(int, double) n); //OK works in local space Module 2 long abs(int n); //(default function) long abs(int cast(int, long) n); //(cast function) You get the idea though. That's my solution to that problem, you may have already though of thatfarahead of me. So of course using your method (which I happen to like), does make things more tricky. "Pavel Minayev" <evilone omen.ru> wrote in message news:adfleq$175n$1 digitaldaemon.com...argument,Just a thought to extend the idea further. What if it would be possible to tell the compiler, arguments of which type does this function expect. The syntax could be something like this: long abs(long cast(byte, short, int) n); extended abs(extended cast(float, double) n); These two lines declare _two_ abs() functions, one taking a longanother takes extended. However, for types byte, short and int, first version is called (and argument is cast to long), and for float and double, the second version is called. This is essentially the same as if there was a set of overloaded functions: long abs(long n); long abs(int n) { return abs(cast(long) n); } long abs(short n) { return abs(cast(long) n); } long abs(byte n) { return abs(cast(long) n); } Only shorter, and the compiler might decide not to use inline wrappers, but to resolve ambiguity just by looking at the list of possible types for each argument. What do you think? P.S. The same could be applied to return type as well...Jun 03 2002"anderson" <anderson firestar.com.au> wrote in message news:adg33m$1m4h$1 digitaldaemon.com...What about these problems to solve, Declared in module 1 long abs(long cast(byte, short, int) n); Declared in module 2 extended abs(extended cast(int ,float, double) n); So I suppose in this situtation a complier error message would betriggered,if two overloads shared the same type. But a better Idea would be to use module 2 for the int in it's local space.If we import both modules into a third one, that we'd have to resolve the naming conflict, using full names anyhow: int a; module1.abs(a); module2.abs(a); If we define AND call abs() from module2, then local declaration shadows out the one from module1. So you won't be able to call abs(byte), for example, unless you provide the full name - module1.abs(byte).It'd also be good to have an alternative method to save on typing extended abs(extended allbut(int) n); //Would do everything except int valuesOr it could be: extended abs(extended !cast(int) n);Extending some of my orignal ideas. If a function is deleared without a in built cast it becomes default. You can overwrite (not overload) a default function for local use (like youcanalready). You cannot however overwrite a default function twice in thesamelocal space. If a function contains the cast word then it is explictly saying tooverloadthose values. You can overwrite (not overload) a cast function for local use. You cannot however overwrite a cast for the same types function twice in the same local space. ie 1 -Wrong Module 1 long abs(long n); (default function) //OK works in local space long abs(int n); (default function) //ERROR, cannot overwrite must castI'd let it be there, just for compatibility, and preserve the current semantics. IMO, it's better to think of cast() as of addition to rather than replacement of current schema of function overloading.Module 2 long abs(int n); //(default function) long abs(int cast(int, long) n); //(cast function)I think this should be an error. IMO, the best idea is to consider such declaration semantically equal to this: long abs(int); long abs(long); Since we already have abs(int) in this module, it should be forbidden. By the way, since n is already int, why list it in the cast clause? It should be implicit.Jun 03 2002"Pavel Minayev" <evilone omen.ru> wrote in message news:adg79p$1r3c$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:adg33m$1m4h$1 digitaldaemon.com...Good IdeaWhat about these problems to solve, Declared in module 1 long abs(long cast(byte, short, int) n); Declared in module 2 extended abs(extended cast(int ,float, double) n); So I suppose in this situtation a complier error message would betriggered,if two overloads shared the same type. But a better Idea would be to use module 2 for the int in it's local space.If we import both modules into a third one, that we'd have to resolve the naming conflict, using full names anyhow: int a; module1.abs(a); module2.abs(a); If we define AND call abs() from module2, then local declaration shadows out the one from module1. So you won't be able to call abs(byte), for example, unless you provide the full name - module1.abs(byte).It'd also be good to have an alternative method to save on typing extended abs(extended allbut(int) n); //Would do everything except int valuesOr it could be: extended abs(extended !cast(int) n);YouExtending some of my orignal ideas. If a function is deleared without a in built cast it becomes default.twicecan overwrite (not overload) a default function for local use (like youcanalready). You cannot however overwrite a default function twice in thesamelocal space. If a function contains the cast word then it is explictly saying tooverloadthose values. You can overwrite (not overload) a cast function for local use. You cannot however overwrite a cast for the same types functionYou right, I did mean, long abs(int n); //(default function) long abs(int cast(double, long) n); //(cast function) I which case there shouldn't be any problems. So as a general example, the following should occure M1 (effected only by 1) 1 int abs(int); M2 (effected only by 2,3) 2 int abs(int); 3 int abs(double cast(double)); M3 (effected only by 4,5) 4 int abs(int); 5 int abs(int cast(long)); M4 (effected only by 4,5,3) import M1 import M2 import M3 Because It's good to encourage low coupling and high coheiesion. Also with scoping, sometimes it's nessary to overload a function that's outside the scope of the present model. For example a sorting algoithm that uses ">". This is my suggestion, which is not very neat and you may have a better idea. M1 (effected only by 1) 1 int abs(int); M2 (effected only by 2,3) 2 int abs(int); 3 int abs(double cast(double)); M3 (effected only by 4,5) 4 int abs(int); 5 int abs(int cast(long)); M4 (effected only by 4,5,3) import M1 import M2 6 int abs(int cast(long)) //Overwrites 5 import M3 (all function called from this one that use abs(long) are effected by 6)in the same local space. ie 1 -Wrong Module 1 long abs(long n); (default function) //OK works in local space long abs(int n); (default function) //ERROR, cannot overwrite must castI'd let it be there, just for compatibility, and preserve the current semantics. IMO, it's better to think of cast() as of addition to rather than replacement of current schema of function overloading.Module 2 long abs(int n); //(default function) long abs(int cast(int, long) n); //(cast function)I think this should be an error. IMO, the best idea is to consider such declaration semantically equal to this: long abs(int); long abs(long);Since we already have abs(int) in this module, it should be forbidden. By the way, since n is already int, why list it in the cast clause? It should be implicit.Jun 03 2002But that does not seem like a good idea to me.M1 (effected only by 1) 1 int abs(int); M2 (effected only by 2,3) 2 int abs(int); 3 int abs(double cast(double)); M3 (effected only by 4,5) 4 int abs(int); 5 int abs(int cast(long)); M4 (effected only by 4,5,3) import M1 import M2 6 int abs(int cast(long)) //Overwrites 5 import M3 (all function called from this one that use abs(long) areeffectedby 6)Jun 05 2002I kind of like this use of explicit. Would it be better than this? default double sqrt(double val) {} float sqrt(float val) {} extended sqrt(extended val) {} int sqrt(int val) {} Something I always wanted in C++ was the ability to mark operator typeconvert as explicit. Has anyone tried to do something like an iterator in D yet? I suppose you could just return slices but that has the potential to copy lots of data around. And the data structure might not be an array. Sean "anderson" <anderson firestar.com.au> wrote in message news:adelqm$37h$1 digitaldaemon.com...I hate to keep this subject up, but have you considered explicit overloading? With explicit overloading, the function used will default to the default function, unless an explicit one has been defined specifically for that type. ie double sqrt(int val) {}; explicit float sqrt(int val) {}; explicit int sqrt(int val) {}; Therefore if a short is given, it will default to the double method, butifa float is given it will use the explicit type. The programmer canoptimisethe float and int methods for better performance. Of cause there are some disadvantages of this to true overloading (havingdoexplicit more types), but It kind meets halfway.Jun 03 2002Yes, for many reasons. Portablily, non-overloaded functions are decleared the same way and can be easily made overloaded without a change to the base function. In the case of sqrt, you may not even have access to the default function. Also you could for example define a double sqrt function and later decide that it's not optimal for int. It's easier to then add an explicit function rather then modify the orignal. Although I'm open to ideas I'd vote against a default like that. "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:adf73u$o1k$1 digitaldaemon.com...I kind of like this use of explicit. Would it be better than this? default double sqrt(double val) {} float sqrt(float val) {} extended sqrt(extended val) {} int sqrt(int val) {} Something I always wanted in C++ was the ability to mark operator typeconvert as explicit. Has anyone tried to do something like an iterator in D yet? I suppose you could just return slices but that has the potential to copy lots of data around. And the data structure might not be an array. Sean "anderson" <anderson firestar.com.au> wrote in message news:adelqm$37h$1 digitaldaemon.com...(havingI hate to keep this subject up, but have you considered explicit overloading? With explicit overloading, the function used will default to the default function, unless an explicit one has been defined specifically for that type. ie double sqrt(int val) {}; explicit float sqrt(int val) {}; explicit int sqrt(int val) {}; Therefore if a short is given, it will default to the double method, butifa float is given it will use the explicit type. The programmer canoptimisethe float and int methods for better performance. Of cause there are some disadvantages of this to true overloadingdoexplicit more types), but It kind meets halfway.Jun 03 2002Unless D supported both of coarse, because the "default" method would require less typing in some situations. And the default method could require prior planning, otherwise everthing automaticly becomes default. And having two methods may be confusing ie default double sqrt(); explicit int sqrt(); float sqrt(); //What is this? Explicit I suppose. So I still think explicit method is better even though It requires more typing. "anderson" <anderson firestar.com.au> wrote in message news:adf8op$pnp$1 digitaldaemon.com...Yes, for many reasons. Portablily, non-overloaded functions are decleared the same way and can be easily made overloaded without a change to the base function. In the caseofsqrt, you may not even have access to the default function. Also you could for example define a double sqrt function and later decide that it's not optimal for int. It's easier to then add an explicitfunctionrather then modify the orignal. Although I'm open to ideas I'd vote against a default like that. "Sean L. Palmer" <seanpalmer earthlink.net> wrote in message news:adf73u$o1k$1 digitaldaemon.com...youI kind of like this use of explicit. Would it be better than this? default double sqrt(double val) {} float sqrt(float val) {} extended sqrt(extended val) {} int sqrt(int val) {} Something I always wanted in C++ was the ability to mark operator typeconvert as explicit. Has anyone tried to do something like an iterator in D yet? I supposedefaultcould just return slices but that has the potential to copy lots of data around. And the data structure might not be an array. Sean "anderson" <anderson firestar.com.au> wrote in message news:adelqm$37h$1 digitaldaemon.com...I hate to keep this subject up, but have you considered explicit overloading? With explicit overloading, the function used will default to thethatfunction, unless an explicit one has been defined specifically forbuttype. ie double sqrt(int val) {}; explicit float sqrt(int val) {}; explicit int sqrt(int val) {}; Therefore if a short is given, it will default to the double method,if(havinga float is given it will use the explicit type. The programmer canoptimisethe float and int methods for better performance. Of cause there are some disadvantages of this to true overloadingdoexplicit more types), but It kind meets halfway.Jun 03 2002"anderson" <anderson firestar.com.au> wrote in message news:adcimp$2li4$1 digitaldaemon.com..."Pavel Minayev" <evilone omen.ru> wrote in messageWhat Pavel's referring to are the default integral promotion rules, which in D are just like in C. Without them, there is too much casting necessary. Also, if function return types were overloadable, in order to compile an expression with multiple overloaded function calls in it, the compiler will have to try every combinatoric assortment of those functions trying to find the "best" match. I don't think the result of that will be pleasing <g>.A headache for both the compiler (to find out such cases), and the developer. Okay, so this case is simple, but call to foo() might have happened in a complex expression, and due to the weak nature of D type system, many type conversions could happen, so it is hard to tell the desired type for the return value of foo() at some point.Ok, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak return types?Jun 12 2002Have you read the rest of the suggestions? Explicit which changed into Pavel's Cast like so, long abs(double n); long abs(long cast(byte, short, int) n); extended abs(extended cast(float) n); That way there is no ambiguity and no extra casting nessary. The initial one is the default, while other are explicit. By explicit I mean must be one of the things in cast to be accepted. Of coarse there would still be some problems programming the complier, but that's your field not mine. "Walter" <walter digitalmars.com> wrote in message news:ae7v8h$a9d$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:adcimp$2li4$1 digitaldaemon.com...in"Pavel Minayev" <evilone omen.ru> wrote in messageWhat Pavel's referring to are the default integral promotion rules, whichA headache for both the compiler (to find out such cases), and the developer. Okay, so this case is simple, but call to foo() might have happened in a complex expression, and due to the weak nature of D type system, many type conversions could happen, so it is hard to tell the desired type for the return value of foo() at some point.Ok, seems resonable. So it's D fault for having a weak type system for returns types. And you like D having weak return types?D are just like in C. Without them, there is too much casting necessary. Also, if function return types were overloadable, in order to compile an expression with multiple overloaded function calls in it, the compilerwillhave to try every combinatoric assortment of those functions trying tofindthe "best" match. I don't think the result of that will be pleasing <g>.Jun 12 2002"anderson" <anderson firestar.com.au> wrote in message news:ae96c2$24ol$1 digitaldaemon.com...Have you read the rest of the suggestions? Explicit which changed into Pavel's Cast like so, long abs(double n); long abs(long cast(byte, short, int) n); extended abs(extended cast(float) n); That way there is no ambiguity and no extra casting nessary. The initial one is the default, while other are explicit. By explicit Imeanmust be one of the things in cast to be accepted. Of coarse there would still be some problems programming the complier, but that's your field not mine.Yes, that handles overloading by argument, but not by function return value.Jun 12 2002The same can be applied, double abs(long n); long cast(byte, short, int) abs(long n); extended cast(float) abs(long n); I think Paval mentioned that. "Walter" <walter digitalmars.com> wrote in message news:ae9h0g$2hal$1 digitaldaemon.com..."anderson" <anderson firestar.com.au> wrote in message news:ae96c2$24ol$1 digitaldaemon.com...notHave you read the rest of the suggestions? Explicit which changed into Pavel's Cast like so, long abs(double n); long abs(long cast(byte, short, int) n); extended abs(extended cast(float) n); That way there is no ambiguity and no extra casting nessary. The initial one is the default, while other are explicit. By explicit Imeanmust be one of the things in cast to be accepted. Of coarse there would still be some problems programming the complier, but that's your fieldvalue.mine.Yes, that handles overloading by argument, but not by function returnJun 13 2002D does not use the C calling convention (not always, at least). So it's wrong to assume that the caller will clean up the stack.It is quite easy for the compiler to force an appropriate calling convention on a multiple-return function.Also, how exactly do you want to pass something on the stack in such a way that callee can read it? Don't forget that you also have the PUSHed value of EBP, and then the return address. You can POP EBP first, of course, and then push the return values, but: 1) You then don't have access to local variables (since EBP is restored to its old value), and registers might not be enough (what if function returns 10 values?) 2) RET expects return address to be on top. This can be done by POPping it into the register, then pushing all the return values, then PUSHing the return address again. Kinda messy.Compared to what else the compiler must do, this seems trivial. Another approach would be to use an 'on-stack' calling convention. (The D calling convention??) Roughly (I think): int a, int b foo ( int c ) { ... Compiler creates 'pseudo-parameters' for returns-- pop EAX push 0 push 0 push EAX And then the normal entry code -- push EBP mov EBP, ESP Now: a is at [ebp + 8] b is at [ebp + 12] c is at [ebp + 16] Return is just a normal return: mov ESP, EBP ret and the caller does: call foo pop EAX ; get 'a' mov [EBP - 4], eax ; put it somewhere pop EAX ; get 'b' add ESP, 8 ; standard parameter trimBy the way, in C, it was even worse: the structure was allocated once, and only one copy of it existed for one function... so each call rewrote data generated by previous one. C++ provides a workaround for this, at a cost of efficiency.I suppose the 'C calling convention' was invented prior to recursion or threading!! :-) Karl BochertMay 30 2002"Karl Bochert" <kbochert ix.netcom.com> wrote in message news:1103_1022775181 bose...I suppose the 'C calling convention' was invented prior to recursion or threading!! :-)Not really. I guess those guys were just too lazy to cover this case properly, bearing in mind that C was a tool made for private use at first...May 30 2002I thought that the caller would leave the space on the stack to hold the return values. Basically that's equivalent to your version just that the first part (before the push EBP instruction) is done by the caller. int, int, int foo() { return 1, 2, 3; } compiles to: push EBP mov EBP, ESP mov [EBP+16], 1 mov [EBP+12], 2 mov [EBP+8], 3 mov ESP, EBP pop EBP ret This function does not necessarily need the frame pointer EBP (In GCC, you can compile with option -fomit-frame-pointer), in this case the function could be even smaller: mov [ESP+12], 1 mov [ESP+8], 2 mov [ESP+4], 3 ret But this is an optimisation which is not necessary at the moment. Now let's look at some calling code: int a, b, c; a, b, c = foo(); In my model, the caller leaves room on the stack for the return values to accumulate. So the example would compile to: sub ESP, 12 ; make room for 3 int on the stack call _foo ; call foo mov _a, [ESP+8] ; store results mov _b, [ESP+4] mov _c, [ESP] add ESP, 12 ; clean up stack Then, my second example function bar(), which is an ordinary function that takes 3 parameters and returns 1 int. int bar( int x, int y, int z ) { return x + y + z; } I assume that a single integer value is not returned on the stack but in register EAX, as for instance GCC does. Then the function might compile into this code (again with full frame pointer enabled): push EBP mov EBP, ESP mov EAX, [EBP+16] add EAX, [EBP+12] add EAX, [EBP+8] mov ESP, EBP pop EBP ret As you can see, the first return value of function foo() is addressed as [EBP+16] within foo(), which is the same location as the first parameter of function bar(). So you can substitute the return of function foo() for any 3 int parameters for a function call. I follow my example: int sum = bar( foo() ); which should compile to: sub ESP, 12 ; prepare to call function foo call _foo ; will leave 3 return values on the stack call _bar ; same as if we had pushed 3 single parameters add ESP, 12 ; clean up stack mov _sum, EAX So what do you think is this easy to implement in the compiler? Karl Bochert <kbochert ix.netcom.com> schrieb in im Newsbeitrag: 1103_1022775181 bose...D does not use the C calling convention (not always, at least). So it's wrong to assume that the caller will clean up the stack.It is quite easy for the compiler to force an appropriate calling convention on a multiple-return function.Also, how exactly do you want to pass something on the stack in such a way that callee can read it? Don't forget that you also have the PUSHed value of EBP, and then the return address. You can POP EBP first, of course, and then push the return values, but: 1) You then don't have access to local variables (since EBP is restored to its old value), and registers might not be enough (what if function returns 10 values?) 2) RET expects return address to be on top. This can be done by POPping it into the register, then pushing all the return values, then PUSHing the return address again. Kinda messy.Compared to what else the compiler must do, this seems trivial. Another approach would be to use an 'on-stack' calling convention. (The D calling convention??) Roughly (I think): int a, int b foo ( int c ) { ... Compiler creates 'pseudo-parameters' for returns-- pop EAX push 0 push 0 push EAX And then the normal entry code -- push EBP mov EBP, ESP Now: a is at [ebp + 8] b is at [ebp + 12] c is at [ebp + 16] Return is just a normal return: mov ESP, EBP ret and the caller does: call foo pop EAX ; get 'a' mov [EBP - 4], eax ; put it somewhere pop EAX ; get 'b' add ESP, 8 ; standard parameter trimBy the way, in C, it was even worse: the structure was allocated once, and only one copy of it existed for one function... so each call rewrote data generated by previous one. C++ provides a workaround for this, at a cost of efficiency.I suppose the 'C calling convention' was invented prior to recursion or threading!! :-) Karl BochertMay 30 2002Hi, "Pavel Minayev" <evilone omen.ru> wrote in message news:ad4djm$8na$1 digitaldaemon.com...But the structure isn't pushed on the stack! It is allocated somewhere, and pointer to it is passed in EAX. By the way, in C, it was even worse: the structure was allocated once, and only one copy of it existed for one function... so each call rewrote data generated by previous one. C++ provides a workaround for this, at a cost of efficiency.This is new to me. I just checked the code generated by Microsoft C/C++ in C mode. It allocates an anonymous stack variable for the return value in the calling code for each function call (not each invocation), which is perfectly reentrant. Small structs are returned in registers. I checked GCC too, and it also allocates the structure on the stack in the calling code. The behaviour you describe above sounds like a compiler bug to me. Regards, Martin M. PedersenMay 30 2002"Martin M. Pedersen" <mmp www.moeller-pedersen.dk> wrote in message news:ad5iq8$1ri2$1 digitaldaemon.com...This is new to me. I just checked the code generated by Microsoft C/C++ inCmode. It allocates an anonymous stack variable for the return value in the calling code for each function call (not each invocation), which is perfectly reentrant. Small structs are returned in registers. I checkedGCCtoo, and it also allocates the structure on the stack in the calling code. The behaviour you describe above sounds like a compiler bug to me.It doesn't. The C++ standard does not specify how it is done, AFAIK, it just says that function must be reentrant regardless of what it returns. I never checked output of most used C++ compilers you've mentioned, and the way I described (callee allocates struct on heap, caller deallocates), I've seen in one incomplete C++ compiler a friend of mine was trying to write. At least it worked...May 30 2002"Martin M. Pedersen" <mmp www.moeller-pedersen.dk> wrote in message news:ad5iq8$1ri2$1 digitaldaemon.com...This is new to me. I just checked the code generated by Microsoft C/C++ inCmode. It allocates an anonymous stack variable for the return value in the calling code for each function call (not each invocation), which is perfectly reentrant. Small structs are returned in registers. I checkedGCCtoo, and it also allocates the structure on the stack in the calling code. The behaviour you describe above sounds like a compiler bug to me.It's the way C compilers used to work. -WalterJun 13 2002