ID:2243145
 
(See the best response by MrStonedOne.)
Code:
return 0
return 1
return on_mount
return TRUE
return FALSE


Problem description:
I'm not understanding what these values truly mean. They're obviously RETURNING to something, but I can't clarify myself where they're returning to. Some even return to a variable (return on_mount). Which I don't understand fully. Any advice and or help?
proc/Addition (a,b)
return a+b


Return's a+b to something
return isn't a proc. It's an instruction.


So basically, this made more sense way back in the day when programming languages were a bit more bare to metal. We need to understand a few terms before you will understand what return actually does.

Runtime Interpreter: The runtime interpreter takes compiled code and interprets it while the program is running. Basically, interpretation is performing simple, small instructions all in a sequence to reach a desired result. Computer programs are long lists of thousands and thousands of instructions all run in sequence over the lifetime of a program.

Entry point: An entry point is any place where the interpreter would consider starting a run of code. Think of this like sentences in a book or something. The start of the sentence is the entry point for that sentence.


When you are defining a proc, you are creating a self-contained group of instructions. The name of the function is its entry point, more or less, and a function ends when it returns.

But where does it return to? Let's take a look at how procs work:

A() //happens first
B() //happens second
C() //happens third


This is a simple example. A() is called, doing all the instructions defined under A()'s entry point until its return it called, at which point the interpreter continues by calling B(), and so on.

When you compile code, complex expressions like:

var/a = Weight(usr.strength*src.weakness) + 4


Compile down to a linear set of small instructions:

define a
push <usr>
access strength (pop push)
push <src>
access weakness (pop push)
multiply (pop pop push)
push 4
add (pop pop push)
assign a (pop)


Internally, all those pops and pushes are basically just putting information into a temporary buffer called a stack, which manipulates the top value on the stack for all future operations.

So the code flow pairs with stack memory changes like so:

push <usr> // {} -> {usr}
access X // {usr} -> {} -> {X}
push <src> // {X} -> {X,src}
access Y // {X,src} -> {X} -> {X,Y}
multiply // {X,Y} -> {X} -> {} -> {Z} (X*Y==Z)
push 4 // {Z} -> {Z,4}
add // {Z,4} -> {Z} -> {} -> {Z+4}
assign a //{Z+4} -> {}



Internally, when a proc is compiled, it is compiled to a series of instructions like the above, and a lot of the internal structure of the code you actually wrote is destroyed in the process. A proc may be compiled with a simple memory location as its name, so calling a proc like so:

A()


will compile to:

goto 46331


This is called a jump point, because the interpreter is jumping to a specific instruction somewhere in the code by number.

So this is where return comes in. When we call a proc, we need to be able to go back to the old string of instructions we were processing when it's done.

The engine does this internally on a proc call by doing something like this:

push 12336
goto 46331
//instruction 12336


The return point is pushed into the stack, allowing the engine to backtrack when it hits a return instruction. The return then jumps the interpreter to the instruction at the stored location, ending the proc call.

When a return is encountered, it knows to pull the value from the stack and use it as a jump point back to where the execution was told to go after the completed proc. This same basic idea is also how conditional statements and loops work.

Please note this isn't exactly how DM's runtime interpreter works, it's just a simplistic example of how many Virtual Machines are written to function, and through understanding the basics of a virtual machine, you can better visualize DM's specific implementation of the concepts above.

TL;DR:

return returns the interpreter to the next instruction after the one that called the proc.
Wherever you call a proc, that proc is effectively replaced by the proc's return value, which is the value that comes after the "return" keyword. And you can call procs anywhere that expects a value.

This is known as "returning a value to the caller", where the caller is simply where the proc was called. The value is literally given back to the caller, in place of the call.

Other examples of expressions are literal values (numbers, strings, type paths), variables, and operations, which involve 1 or more sub-expressions.
// using a proc in a variable initialization
var x = SomeProc()

// using procs as operator sub-expressions
x = SomeProc() + SomeProc() // only certain values with with the + operator!

// using a proc in an if() condition
if(SomeProc()) // ...

// using a proc in a while() condition
while(SomeProc()) // ...

// passing the return value of SomeOtherProc()
// as the first argument to SomeProc()
SomeProc(SomeOtherProc())

Also, one thing to not get confused about is that return on_mount returns the value stored in the on_mount variable. It doesn't return the variable itself. Similarly, expressions are not returned; they're evaluated first, and the single resulting value is returned.
Best response
Not enough attempts at this, and i'm high, so my turn!

The key thing you have to understand, is that every program, at both the big picture level (the program as a whole) and the small picture level (individual procs or functions) as well as every level between, is based around the same 3 things:

Input
Calculation
Output

Now this seems like it's simple and that it's stating the obvious, but it really useful to remember when trying to understand programming.

Let's take a simple command line dos program, this one calculates GPA.

I run the program, I give it a list of my grades and course this quarter, it goes and does fancy math magic, and it comes back with my Grade Point Average.

Input, Calculation, Output.

So lets say this is not a program, but a dude you know who is good at math.

You give him your course sheet and your grades for the quarter, and ask him to calculate your GPA.

He goes to his math den of evil and after 5 minutes he returns back with your GPA.

Let me just repeat that last sentence for you.

He goes to his math den of evil and after 5 minutes he returns back with your GPA.

Now lets say this isn't a full blown program or some nerdy roommate, but just a simple proc in dm.

//                             V input
/proc/CalculateGpa(var/list/courses)
var/gradepoints = 0
var/credits = 0
for(var/datum/course/course in courses)
gradepoints += (course.grade * course.credits) //<- calculation
credits += course.credits //<- calculation
var/gpa = gradepoints / credits //<- calculation
return gpa //<- Output


And lets say you have another bit of code that does this:

var/list/courses = list()
courses += new /datum/courses {name = "How2Computers 101", grade = 2.0, credits = 4}
courses += new /datum/courses {name = "How2Programming 101", grade = 1.8, credits = 2}
courses += new /datum/courses {name = "Protesting Fascism 203", grade = 3.5, credits = 7}
usr << "You're gpa is: [CalculateGpa(courses)]"


You can see where it provides the input to CalculateGpa, and you can see where it gets the output from CalculateGpa.

return just provides the output to the code that invoked the proc.
@Stonedone: That's a good explanation for OP's purposes. You've got my vote.

Will admit, it's odd to me that yielding values and returning are the same concept in most languages these days, but... Eh. Whatever gets people there faster.
In response to Ter13
Agreed, that's one of the best explanations of return for the less technically inclined I've ever seen. +1 from me as well.