 |
Larkin Wizard

Joined: 25 Mar 2003 Posts: 1113 Location: USA
|
Posted: Mon Nov 12, 2007 4:20 pm
[2.11Pro] Use of #RETURN multiple times in a function non-intuitive to me |
I probably already know what I'm doing wrong here, but I was hoping to use logic in my functions that allowed for easier maintenance and a little cleaner code. (I plan to try a Lua function next!)
Anyway, would it be plausible to make the following function work the way a traditional function would work? Basically, I want to cut out of the function early on any one of a set of conditions, but when none of those is met I'll return the default value...
Code: |
#FUNCTION able_apply {
#IF (@afflictions.slickness) {
#RETURN 0
}
#IF (@leftarm == "severed" and @rightarm == "severed") {
#RETURN 0
}
#IF (@afflictions.crucified) {
#RETURN 0
}
#RETURN 1
}
|
It's always returning 1 now, and I suspect that's because the function doesn't abort on the first #RETURN. Am I right on that? |
|
|
 |
Fang Xianfu GURU

Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Nov 12, 2007 5:06 pm |
The trouble is that #return doesn't cause a function to exit.
#function omg {#return lol;#say hax}
the #say command will still execute because the function doesn't exit - #return basically just pushes a value onto the stack and that's it. I was going to post about this, but you beat me to it :P it'd be nice if it could do this, you're right.
However, you can build your function to exit itself once it reaches a return by nesting the #ifs or using #switch, so it's not that big a deal. |
|
|
 |
Taz GURU
Joined: 28 Sep 2000 Posts: 1395 Location: United Kingdom
|
Posted: Mon Nov 12, 2007 5:38 pm |
Just put #ABORT 0 in after the #RETURN.
[EDIT]: Since you're within an actual script block that should be #ABORT 1 to abort the whole function. |
|
_________________ Taz :) |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Nov 12, 2007 6:21 pm |
Yeah, I'm not sure about this one. I actually like being able to set the #RETURN value without exiting. This is actually how Delphi works. I Delphi functions, you do:
Result := whatever
to set the result of a function, but it doesn't cause the function to terminate. And this can be quite useful in many situations. So that's why I did it the same way in CMUD. Especially since there are already ways to abort a function. Although honestly, I've always considered using #abort (or using "break" in other languages) to be the same as a "goto" and just means your code probably isn't as well-structured as it could be. I know people still use it all the time...Delphi has "exit" and I do use it, but usually only at the beginning of a procedure or function to exit if it wasn't called with valid arguments. Using "exit" in the middle of a long routine is just asking for memory leaks and other obscure bugs unless you are religious about using try/finally blocks. Sorry for all of the Delphi references. |
|
|
 |
Larkin Wizard

Joined: 25 Mar 2003 Posts: 1113 Location: USA
|
Posted: Mon Nov 12, 2007 6:33 pm |
I avoid #ABORT like the plague after having seen it used incorrectly and causing odd side effects too many times.
I figured out that it was very easy for me to just convert my #IF commands into one #SWITCH, so I'm happy with how it works now. Knowing how #RETURN works helps me code my #FUNCTIONs, and this behavior might be a good idea to note in the help file, just for those of us who come from traditional (non-Delphi ) coding background.
Thanks for the replies! |
|
|
 |
Fang Xianfu GURU

Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Nov 12, 2007 7:56 pm |
I went ahead and added this to the help file.
|
|
|
 |
Arde Enchanter
Joined: 09 Sep 2007 Posts: 605
|
Posted: Mon Nov 12, 2007 8:08 pm |
Hmm... It not returns, it only sets the value will be returned - technically it is more correct statement. Fang, may be you add more complex example to the help?
|
|
_________________ My personal bug|wish list:
-Wrong Priority when copy-paste setting
-1 prompt trigger for Mapper, Session and General Options, not 3 different!
-#SECTION can terminate threads
-Buttons can't start threads |
|
|
 |
Fang Xianfu GURU

Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Mon Nov 12, 2007 10:52 pm |
Just for you, Arde, I rephrased it and added a few more examples. You're not getting a Christmas present now, just so you know.
|
|
|
 |
Seb Wizard
Joined: 14 Aug 2004 Posts: 1269
|
Posted: Mon Nov 12, 2007 11:11 pm |
Well, I agree with the complex examples sentiment. Most of the examples in zMUD were very simplistic and didn't necessarily indicate what the syntax would be in a more complex example. (So, often it was a question of trial and error.)
|
|
|
 |
Zhiroc Adept
Joined: 04 Feb 2005 Posts: 246
|
Posted: Mon Nov 12, 2007 11:51 pm |
Hmm, if it's called #RETURN, it should return from the function at that point like every other language with a "return" directive. You can document it all you want, but you'll find people getting it wrong all the time otherwise....
Multiple #RETURNS are good for exiting loops early, and avoiding if/then/elseif statements.
And if you want the other behavior, it's easy to do with a local variable and a #RETURN at the end. |
|
|
 |
Fang Xianfu GURU

Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Tue Nov 13, 2007 12:22 am |
You can already use #abort much like you'd use a return or break to exit a loop.
And see Zugg's post above for "every other language". |
|
|
 |
Seb Wizard
Joined: 14 Aug 2004 Posts: 1269
|
Posted: Tue Nov 13, 2007 12:33 am |
I have to agree with Zhiroc (changing "every other language" for "most other languages").
If #RETURN was like Zhiroc suggests, then for Zugg's example, you would just do
$Result = whatever
and then
#RETURN $Result
And actually, that looks very similar! Maybe functions could even return $Result by default if they reach the end of the code with no #RETURN statement. This would make $Result a special, reserved, local variable though. |
|
|
 |
Guinn Wizard
Joined: 03 Mar 2001 Posts: 1127 Location: London
|
Posted: Tue Nov 13, 2007 1:03 am |
Another vote for it seeming counter intuitive. Admittedly I've only really used Java so it's just my basis for 'normal' being different from Zugg's.
|
|
_________________ CMUD Pro, Windows Vista x64
Core2 Q6600, 4GB RAM, GeForce 8800GT
Because you need it for text... ;) |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Nov 13, 2007 1:28 am |
Sorry, but this isn't going to change. Sorry about it being counter-intuitive for some people, but it's just something you'll need to get used to.
The way it is now, you can always add your own #ABORT if you really want it to exit. If I changed it so that #RETURN also exited all the time, then there would be no way to use it the way it is now, and I don't want to restrict that functionality. As I mentioned, being able to do stuff after assigning the return value can be very useful.
Also, using multiple #RETURN commands should *not* cause any error messages. If it is, then that's a bug I need to fix. In fact, a very common use of #RETURN is the following:
Code: |
#FUNCTION MyFunc {
#RETURN 0 // set default return value
#IF (something) {#RETURN newvalue}
} |
In this case you set a default return value, and then only change the return value if an expression is true. I do this kind of stuff all the time in Delphi. If #RETURN always exited, then there would be no way to do this.
So that's why I'm leaving it the way it is...because you can still just add your own #abort if you need it. Making some sort of special $Result local variable just adds even more complexity to the parser and compiler, and then also prevents someone from using "Result" as their own local variable name. |
|
|
 |
Seb Wizard
Joined: 14 Aug 2004 Posts: 1269
|
Posted: Tue Nov 13, 2007 2:16 am |
How about an extra parameter to #RETURN?
#RETURN [RtnVal], [True/False]
where RtnVal defaults to "" and True/False is "Now?" and defaults to True (or False if you want). If it is True, then it returns immediately. If False, then it returns at the end. Or we could use "Yes", or "1" (minus the quotes) for "Now?". [EDIT: Actually any non-zero value should work for True, except for False, obviously.] |
|
Last edited by Seb on Tue Nov 13, 2007 2:34 am; edited 2 times in total |
|
|
 |
Guinn Wizard
Joined: 03 Mar 2001 Posts: 1127 Location: London
|
Posted: Tue Nov 13, 2007 2:17 am |
Edit: Whoops, writing this as Seb replied
Quote: |
If I changed it so that #RETURN also exited all the time, then there would be no way to use it the way it is now, and I don't want to restrict that functionality. |
I wouldn't think it'd restrict functionality necessarily. Your example would become
Code: |
#FUNCTION MyFunc {
$return = 0 // set default return value
#IF (something) {#RETURN newvalue}
#RETURN $return
} |
As it is, Larkin's becomes
Code: |
#FUNCTION able_apply {
$return = 1
#IF (@afflictions.slickness) {
$return = 0
}
#IF (@leftarm == "severed" and @rightarm == "severed") {
$return = 0
}
#IF (@afflictions.crucified) {
$return = 0
}
#RETURN $return
} |
Seems like no functionality is really lost either way, it's just another way to skin the same cat...
Now if there was a #RETURNNOW function that did '#RETURN x;#ABORT' then we'd all be happy :) Or is that just being cruel to the poor cat? |
|
_________________ CMUD Pro, Windows Vista x64
Core2 Q6600, 4GB RAM, GeForce 8800GT
Because you need it for text... ;)
Last edited by Guinn on Tue Nov 13, 2007 2:18 am; edited 1 time in total |
|
|
 |
Iceclaw Apprentice
Joined: 11 Sep 2005 Posts: 124
|
Posted: Tue Nov 13, 2007 2:18 am |
I like the extra parameter option, default FALSE, return at end :)
|
|
|
 |
Heretic Newbie
Joined: 27 Oct 2005 Posts: 7
|
Posted: Tue Nov 13, 2007 3:06 am |
Zugg wrote: |
In fact, a very common use of #RETURN is the following:
Code: |
#FUNCTION MyFunc {
#RETURN 0 // set default return value
#IF (something) {#RETURN newvalue}
} |
|
In all my years of programming I've never seen or had any interest in seeing this. Nor has anyone I've ever talked to with at least equivalent experience. Especially because this is absolutely trivial to implement without this kind of loss of readability.
The equivalent in C:
Code: |
int something(){
int r = 0;
if (whatever) r =newvalue;
return r;
}
|
Much more intuitive, same functionality, no significant amount of extra effort. Everyone's a winner.
Have a nice day! |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Nov 13, 2007 3:53 am |
Well, obviously my example above was a trivial example. Look, I've been programming for over 20 years, ok? Yes, I've always used Delphi/TurboPascal and not C/C++, so maybe I'm just weird. But in the example that you gave, if the programmer ever uses "exit" (or break, or whatever C uses to exit a routine prematurely), then you can end up with a function that has an undefined result. So I *always* set the default return value in my functions at the beginning.
This also helps with exception handling. If your routine gets an exception and you tell it to continue, then you still have the default function result instead of undefined.
Yes, it's also better to try/finally trap to ensure that you return a result. I use that as well. But I still have a lot of code that looks like this:
Code: |
function MyFunc( args): Boolean;
begin
Result := false;
if Args not valid then exit;
do function here and set Result := value;
end; |
In other words, I set the default function value, then verify that correct arguments were passed (pointers not nil, etc). Yes, I could have also easily done this:
Code: |
function MyFunc( args): Boolean;
begin
if Args valid then begin
do function here and set Result := value;
end
else Result := false;
end; |
So, it's just a style difference. I use the first method because:
a) It makes it obvious to me what the default return value of every function should be at the very top
b) Allows me to make multiple argument checks and just use Exit for each one instead of building some huge IF statement.
c) Keeps the main function code indented one level less
Yes, some of these are trivial. This is all just a style issue.
But look, this discussion is getting carried away. I'm not going to add yet another argument to #RETURN to make it even more confusing. zScript is NOT C! There are lots and lots of things in zScript that are different than how C works. If you want to use a "return" that always aborts, then feel free to write your functions using Lua. |
|
|
 |
Seb Wizard
Joined: 14 Aug 2004 Posts: 1269
|
Posted: Tue Nov 13, 2007 4:13 am |
I don't mean to be incendiary, but:
Wikipedia: Return statement wrote: |
In computer programming, a return statement causes execution to leave the current subroutine and resume at the point the subroutine was called -- known as its return address. The return address is saved, usually on the process's call stack, as part of the operation of making the subroutine call. Return statements in many languages allow a function to specify a return value to be passed back to the code that called the function.
In C++, ... <snip>
In Pascal there is no return statement. A subroutine automatically returns when execution reaches its last executable statement. Values may be returned by assigning to an identifier that has the same name as the subroutine (a function in Pascal terminology). |
So why invent a new RETURN statement that doesn't actually return, when even Pascal doesn't use RETURN to just set a default return value and not return?
Zugg wrote: |
a) It makes it obvious to me what the default return value of every function should be at the very top
b) Allows me to make multiple argument checks and just use Exit for each one instead of building some huge IF statement.
c) Keeps the main function code indented one level less |
I can see the logic behind your point (a) and the benefit, but points (b) and (c) can be accomplished with returns that actually return as shown be some of the examples above, e.g.
Code: |
#FUNCTION MyFunc {
$return = 0 // set default return value
#IF (something) {#RETURN newvalue}
#RETURN $return
} |
And that also covers point (a) too. |
|
|
 |
Heretic Newbie
Joined: 27 Oct 2005 Posts: 7
|
Posted: Tue Nov 13, 2007 4:18 am |
Zugg wrote: |
Well, obviously my example above was a trivial example. Look, I've been programming for over 20 years, ok? Yes, I've always used Delphi/TurboPascal and not C/C++, so maybe I'm just weird. But in the example that you gave, if the programmer ever uses "exit" (or break, or whatever C uses to exit a routine prematurely), then you can end up with a function that has an undefined result. |
Just for your information, in C "break" will end a loop. It's effectively "goto endofloop." It will cause a compiler error if you try to use it in a function without being in a loop, and has nothing to do with ending the function. Same with "continue" which is effectively "goto beginningofloop." In short, as long as you have a "return" statement at the end of the function, a function will -not- give up control without assigning some return value except for C++ exceptions, in which case it doesn't even conceptually make sense for there to be a return value.
It seems every time I post you brag about your "over 20 years of experience," and that certainly does give your opinion some weight, but don't forget that any programmer -always- has a lot to learn from other languages and other schools of thought. |
|
|
 |
Seb Wizard
Joined: 14 Aug 2004 Posts: 1269
|
Posted: Tue Nov 13, 2007 4:24 am |
Zugg, if you really want to keep functions the way they are, I think you should at least consider renaming the #RETURN command to #SETRETURNVALUE, since that is what it actually does (and does not return). It will cause a lot less confusion and argument.
|
|
|
 |
Vijilante SubAdmin

Joined: 18 Nov 2001 Posts: 5182
|
Posted: Tue Nov 13, 2007 5:14 am |
I can see both sides of this arguement. The convienence of return in C to end the function is useful, however even in C I often write it so that the return value is held in a variable from start to finish. I also programmed in Pascal, and often was irritatated at the lack of a quick out, exit wasn't allowed at the time. Having learned from that experience though I tend to write all loops, no matter what language, to have internal exit conditions as well as the external data. From an assembly standpoint the entire programming community are all liars, 1/20th of the instructions used are a form of 'goto'. Knowing that little detail since I started learning assembly, over 20 years ago, I am fairly certain of a few things:
1. #RETURN is a perfectly fine name
2. Whichever way Zugg does #RETURN is right.
3. The Wiki is not gospel, there are errors an ommisions
4. I am very likely to lock this thread
5. I haven't quite run out of patience yet
About all I can say for those that think #RETURN needs to exit is learn more diverse ways to write your code. An #IF-ELSE chain would work for Larkin's original problem. The reason it works is because he is actually doing if(not(slick&labroke&rabroke&crucified)) which has a number of logical equivalents. In this case he is looking to use this one if(not(slick)|not(labroke)|not(rabroke)|not(crucified)). The not is in the return values for those that are having trouble following. It gives just the same efficiency when coded that way as when return does a jump to end of function. Actually when a compiler is done with it the 2 forms end up nearly identical in assembly. |
|
_________________ The only good questions are the ones we have never answered before.
Search the Forums |
|
|
 |
Fang Xianfu GURU

Joined: 26 Jan 2004 Posts: 5155 Location: United Kingdom
|
Posted: Tue Nov 13, 2007 11:21 am |
At the risk of looking like a sock puppet, I'm afraid I agree with Viji. These things don't really make a difference, since either method lets you accomplish either way of doing things. The first time you try to make a function and it doesn't work like you expect (whichever way you expect), you'll read the help file and discover what rules it uses.
I personally have never used a language that doesn't use return to exit a function, but I don't see a problem with doing it this way, either.
And while Wikipedia is the best site on the planet, it does have a tendency, as Seb's found, to state things that happen to be true as if they were Cosmic Facts. |
|
|
 |
Arde Enchanter
Joined: 09 Sep 2007 Posts: 605
|
Posted: Tue Nov 13, 2007 11:38 am |
Fang Xianfu wrote: |
Just for you, Arde, I rephrased it and added a few more examples. You're not getting a Christmas present now, just so you know. |
Thank you, Fang! You can't deny that now help article for #RETURN is much, much better. And btw, I have my birthday in November, you may give me your present 1 month earlier instead of Christmas.
I tend to agree with what Vijilante wrote in his last paragraph and Zugg in his latest post (and I will not even bother thinking how I looks like - why I must do it?). The language (here it is the zScript) is just an instrument, learn it features and restrictions before use. The question is in having a complete documentation with plenty of samples, not in how Zugg had implemented one or another command of function. If anyone now would write a function for a first time, will he/she have a question on how #RETURN works? No, even if the name for a command is non-intuitive.
UPDATE: Fang, you have beat me in time with your answer.  |
|
|
 |
|
|