ID:157019
 
I want my procedure to take in multiple values and be able to send some back to the procedure call.

For example, say I want to be able to rotate (and in some cases scale) an object.
rotate(x1, y1, x2, y2, rotationtype)
if (rotationtype == "A")
x1 = x2 + y2
y1 = y2 - x2
return 1
else if (rotationtype == "B")
x2 = (x1 - y1)/2
y2 = (y1 + x1)/2
return 1
else
usr << "Bad rotation."
return 0

I want to be able to call rotate and get values from it IN ADDITION TO using the return command to determine whether the rotation worked or not.

How do I do this?
BYOND does not support procedures returning multiple values, nor out parameters. Your best choice is probably to pass in an object as an argument and modify its variables.
In response to Garthor
Okay, I read somewhere about datums. Would those count as objects? How do I make the mob variables and procedures interact with the datums? The DM guide does not explain this in a lot of detail.
In response to TuringAI
Pretty much anything that isn't a number or a string is an object.

I'm not sure what you mean by making "the mob variables and procedures interact with the datums".

mob
proc
do_something(var/object/O)
O.whatever = O.whatever + O.whatever
In response to Garthor
Garthor wrote:
Pretty much anything that isn't a number or a string is an object.

I'm not sure what you mean by making "the mob variables and procedures interact with the datums".

mob
> proc
> do_something(var/object/O)
> O.whatever = O.whatever + O.whatever


Well I was trying to define my 'object' as a datum by putting the definition outside of the obj tree. Of course, it didn't work very well.
In response to Garthor
Garthor wrote:
BYOND does not support procedures returning multiple values, nor out parameters.

proc/cake()
return "cake=good&pie=bad"
mob/verb/Displayreturnaslist()
var/list/l = params2list(cake())
world<<l
for(var/v in l)
world<<"[v]=[l[v]]"


Isn't this an alright method?
In response to Garthor
Okay, now I'm getting runtime errors. I have variables and procedures in my rotating_grid object but for some reason it's crashing at runtime, telling me

runtime error: Cannot modify null.x1.
proc name: proc1 (/mob/proc/proc1)
usr: TuringAI (/mob)
src: TuringAI (/mob)
call stack:
TuringAI (/mob): proc1()
TuringAI (/mob): Verb1()

I JUST defined my object and for some reason it thinks it's null! It's like the compiler just skipped over the variable declaration or something!

The variable declaration is:
var/obj/rotating_grid/rg


The object declaration includes a rotating_grid type because I already have a lot of different object types, and then within this object type I have variables x1, y1, x2, and y2.

Why isn't it working?!?
In response to Leur
Leur wrote:
Garthor wrote:
BYOND does not support procedures returning multiple values, nor out parameters.

> proc/cake()
> return "cake=good&pie=bad"
> mob/verb/Displayreturnaslist()
> var/list/l = params2list(cake())
> world<<l
> for(var/v in l)
> world<<"[v]=[l[v]]"
>

Isn't this an alright method?

That's an option, but it's an absurd amount of extra work to just call a proc.
In response to TuringAI
It's null because you didn't assign it a value at any point.
In response to Garthor
Actually I did.

In the procedure, I declared the object, then I assigned the object's X1 and Y1 values accordingly.
In response to TuringAI
TuringAI wrote:
Actually I did.

In the procedure, I declared the object, then I assigned the object's X1 and Y1 values accordingly.

// Declares a null rg reference.
var/obj/rotating_grid/rg

// Creates a new rotating_grid object and assigns it to the reference.
var/obj/rotating_grid/rg = new()


If this does not help, please post the code where you declare it.
In response to Green Lime
Ah, yes, that helps. Thank you!

I was mostly going by the code he had posted before. I guess I have a problem taking things too literally.

:P
Another way of returning multiple values is to return a list. It works fairly well, if you always get the same number of values back. The problem is you have to keep track of which position in the list corresponds to what value. (That's where comments/documentation is important) In my opinion, for simple cases, I think returning a list is a little easier. Your actual example could be written as:
rotate(x1, y1, x2, y2, rotationtype)
if (rotationtype == "A")
x1 = x2 + y2
y1 = y2 - x2
else if (rotationtype == "B")
x2 = (x1 - y1)/2
y2 = (y1 + x1)/2
else
usr << "Bad rotation."
return 0
return list(x1,y1,x2,y2)

And then a call to it would look like:
someProc(var/Object/O)
var/result = rotate(O.x1,O.y1,O.x2,O.y2,"A")
if(!result) //rotation failed
...
else
O.x1 = result[0]
O.y1 = result[1]
O.x2 = result[2]
O.y2 = result[3]


Like I said, it's best if you always get the same number of values returned, but if you get an uncertain amount, you could use an associative list, but at that point, the costs start to outweigh the benefits.

In my opinion, it's easier than the param option, and it's useful, especially if you don't have an object that you want to modify. (In this case, passing the object itself might be easier, but in some cases it's not)
In response to Chessmaster_19
ref
var /value

New(v)
value = v

proc
put(v)
value = v
get()
return value

proc/modifiesRef(ref/fruit, ref/automobile)
fruit.put(pick("apples","oranges","bananas"))
automobile.put(pick("pick-up","sedan","coup"))

proc/usesRef()
ref/fruit = new /ref("pineapple")
ref/automobile = new /ref("SUV")

modifiesRef(fruit,automobile)

world.log << "fruit: [fruit.get()]"
world.log << "automobile: [automobile.get()]"


Before you comment on that, let me put on some flame-retardant undies... :P

I think something like the following would be more appropriate for the OP's purposes:

point2d
var
x;y
New(X,Y)
x=X
y=Y

proc/rotate(point2d/p1, point2d/p2, rot_type)
if (rot_type == "A")
p1.x = p2.x + p2.y
// ... and so on ...


If you want to go full blown OOP, you would implement rotate as a member of point2d. But then, instead of modifying the passed point, I would prefer that it return a new point.I would also move the choice to scale or not outside of the function...
In response to Lewzer
I'm almost willing to take a shot in the dark and say that you started programming on Java.
In response to Chessmaster_19
Was that a shot!? ...jk :)

DM is object-oriented... why fight it?

I started with C and x86 assembly way back. I then moved on to functional languages like Scheme and OCaml. I actually avoided Java for the longest time: too verbose (C++, too!). If it wasn't for the plethora of libraries available, I would probably still avoid it.