LoginLogin

How to use DEF

Root / Programming Questions / [.]

kitesinpowerlinesCreated:
Hello everyone checking out this thread! I know someone can help me here. I consider myself an "intermediate programmer" because I know how to use most SmileBASIC commands but there is one that I still find confusing; the DEF statement. I worked with it some in Python but it wasn't presented very clearly so I was wondering about the basics, such as
  • What is a DEF statement/how does it work?
  • When should I use a DEF statement?
  • How would I create one?
Your answers, advice, tips, examples, etc. will help me grow as a programmer and allow me to improve old and new projects I have on my plate. Thanks!

A DEF statement can be placed anywhere in your code. Its kinda like a FOR NEXT statement. But its not a loop. Heres how you'd use it.
DEF TheNameYouWantEvenStrings
'put here any code you want to get used
'like an animation trigger or anything you want
'after all the code you wanted put a END at the end of every DEF
END
That can go anywhere in your code. Now anywhere in your code put TheNameYouWantEvenStrings and everything in between the DEF and END will get activated. So like this:
DEF NameOrVar
SPSET 0,1
BEEP 1
END


NameOrVar
A more clear explanation would be this. SMILEBASIC will not use any of the code in between DEF and END until The name or var you put it as has been called out somewhere in your code.

You can also pass arguments to functions, like this:
DEF COLORPRINT COL,TEXT$
 COLOR COL
 PRINT TEXT$
END
And make functions that return values:
DEF ADD(A,B)
 RETURN A+B
END

DEF is important, super important. In combination with WHILE/WEND, REPEAT/UNTIL, and IF/THEN/ELSE statements that have multiple lines of code per case, you should NEVER use GOTO or GOSUB ever again. Never! DEF as you may have guesses is short for DEFINE. We use it to define fuctions and procedures. If you return a value it is a function if you don't, it is a procedure. The basic syntax looks like the following for a procedure with no parameters:
DEF ProcedureName
 'Code goes here
END
For a function with no parameters:
DEF FunctionName()
 'Code goes here
 RETURN SomeValueOrString
END
Please note the parenthesis on the first line. That is how SmileBasic tells apart functions and subroutines. If you make a function, you need to return a value. You do that with the RETURN keyword. Both can take parameters. One or more values you pass in separated by commas.
DEF ProcedureName Param1%, Param2#, Param3$
 'Code goes here
END

DEF FunctionName(Param1%, Param2#, Param3$)
 'Code goes here
 Return SomeValue%
END
To call a function or subroutine it looks something like the following
'Procedure, no parameters
ProcedureName

'Procedure with parameters. 
ProcedureName 42, PI(), UserName$
'Note you can pass in constants, variables, and the result of functions as parameters

'Function without parameters
result% = FunctionName()

'Function with parameters
result% = FunctionName(42, PI(), UserName$)
'Note the result has to be used somehow
'Passed to something else or assigned to a variable or
'otherwise used in an expression
So, why do I want to go through all this work when I am comfortable with GOTO and GOSUB you ask? There are several reasons. 1. It makes your code easier to reuse. If things are packaged up in a function or procedure it is much easier to copy and paste it into something new. 2. It reduces interdependencies in code. If you use GOTO or GOSUB, you can't pass in parameters or return results without using global variables. This makes it harder to move code around. It can also have unintended consequences when one bit of code messes up anothers variables. 3. You can now have local variables. If you want you can have two variables with the same name, one at the global level and one inside your function or procedure. SmileBasic will check from the local call to find a variable. If you have a local variable of the same name it will hide the global while you are in the function. Even better if you call a function within a function (recursion) each call gets its own set of variables. At any rate less global variables is almost always better. It is also good to not accidentally wipe out another bit of code's stuff and be able to reuse variable names without fear. 4. Recursion. You can have a function call itself which opens up a whole set of algorithms that were ackward otherwise. This relies on each call getting its own state (stack frame) as noted previously. (Yes the example could be easily changed to a loop, it is a simple example).
DEF Factorial(num%)
 IF num% <= 1 THEN
  RETURN 1
 ELSE
  RETURN num% * Factorial(num% - 1)
 ENDIF
END

Print Factorial(6)
5. It makes code easier to read. If you know what to pass in and expect as a result you can treat the code in a function/procedure as a black box you don't have to worry about. This makes code easier to read. With functions and Procedures you need far fewer global variables too. Less stuff to remember. Also a function or procedure name says a lot more than a line number which helps document intent. 6. Organization, you can put code in discrete units that have defined beginnings, endings, input, and output. Each one should be small enough to have a single well defined purpose if done well. I hope that is good enough motivation for you. It is better than GOTO and GOSUB in just about every way. User defined functions will help you understand methods in object oriented languages too. Now if only we had user defined types/structs .... if only.

Thanks, you're all super helpful! I will try to incorporate DEF in my current projects, and for my next one (which I'm still working out the details), I'll try to write without using GOTOs and GOSUBs.

A DEF statement can be placed anywhere in your code.
Actually, there is a very significant restriction about where you can put DEF. It cannot appear between another DEF and its corresponding END. In other words, DEF - END - DEF - END is okay, DEF - DEF - END - END is not.

A DEF statement can be placed anywhere in your code.
Actually, there is a very significant restriction about where you can put DEF. It cannot appear between another DEF and its corresponding END. In other words, DEF - END - DEF - END is okay, DEF - DEF - END - END is not.
It's also not a good idea to put your DEFs before your other code. Functions can only access global variables that are defined BEFORE them.

You can also pass arguments to functions, like this:
DEF COLORPRINT COL,TEXT$
 COLOR COL
 PRINT TEXT$
END
And make functions that return values:
DEF ADD(A,B)
 RETURN A+B
END
but how do you use that kind of def? when i put variable name↓ argument↓ argument↓ def variable name (argument,argument) instructions return somevalue end it gives an illegal function error.

variable name↓ argument↓ argument↓
def variable name (argument,argument)
instructions
return somevalue
end
Do not add the output variable to the definition, only when calling the function do you use this.
DEF FUNC(VARA,VARB)
 VARC=VARA+VARB
 RETURN VARC
END
'code
RES=FUNC(2,5)
?RES
?FUNC(8,6)
?FUNC(5,3)

DEF is important, super important. In combination with WHILE/WEND, REPEAT/UNTIL, and IF/THEN/ELSE statements that have multiple lines of code per case, you should NEVER use GOTO or GOSUB ever again. Never!
I know there is a stigma surrounding GOTO and GOSUB among all of us, but we've gone over this before. There are some legitimate uses for them, they're just far and few between when other methods are taken into account. ON VAR GOTO in particular is the closest equivalent to a switch case we have in SmileBASIC (I would say ON VAR GOSUB is too, but it's riddled with issues). I personally use a DEF block in conjunction with ON VAR GOTO to make simple handlers that are much easier to wrap my head around than ELSEIF chains. So for example, my first attempt at an animation handler looks a little something like this
DEF AnimationHandler
  For I=0 to 69
    IF animPass[I]!=animCurrent[I] THEN
      animCurrent[I]=animPass[I]
      animPass[I]=-1
      ON animCurrent[I]+1 GOTO @END,@0,@1
      
      @0 'Description
        four=2+2
        GOTO @END
      
      @1 'Tag
        quickMaths=four-1
        GOTO @END
      
      @END
    ENDIF
  NEXT
END
Now outside of anything I'm totally unaware of regarding animation handling (I'm still learning), this is a good block of code. It's readable, simple, and expandable. Since the labels within a DEF block are local, you needn't worry about label conflict between DEF blocks. If you are working with an input that has huge gaps between potential values, however, that is where the usefulness of it ends.

variable name↓ argument↓ argument↓
def variable name (argument,argument)
instructions
return somevalue
end
Do not add the output variable to the definition, only when calling the function do you use this.
DEF FUNC(VARA,VARB)
 VARC=VARA+VARB
 RETURN VARC
END
'code
RES=FUNC(2,5)
?RES
?FUNC(8,6)
?FUNC(5,3)
thx!

one thing you could do is just use RETURN:
DEF something SP OUT X,Y,R
X = SPVAR(SP,0)
Y = SPVAR(SP,1)
R=SPROT(SP)
IF X<0 && Y<0 THEN RETURN
SPOFS SP,X,Y
END
Also note that if it has a return value, return something

The DEF keyword is used basically for defining functions. What is very interesting about the functions in SmileBasic however is the ability to return 2 variables using the OUT keyword. example:
DEF Calculator num1,num2 OUT answer1,answer2
   answer1 = num1 + num2
   answer2 = num1 * num2
END

'calling function
Calculator 5,6 OUT sum1,sum2
PRINT sum1,sum2
You can do a lot of interesting things with this.

The DEF keyword is used basically for defining functions. What is very interesting about the functions in SmileBasic however is the ability to return 2 variables using the OUT keyword. example:
DEF Calculator num1,num2 OUT answer1,answer2
   answer1 = num1 + num2
   answer2 = num1 * num2
END

'calling function
Calculator 5,6 OUT sum1,sum2
PRINT sum1,sum2
You can do a lot of interesting things with this.
cool