---------------------------------------------------------

*************** SPECIAL EDITION *************************

---------------------------------------------------------
The Liberty Basic Newsletter - Issue #67 - MAR 2000
       2000, Cliff Bros and Alyce Watson
             All Rights Reserved
---------------------------------------------------------
In this issue:

    Liberty BASIC version 2 - in review

    User defined functions in Liberty BASIC 2.0.
        - by Carl Gundel

    Beginner's tutorial on user defined functions.

In future issues:
    Writing output 'code'
    RGB color choices
    Changing the runtime icon
    Launching the default web browser and email client
    Installers
---------------------------------------------------------
LIBERTY BASIC 2.0 IN REVIEW

If you haven't already, get the Alpha 4 of Liberty BASIC 
v2.0 here:

http://world.std.com/~carlg/LBALPHA4.ZIP

Carl has been very sensitive to the needs and suggestions
of Liberty BASIC programmers, and version 2.0 provides a
whole sack-ful of goodies!  User defined functions were on
the top of many people's lists, and they are discussed later
in this newsletter.

Here are some of the other new features:

- Printer and font common dialogs
These dialogs work for font choice and printing from within
the LB editor, and they can also be used by the programmer!
Now, issuing an Lprint command will call up the printer dialog,
allowing the user a choice of printer.  We can also call up the
common font dialog, and the user's choice is returned in a string,
in proper Liberty BASIC format!


- Fonts now include support for italic, bold, strikeout and underscore.  


- Enhanced font point size specification.  
Now if you specify only one size value it will use this to set the 
actual point size of the font.  You can still specify font sizes as 
before, with a width and height value, so you can choose the best 
sizing method for each situation.


- Popupmenu command.  
This is just like the menu statement, but it pops up a menu anywhere 
you like.  This allows you to have multiple menus, and to create
menus after a window has opened, which was not possible before.


- Color control
Two variables, ForegroundColor$ and BackgroundColor$ let you control 
color for windows of type window, and window_nf.  Dialog boxes now 
automatically have a gray background.  You can also set the background
color for some controls, with these variables: TextboxColor$, ListboxColor$
ComboboxColor$, TexteditorColor$


- Ability to use expressions when specifying controls.
People have asked for this one many times.  Now, values for some
controls do not need to be hard-coded.  As an example, you could
specify a buttonwidth variable, giving it a value at the top of
your code.  When setting up buttons, you would then use this
variable for the width parameter.  If you decided to change this
value, you would only need to do it in one spot, instead of in
every single button command.  This works for checkbox, combobox
and groupbox controls as well as for buttons and bmpbuttons.


- Added recent files to the LB editor file menu.

- Added a toolbar with buttons to the Liberty BASIC editor


- Added a dechex$() function 
This function produces a hexadecimal representation of a decimal value.  
This is the opposite of the hexdec() function.
  hexString$ = dechex$(255)    'produces "FF"


- Added new forms of the date$() function
You may now specify a template string to get the form you want.
  print date$()             ' Nov 30, 1999
  print date$("mm/dd/yyyy") ' 11/30/1999
  print date$("mm/dd/yy")   ' 11/30/99
  print date$("yyyy/mm/dd") ' 1999/11/30    for sorting
  print date$("days")       ' 36127         days since Jan 1, 1900


- Added two new forms of the time$() function.
Note that the new functions return numeric values.
  time$ = time$()   'this is same old form, and does the same thing
  seconds = time$("seconds")   'returns seconds since midnight
  msecs = time$("milliseconds")  'returns milliseconds since midnight


- Random number function has been greatly improved.


- Added a set command to the graphics window and graphicbox.  
It draws a single spot using the current pen.  If you don't specify 
a location it will draw in the current spot.  If you do specify a
location is will draw the spot there.
    print #draw, "set"
or using the following should improve the performance of your
programs over using place and go.
    print #draw, "set 100 100"


- Modified the branch labels dialog box to include function defs along
  with branch labels

- GetBmp now works with displays set to 32-bit color resolution.  It
previously bombed at more than 24-bit resolution.

- Bitmaps in 24-bit format may now be loaded and displayed.

- BmpSave will now work!
---------------------------------------------------------
PLEASE TEST AND GIVE FEEDBACK!

The more people testing, the better version 2 will be, so
please download the new alpha and give it a try.  What
should you do to test?  Try out the sample programs and
see if you understand what is going on, then try to modify
them.  Write your own routines, making use of the new features.
Use the alpha version to run your old programs, to see if
there is compatibility, and to check for new bugs that may
have crept in.

What should you do with your test results?  It is most 
helpful to report errors, bugs, and any problems you had, 
including difficulty you have in using and understanding
the new features.  Post your findings on the alpha-test
message board here:

http://tigernetsoftware.hypermart.net/wwwboard/

A public posting is much better than a private message to
Carl.  Only one person needs to post a bug report this way,
so Carl doesn't need to sift through 27 private messages
that all report the same bug.  A public posting also gets
information to many people and allows more discussion.

If you do find a bug, try to be as specific as possible when
describing it.  For instance, saying "Graphics windows are
not being filled with the correct color" is much more helpful
than saying "I had a problem with graphic color."  If possible,
include a small snippet of code that reproduces the problem.

---------------------------------------------------------
EDITOR'S NOTE

Perhaps the most exciting feature to be added to Liberty
BASIC in version 2 is the ability to define our own
functions.  We have a real treat for this newsletter!
Carl Gundel has written an article to share with us his
thoughts on user defined functions and their implementation
in Liberty BASIC.  He hopes that this article will generate
discussion on this very important issue.  This is a chance
for all of us to have a voice in the development of
Liberty BASIC.  Thanks Carl!

For those who feel a bit lost when confronted with the concept
of user defined functions, there is a beginner's tutorial
at the end of this newsletter.

Thank you, Carl, for providing this wonderful language, and
for your continued involvement with the community of people
who have come together in friendship to share our love
of Liberty BASIC.


---------------------------------------------------------
---------------------------------------------------------
      USER DEFINED FUNCTIONS IN LIBERTY BASIC 2.0
           -- THEORY AND IMPLEMENTATION --
               CARL GUNDEL, MARCH 2000
---------------------------------------------------------
---------------------------------------------------------
User functions in Liberty BASIC v2.0

Probably the single most significant feature of Liberty BASIC
v2.0 is its new support for user defined functions.  This is
an important feature because it improves substantially our
ability to create modular programs and also makes it easier
to make libraries of code that are reusable between programs.
We will also be more able to share code with each other.

This article isn't meant to be a tutorial on functions.
Instead it describes the current state of the user function
feature of Liberty BASIC v2.0 alpha 4.  In addition, we will
explore what is possible for the final release of Liberty
BASIC v2.0, as opposed to what is currently implemented.

Local things - Variables and branch labels
--------------------------------------------------------------
Using GOSUB and RETURN, we Liberty BASIC programmers have
been able to place often repeated code in our programs into
subroutines.  This is definitely useful, but when using this
approach we have to worry about not using variable names for
more than one thing.  Subroutines don't let us choose names
for our variables without first looking around at the entire
program to make sure we don't reuse a variable whose contents
shouldn't be tampered with.

User functions on the other hand let us choose whatever names
we feel are most appropriate for variables for a given task.
We call these kind of variables local variables.

Here is a short code sample which is written as a subroutine,
and then we'll follow it with an equivalent user function:

'Return a string without quotes
'This is used when getting typed input
[noQuotes]
    noQuotes$ = ""
    for nqLoop = 1 to len(nqText$)
        if mid$(nqText$, nqLoop, 1) <> chr$(34) then
            noQuotes$ = noQuotes$ + mid$(nqText$, nqLoop, 1)
        end if
    next nqLoop
    return

In this case I put the letters nq in front of all my variable
names to help make sure there is no conflict between the
variables in this subroutine and the variables in the rest of
the program.  These sort of conflicts often lead to nasty and
hard to figure out bugs!

Now here's the function:

'Return a string without quotes
'This is used when getting typed input
function noQuotes$(text$)
    for x = 1 to len(text$)
        if mid$(text$, x, 1) <> chr$(34) then
            noQuotes$ = noQuotes$ + mid$(text$, x, 1)
        end if
    next x
end function

In the function we are able to choose very simple names for
each variable.  We can coincidentally have the same variable
name in many different functions, but each identically named
variable represents a value unique to the function it is
defined in.

To return a value from a function, all we have to do is set
the value of a variable having the same name.  In the example
function noQuote$() above we set the variable noQuote$ to be
the string we want to return.

Each time we use a function (this is like using GOSUB to use
a subroutine) it makes new copies of its variables, just as
all variables have no value when any Liberty BASIC program
has not started to run yet.

Because of this, it was possible to eliminate the line in the
subroutine which resets the variable (noQuote$ = "") because
variables in any function are created from scratch each time 
the function is called.

Understand that this process does not erase the previous
values of the same variables in that function.  Each use of
a function has its own variables.  When the function ends
its variables are discarded.  This is often unimportant, but
sometimes it is useful to write a function which calls
another function, and that second function may need to call
the first (or it may call another which calls the first).
Just imagine what would happen if you went to the bank and
started to fill out a form for a loan and had to excuse
yourself to put money in the parking meter, and then another
customer came in and began writing on your loan application!

The ability for a function to use itself to get the job done
is called recursion.

Here is a very simple (and probably useless) example of the
use of recursion to count to ten:

print countToTen(0)

function countToTen(value)
    countToTen = value
    if value < 10 then countToTen = countToTen(value+1)
end function

In addition to local variables, functions have local branch
labels.  This means that I do not need to worry if I am
duplicating branch labels from one function to the next, or
from the main application space (the part of the program
that starts to run at the beginning of your program).

Global things
--------------------------------------------------------------
Arrays and things with handles are globally visible in Liberty
BASIC v2.0.  This has its pros and cons.  For many kinds of
programming it makes code simpler.  We don't need to add any
code instructing Liberty BASIC to pass arrays and things with
handles (files, windows, and comm port connections).  In other
words we can keep on treating arrays and these other global
things the way we always did before.  On the other hand this
can make our code more complicated because if we need to use
these kinds of resources in our functions we must be careful
how we share them throughout our programs.

Here is a nonsense example:

'fill and display an array with a random quantity of
'numbers
dim numbers(100)
count = fillRandomly(100)
for x = 1 to count
    print numbers(x)
next x
end

function fillRandomly(limit)
    fillRandomly = int(rnd(1)*limit)+1
    for x = 1 to fillRandomly
        numbers(x) = int(rnd(1)*fillRandomly)+1
    next x
end function

When we fill in the array named numbers() inside the function
fillRandomly(), we are filling the same array named numbers()
that we dimension in the start of the example.  This is why
we then have no trouble printing out the contents of that
array.

As an example of a global handle, examine this short program:

'show how to use functions with handles
open "global handles" for graphics as #draw
print #draw, "down"
x = drawLine(50, 50, 150, 50)
x = drawLine(50, 100, 150, 100)
x = drawLine(50, 50, 50, 100)
x = drawLine(150, 50, 150, 100)
input r$

function drawLine(a, b, c, d)
    print #draw, "line "; a; " "; b; " "; c; " "; d
end function

See how in this example it shortens and simplifies our code?
Instead of duplicating that style of print statement for each
line we draw all we need to do is use the drawLine() function.
Since functions always return some value, even if it is zero
as in this case, we must do something with that value.  So
we assign the value to x.

What could be
--------------------------------------------------------------
What we've looked at so far is natural for converting existing
Liberty BASIC programs, but it does tie functions to specific
windows.  To remove this dependency, it is possible that the
function calling mechanism could be extended to make this 
possible:

x = drawLine(#draw, 50, 50, 150, 50)

and

function drawLine(#graphics, a, b, c, d)
    print #graphics, "line "; a; " "; b; " "; c; " "; d
end function

This form is workable and it is visually satisfying, but I
haven't found an acceptable solution for doing this with
arrays.  I can imagine something obvious like the following
but I'm not sure I like it:

'fill and display an array with a random quantity of
'numbers
dim numbers(100)
count = fillRandomly(numbers(),100)
for x = 1 to count
    print numbers(x)
next x
end

function fillRandomly(array(), limit)
    fillRandomly = int(rnd(1)*limit)+1
    for x = 1 to fillRandomly
        array(x) = int(rnd(1)*fillRandomly)+1
    next x
end function

The sort of functionality we see in this example would let
us use a single function with more than one array.

Another feature which would be nice is local arrays.  For
example if an array is dimensioned within a function
that array might be considered local, even if it has the
same name as a global array.  Of course another way to do
this would be to treat only arrays explicitly declared as
global to be visible to functions.

As for requiring that we must always do something about the
return value of a function, I was thinking we could do
something like:

call drawLine(x1, y1, x2, y2)

or just this (no parenthesis needed):

drawLine x1, y1, x2, y2

These would allow us to capitalize on the existing user
function mechanism without the expense of implementing
sub-programs as a completely parallel feature as in some
other BASICs.

I'm open to suggestions about these things, but not at all
unwilling to release v2.0 with user functions support
implemented pretty much as it is now.  New features can always
be added in later releases.  How does the Liberty BASIC
community feel about emulating the way QBASIC does these
things?

I want to open this up for discussion, so I have added a page
to the Liberty BASIC CoWeb where people can have an
opportunity to give feedback about what I've presented.

---------------------------------------------------------
---------------------------------------------------------
BEGINNER'S TUTORIAL ON USER DEFINED FUNCTIONS

Carl has dealt with user defined functions in detail.  The
following little tutorial is meant to explain how to set up
and use these user defined functions in the simplest terms 
and format.  It only deals with the most fundamental parts
of writing and using our own functions.

We use functions in Liberty BASIC all of the time.  Many
functions are an integral part of the language.  One function
is the ABS(x) function.  It returns the absolute value 
(the value without regard to sign) of a number.  Here it is
in action:

a = ABS(-3)

Now, the variable "a" holds the value "3".  We can also
use a variable as a value inside of the brackets:

x = -3
a = ABS(x)

The variable "a" again holds the value "3".  Liberty BASIC
does its work in the background, and all we see is the result.
Let's pretend that we can "see" the ABS function.  It might
look like this:

  function ABS(num)
    IF num >= 0 THEN 
      ABS = num
    ELSE
      ABS = 0 - num
    END IF
  end function

A function may receive a parameter, or a set of parameters, 
it performs an action, or a set of actions, and then it may 
return a value.  The ABS function required only one parameter, 
and it returned a numeric value.  The LEFT$ function requires 
two parameters, and it returns a string value:

    new$ = LEFT$(text$, length)

To use a function, we must list the proper number and type
of parameters.  If we tried the following, it would halt
with an error message:

    new$ = LEFT$(text$)

It is missing a parameter, and that generates an error.  
The next one also generates an error:

    new$ = LEFT$(length,text$)

It contains the proper number of parameters, and they are 
of the proper type, but since they are not in the proper
order, the function perceives the parameters to be of the
wrong type.

Liberty BASIC 2.0 allows us to define our own functions.
Carl has listed the benefits in his article.  Let's talk
about creating our own functions.

---------------------------------------------------------
CREATING OUR OWN FUNCTIONS

Let's start out by structuring our code for maximum ease 
of use.  We can do that by grouping all of our functions
together, possibly at the bottom of the source code.  This
will make them really easy to find.  Carl has added 
function-names to his branch label search window, so we can 
find them without too much trouble, but grouping them together 
makes it easier, still.  

**************************************************************
Carl says:
If you put functions before your code you will need to goto 
or gosub to your code after the functions like so:

dim arrays 'this needs to happen right up front unless you use redim
goto [getStarted]

{function defs}

[getStarted]

Without that jump over the functions, the program will just stop.
Look at fform20.bas for an example of this in action.

Notice also that array dimensioning needs to happen up front unless 
you use redim.  I intend to fix this before LB2.0 is released.
**************************************************************

The syntax for a function requires the word "function" to
start, followed by the name of the function.  Avoid reserved
words, such as Liberty BASIC commands and functions.  If you
try to use reserved words, the compiler will halt with a syntax
error.  You couldn't use a function called "print" for this
reason, but you could use "print1".  Just as variable names
are case sensitive, function names are case sensitive.  A
function named Carl() is not the same as a function named
carl() or a function named cArl().  Here is the syntax
for creating a function:

  function FunctionName(parameter1,parameter2...)
    {basic code routine}
    FunctionName = (value)
  end function


Note from Carl:  "Also, until I can get more specific, it's best 
to keep the [inputLoop] of a Liberty BASIC program outside of 
functions."

Let's write a function.  Let's take in a numeric parameter,
square it within the function, and return the square.

  function Square(num)
    Square = num * num
  end function

The return from a function is contained in a variable that
is identical to the name of the function.  Since we have called
our function "Square()", the returned value will be contained in
"Square".

A number multiplied by itself will give the square of the
number.  Another way to define "square" is to take a number
to the power of 2.  In Liberty BASIC, we would write num^2.
Here is the same function, using the power of two, instead
of multiplying a number by itself:

  function Square(num)
    Square = num^2
  end function

Does it matter which way we write the code inside of the function?
No!  As long as the routine works properly, it doesn't matter
at all to the calling routine.  The calling routine is only
concerned with the result of the function.  Let's take a look
at how we will use our new function within a program.
---------------------------------------------------------
USING OUR OWN FUNCTIONS

We can call upon our function as often as we want.
Here is an entire, simple program that uses our
Square function:

  x = 4
  print Square(x)

  function Square(num)
    Square = num * num
  end function

If you copy and paste the above lines into alpha #4,
you will see this output on the screen:

  16

Run the following code, which adds another function call:

  x = 4
  print Square(x)
  x = 5
  print Square(x)

  function Square(num)
    Square = num * num
  end function

This time, the output on the screen would look like this:

  16
  25

We can use our own functions in the same ways that we use
Liberty BASIC functions.  In LB:
  
  print ABS(-3) + 1

results in output:

  4

Let's see how that works with user defined functions:

  x = 4
  print Square(x) + 1

  function Square(num)
    Square = num * num
  end function

OUTPUT:
  17

If a function returns a value, we can set a variable equal
to that value, allowing us to store it for later use.
The value of Square(x) can be changed if the function is 
called again in the program, but we can conserve the value 
by placing it into the variable, "sq".  Example:

  x = 4
  sq = Square(x) + 1

  print "The value in Square is now ";Square(2)
  print "The value of sq is equal to ";sq

  function Square(num)
    Square = num * num
  end function

OUTPUT:
    The value in Square is now 4
    The value of sq is equal to 17

---------------------------------------------------------
STRINGS IN USER DEFINED FUNCTIONS

If a function is to return a string, rather than a numeric
value, then its name must end with a "$".  This matches the
way Liberty BASIC treats variables.  A function named Carl$()
will return a string value, while a function called Carl() will
return a numeric value.

We already use string functions in Liberty BASIC.  Here's an
example:

  print UPPER$("hello")

produces output:

  HELLO

Let's write a simple string function:

    print Month$(date$())

    function Month$(string$)
        Month$ = LEFT$(string$,3)
    end function

OUTPUT:
    Mar

We can make that particular function even more efficient.  Since
we want it to return the 3-letter month value from the date$()
function, we can put the date$() function within our user defined
function.  In that case, we don't need to pass ANY parameters!

    print Month$()

    function Month$()
        Month$ = LEFT$(date$(),3)
    end function

OUTPUT:
    Mar

We can use our own functions in tandem with Liberty BASIC functions,
just as we can use LB functions in tandom with one another.  For instance,
we might have something like this in Liberty BASIC:

    print upper$(word$("Carl Gundel",1))

OUTPUT:
    CARL


We can combine our own user defined functions and Liberty BASIC functions
in just the same way.  Here's a sample:

    print upper$(Month$())

    function Month$()
        Month$ = LEFT$(date$(),3)
    end function

OUTPUT
    MAR

The parameter types for a function can be a combination of strings
and numerics, and parameter types need not match the type of the
function itself.  Here is an example of a function with a numeric
return, whose parameters are all strings.  This function is similar
to LB's instr() function, except that it returns the last occurance
of string 2 within string 1, rather than the first occurance.

  function lastSpot(string$,a$)
    value = len(string$)
    WHILE mid$(string$,value,len(a$))<>a$ and value > 0
      value = value -1
    WEND
    lastSpot = value
  end function

Here it is in action -- a numeric value is returned, while
the parameters are both strings:

  print lastSpot("one two one","one")

  function lastSpot(string$,a$)
    value = len(string$)
      WHILE mid$(string$,value,len(a$))<>a$ and value > 0
        value = value -1
      WEND
    lastSpot = value
  end function

OUPUT:
  9
---------------------------------------------------------
LOCAL VARIABLES AND INFORMATION HIDING

Carl has addressed the use of global and local variables
in detail in his article.  It is very important, so we'll
talk just a little bit about it again here.

Look at the little program below.  It may not look like it,
but there are actually TWO variables called "name$".  The
contents of one do not affect the contents of the other,
because one "name$" variable is local, contained within
the function, ShowBob$().  If you print the contents of
the variable, "name$" both from within the function, and
outside of it, you will get different results.  Also notice
that the "name$" variable that is used outside of the function
retains its value.  It is exactly the same before and after the
function is called, proving that the variable "name$" that is
used within the function is separate from it's global look-alike.

    print "name$ at start is ";name$
    print "ShowBob$ return is ";ShowBob$()
    print "name$ after function ends is ";name$
    name$ = "Sam"
    print "name$ is now ";name$
    print "ShowBob$ return is ";ShowBob$()
    print "name$ is now ";name$

    function ShowBob$()
        name$ = "Bob"
        print "name$ inside function is ";name$
        ShowBob$ = name$
    end function

OUTPUT:
    name$ at start is
    name$ inside function is Bob
    ShowBob$ return is Bob
    name$ after function ends is
    name$ is now Sam
    name$ inside function is Bob
    ShowBob$ return is Bob
    name$ is now Sam

As Carl has already explained so well, this use of a local
variable insures that we do not accidentally give a bad
value to a variable that is used elsewhere in the program.
Think of it as a sort-of "pre-debugging" technique!
---------------------------------------------------------
Don't forget to visit the Liberty BASIC Community Web at:
http://www.libertybasic.com/CoWeb
---------------------------------------------------------
Brosco and Alyce have written a Book for Liberty BASIC,
which is available in electronic form on a CDROM.
For details:  http://alyce.50megs.com/sss/cd.htm
---------------------------------------------------------
Newsletter compiled and edited by: Brosco and Alyce.
Comments, requests or corrections: Hit 'REPLY' now!
mailto:brosco@orac.net.au or mailto:awatson@wctc.net
---------------------------------------------------------