March 28, 2024, 08:29:25 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Subroutines

Started by REDEBOLT, December 21, 2008, 10:34:10 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

REDEBOLT

I am attempting to define and call a subroutine:
autodefine "OFF"

DECLARE MAT()

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SUB MAT()
def x:float
RETURN

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

OPENCONSOLE
MAT()
PRINT
PRINT "Press any key to close this program"

DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END


I get a compile error that says that MAT() is undefined.
???

Regards,
Bob

Ionic Wind Support Team

In Creative BASIC there is no ENDSUB statement.  So subroutines have to go at the end of the code, not the beginning.


autodefine "OFF"

DECLARE MAT()


OPENCONSOLE
MAT()
PRINT
PRINT "Press any key to close this program"

DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SUB MAT()
def x:float
RETURN

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Ionic Wind Support Team

Ionic Wind Support Team

Of course you can do it though.  You just have to direct the flow of execution around the subroutine:


autodefine "OFF"

DECLARE MAT()
goto start
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SUB MAT()
def x:float
RETURN

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
start:
OPENCONSOLE
MAT()
PRINT
PRINT "Press any key to close this program"

DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END


Paul.
Ionic Wind Support Team

REDEBOLT

Thanks, Paul.

Now for the next problem:

AUTODEFINE "OFF"

OPENCONSOLE
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE MATRIX
DEF m_nr AS INT ' Number of rows.
DEF m_nc AS INT ' Number of columns.
DEF m_pa AS POINTER ' Pointer to MAT.
ENDTYPE

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DEF X AS MATRIX
PRINT
PRINT "Press any key to close this program"

DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END


I get a syntax error on line 12:

"DEF X AS MATRIX"

Also, can I also put the TYPE definition in a component?

Regards,
Bob

Ionic Wind Support Team

Creative isn't as tolerant to comments on the same line as statements as Emergence is.  Just put a colon before the comments in the type definition.

And yes you can put it in a component.

Ionic Wind Support Team

aurelCB

Semicolon also work as coment but in new line...
AUTODEFINE "OFF"

OPENCONSOLE
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE MATRIX
DEF m_nr AS INT :' Number of rows.
; number of rows
DEF m_nc AS INT :' Number of columns.
DEF m_pa AS POINTER :' Pointer to MAT.
ENDTYPE

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DEF X AS MATRIX
PRINT
PRINT "Press any key to close this program"

DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END

crystal_blox

January 10, 2009, 08:39:40 PM #6 Last Edit: January 12, 2009, 04:39:09 AM by crystal_blox
Can anybody tell me:
Just how much expression can be put in a sub call argument?
I'm getting various objections to the code below,
and it's frustrating not knowing the rules.
I remember Paul mentioning no nested brackets,
presumably meaning no "[]" or "()" in an argument expression,
but that doesn't look like the issue here.
It seems to be accepting boolean operator "<" but rejecting boolean operator "=".
I wouldn't mind using "==" at odd times to get around it.


rem - from clock.cba
rem - replacing loading IF's w. sub "forbid" (like "assert")

AUTODEFINE "OFF"
DECLARE   forbid( cond : int  ,  warn$ : string )
def   dx, bkimg : int
def   msg$ : string

rem -  this worked OK;   I think its compact, tidy, readable.
  msg$= "Could not create DirectX screen"
  dx = CREATESCREEN( w1 , 800 , 600 ) :  forbid(dx<0 , msg$)

rem - Problem: this cant be made to work:

  msg$= "Cant load background image"
  bkimg = DXNEWMAP(w1, GETSTARTPATH + "back.jpg" , 800 , 600 , 1 )
                   rem - DXNEWMAP() - quikref:"Returns 0 on failure"
  'forbid(  bkimg=0  , msg$) : ' box: "Variable Wrong Type"
  forbid(  (bkimg=0)  , msg$) : ' box: "Cant load background image"
  'forbid(  (bkimg<>1)  , msg$) : ' OK! clock runs... but I_m not supposed to know "1"
  rem - if all forbids are commented out, image loads & displays & clock runs normally.

DXCREATEMAP w1, 1, 1, 0
DXDRAWMAP w1

run = 1 : WAITUNTIL run = 0

LABEL finis
  CLOSEWINDOW w1 :  CLOSECONSOLE
END
' ====================================================================
mainwindow:
SELECT @CLASS
    CASE @IDDXUPDATE : GOSUB update
    CASE @IDCLOSEWINDOW : run = 0
ENDSELECT
RETURN
' ====================================================================
SUB update : ' stuff
RETURN
' ====================================================================

SUB forbid( cond : int  ,  warn$ : string )
if ( cond )
MESSAGEBOX w1, warn$ , "Error"
goto finis
ENDIF
RETURN


I'm using CreativeBasic v1.01 in XP-sp2.  Had a lot of fun so far.

crystal_blox

January 10, 2009, 09:45:16 PM #7 Last Edit: January 11, 2009, 01:21:46 AM by crystal_blox
I would also like to point out that in a trailing comment
(that is, it's not the first statement on the line),
using a tick in one's diatribe can activate the whole comment,
resulting in attempted execution and errors.
Paste this code in your cba window,
and it should take on multiple colors: green, black, and blue.


a=3 : ' It's not  safe to  ... (black, w. blue "not" and "to")
: ' It's not  safe to  ...  (black, w. blue "not" and "to")
  ' It's not  safe to  ...  (green)
: ' It_s not  safe to  ... (green)
: ' It's not_ safe to_ ... (all black)


Wish it weren't so.  I use trailing comments a lot.

aurelCB

crystal...

First of all , you mix all things together.
You open at same time console,window and dxscreen - of course that's not work
Second you also want close console and window together - not work
You also declare function forbid wich is directly executed on start ?- not work
And of course code wich is on picture is written in wrong way.
You cant use colon before comment in new line.


crystal_blox

Aurel-
   beg to differ on most counts.

- You  can  use a colon before a comment in a new line, at least in Creative Basic.
           I've been doing it all day.   It basically creates a harmless empty statement.
           True it isn't usually useful, but here it helps detail the interpreter's behavior.

- Don't know what you see so wrong in the picture.  (2nd_tick_cases.png)
     Mostly it's just white-space and comment statements.
     My belief is it should be hard to mess anything up using those two things.

- sub forbid was not executed directly on start, it was declared at the start,
        then executed after trying to create a DirectX screen,
        which apparently could fail, judging from this warning-box:

IF CREATESCREEN(w1,800,600) < 0
MESSAGEBOX w1, "Could not create DirectX screen","Error"
CLOSEWINDOW w1
END
ENDIF

      in Graham's example program.  Graham's program is now attached below...

- I opened the unneeded console window to let me print out variables for my debugging.
      Both console and DX-window worked side-by side, just fine.  I recommend it.
      I even got them to both vanish at the same instant whenever the DX-window's closebox is clicked.
      It quits nice and fast that way.  The console-window's closebox does nothing, but no big deal.

- It seems the DX screen shows in the main-window's pane, in Creative-Basic. They're the same window.
        Maybe EB or other basics differ,  I haven't yet seen them enough to know.

- yes I tend to mix things together when they don't affect each other.
      I think a trailing comment is sometimes the clearest place to record execution outcomes
      of a long list of alternative statements.
      Go ahead and delete those comments...it doesn't seem to affect the behavior in those cases.

I guess I was hoping to hear that a version 1.02 might happen someday with those two issues looked at.
I'm studying my Aurora and EB now, but I really wanted to go further with the easy 3D I was getting in CB.


aurelCB

First of all i try Graham example before 2 year and i must say that is exccelent :)
I think that you are to fast.
So try this:

'try this
'AUTODEFINE "OFF"
'DECLARE   forbid( cond : int  ,  warn$ : string )
DEF w1:WINDOW
def dx, bkimg : int
def msg$,msg2$: string
def run:int

rem -  this is right aproach
WINDOW w1,0,0,800,600,@NOAUTODRAW,0,"Creative Basic Clock",main
  msg$= "Could not create DirectX screen"
' check screen size
IF CREATESCREEN(w1,800,600) < 0
MESSAGEBOX w1,msg$,"Error"
Goto finish
ENDIF
 

  msg2$= "Cant load background image"
  'bkimg = DXNEWMAP(w1, GETSTARTPATH + "back.jpg" , 800 , 600 , 1 )
'check newmap
IF DXNEWMAP(w1,GETSTARTPATH + "Back.jpg",800,600,1) = 0
MESSAGEBOX w1,msg$,"Error"
Goto finish
ENDIF

'create a blank map filled with tile#0
DXCREATEMAP w1,1,1,0
DXDRAWMAP w1


run = 1
WAITUNTIL run = 0
CLOSEWINDOW w1
END
' ====================================================================
SUB main
SELECT @CLASS

    CASE @IDDXUPDATE
Gosub dxupdate

    CASE @IDCLOSEWINDOW
run = 0

ENDSELECT
RETURN

'SUB forbid( cond : int  ,  warn$ : string )
'// cond is not changed // - so this not work
'if ( cond )
' MESSAGEBOX w1, warn$ , "Error"
' goto finis
'ENDIF
'RETURN

SUB dxupdate
DXDRAWMAP w1
'show the changes
DXFLIP w1
RETURN

finish:
Closewindow w1
END

Johnny

Hello Cristal,

I noticed also the strange behaviour of the remark accent when it's not in the beginning of a line, to avoid this I like to use "rem" instead, that works just fine.
Change your example to this, then the colloring is OK...

a=3 : rem It's not  safe to  ... (black, w. blue "not" and "to")
: rem It's not  safe to  ...  (black, w. blue "not" and "to")
  ' It's not  safe to  ...  (green)
: rem It_s not  safe to  ... (green)
: rem It's not_ safe to_ ... (all black)


The use of "=",">=","<=" (in particular the equal sign) seems to be impossible inside a SUB call, but "<", ">" and "<>" do work fine.
It is easy to overcome this by inverting the comparision like this:
... X = Y ...   becomes   ...(X <> Y) - 1 ...
... X <= Y ...   becomes   ...(X > Y) - 1 ...
... X >= Y ...   becomes   ...(X < Y) - 1 ...
(The "- 1" after the compare part inverts true to false and false to true, thus inverting the comparisions results)

In your program...
forbid(  bkimg = 0  , msg$) : ' box: "Cant load background image"
Becomes then...
forbid(  (bkimg <> 0) - 1  , msg$) : ' box: "Cant load background image"

Don't shoot me! I'm only trying to offer a work around...   ;)

Greetings to all,
Johnny

aurelCB

From user guide:
DXNEWMAP window, bitmapfile, width, height, tiles
there is no like:
bkimg=DXNEWMAP window, bitmapfile, width, height, tiles
Only this function work similiar:
tile = DXGETMAPTILE (window,x,y)

In this case work:
bkimg=0
IF DXNEWMAP(w1,GETSTARTPATH + "Back.jpg",800,600,1) = bkimg
   MESSAGEBOX w1,msg$,"Error"
   Goto finish
ENDIF


crystal_blox

January 14, 2009, 03:25:00 AM #13 Last Edit: January 14, 2009, 03:40:23 AM by crystal_blox
Aurel, Johnny,  thanks for your replies.

I think I can use what Johnny suggested:
forbid( (bkimg<>0)-1 , msg$ )

" : REM " I like less because it fills the almost-white space I usually have, " : ' ",
in between my dense wordy code and my dense wordy comment.
And because I'm often running out of line-length.

Aurel, my reason for inventing the subroutine is:  I just don't want to use those 4-line IF-ENDIF blocks.
They fill the page with housekeeping,  pushing the main program sequence,
which I'm trying to see clearly and think about,  off the top or bottom of the page.
And that IF block is used repeatedly in this program and others.
Right now I really want my programs to say everything only once,
and I see modern Basic getting pretty close to allowing me to reach that goal.
I admit, if I ever have occasion to really work with other programmers,
I might need to use your more-conventional style.

About all that DXNEWMAP stuff -

I understand there are usually two forms of a subroutine call:
  the "statement" or "command" form:
thissub a, b, c
  which does not return a value,

  and the "function" form:
d = thissub( a, b, c )
  which returns a value.

I've noticed that it's becoming common in interpretive languages  to allow the use of either form
for any subroutine name that exists and returns a value.
If a function is used in the command form,  it's return value is simply not used by the program.

The userguide quickref page shows DXNEWMAP in command form, 
but then finishes with "Returns 0 on failure",
so I infer that the function form DXNEWMAP(...) must also work.

You gave me an idea of trying
0=bkimg
instead of
bkimg=0
the idea being that maybe the impossibility of assigning a new value to literal 0
might make the interpreter see "=" as the boolean operator, not the assignment command.
I might play around with stuff like that.

Thanks again, guys.

aurelCB

January 14, 2009, 06:53:12 AM #14 Last Edit: January 14, 2009, 11:26:33 AM by aurelCB
Hi again...
I'm not expert for declared subrutines(called functions).
And i dont use them very much in my programs ( read - 'i dont like them').
But i spend some time reading user guide and make one small example.
Little changes, i also add work with pointer .
I hope that is good.

Zlatko

DECLARE DrawMessage(w:WINDOW,msg$:STRING,x2:INT,y2:INT)
DECLARE DoCircle(x:INT,y:INT,size:INT)
DEF win:WINDOW
DEF cond:int
DEF run:int
DEF msg:pointer

Window win,0,0,400,400,@SIZE|@MINBOX|@MAXBOX|@CAPTION,0,"SUB Demo",mainwindow
Setwindowcolor win,rgb(200,200,230)

Docircle (100,100,25)

IF cond=1
DrawMessage(win,"Circle",100,150)
Endif
'read and show pointer in message box
MessageBox win,#msg,"Message with Pointer"

'-----------------------------------
run = 1
waituntil run = 0
closewindow win
end
'-------------------------------
mainwindow:
select @class
    case @idclosewindow
        run=0
endselect
return
'-----------------------------------------
REM window & string variable passed by reference
SUB DrawMessage(w:window,msg$:STRING,x2:INT,y2:INT)
    move w,x2,y2
    print w,msg$
'show string "Circle" in messagebox
IF cond=1 then MessageBox w,"IF cond = "+str$(cond)+"; "+ msg$,"Condition"
msg$="msg Pointer"
'set pointer to string msg$
msg=msg$
RETURN
'-----------------------------------------
'passed by value
SUB docircle(x,y,size)
CIRCLE win,x,y,size
cond=1
RETURN cond


crystal_blox

Zlatko, is it?   My name is Jim.   

I ran your example. 
Nice to know what pointers look like.
and to see how to print right inside the graphic window.

Guess what, if you delete the last word of your program: "cond",
it also works; it does exactly the same thing!

The line
  RETURN cond 
tries to send the value of cond (previously set to 1)
back to the main program.

The place this value goes to is right where the sub was called:
Docircle (100,100,25)

But there is no "=" there to catch the return value and put it into a variable,
such as:
DEF resultcode: int
...
resultcode= Docircle (100,100,25)


With no "=" present, the return value is simply ignored and forgotten.
That's OK, you didn't want to do anything with it then.

If nobody in the main program is using the value,
perhaps there is no need to send it.
That's why it's OK to delete the "cond" after "RETURN".

Creative Basic is quite tolerant of that kind of thing.
It allows you 3 ways to say docircle:
Docircle 100,100,25         : ' draws a circle
Docircle (100,100,25)       :  ' draws a circle
ItWorked = Docircle (100,100,25)   : ' draws a circle  and sets ItWorked to 1.
They all work OK, and do what the programmer probably meant to do.

Notice that "cond" and "win" are defined
in the main program, and not defined in the subroutine docircle.
So when docircle executes
cond=1
it finds the variable that was defined far above
and sets it to 1.
Then cond=1 for all the main program,
and there is no need to send it to the main program by using RETURN.

When would one need to use "RETURN xxx" ?
When there is an "=" in the place that called the subroutine, _and_:
   a)  variable xxx was DEF'd inside the subroutine, or
   b) the sub is executed a bunch of times, and returns a different value each time,
and you want to make sure your main program doesn't use a stale old value
   c) the return value is put in different variables by "=" on different times:
  a1= docircle(50,50,20)
  ...
  a2= docircle(70,70,30)
       
   d) you want to make it obvious in your code that the value came from that subroutine.
        If you say
docircle(...)
if cond=1 then ...

it can take much looking around to make sure that only docircle changed cond.

If, on the other hand, you say:
cond=docircle(...)
if cond=1 then ...

...

sub cond(...)

return 1

then you get to feel sure that cond came from docircle when IF uses it.

I talk too much.  I better go to bed...

Jim
     

crystal_blox

I see I have negative karma.  :-[  ???   I know I'm not entirely tactful,
but if there's something specific,  a  message might help me out.

Jim

mrainey

You want karma, you got karma!   :D
Software For Metalworking
http://closetolerancesoftware.com

aurelCB

Yes Jim you right i just forget delete cond after RETURN. ::)
And of course variable cond is global .

crystal_blox

Thanks, Mike!  That answers my question.  :)

Zlatko,  I never can tell exactly how much you know.
Sometime I'll look closer at your website.

aurelCB

No problem,Jim... :)
Just look at the website ;)
And i allways forget something(my old problem ::))

crystal_blox

Just like to share another bug & workaround.
Sometimes when I'm programming I suddenly get to a point where further progress is blocked by unreasonable error messages that I can't figure out how to eliminate.  I think I've found a helpful clue. Sometimes the error refers to a name in a subroutine, but it's really caused by a different error _after_ the subroutine returns.
In this example a "variable not found" message refers to inkey$  ???  in my subroutine "waitkey",
but the real error is an unbalanced quote a line or two after the "gosub waitkey" statement.
I provided alternative lines to enable or disable using comment-ticks (').
Using them you can add the missing close-quote and see the error message go away,
or disable the gosub and use a non-subroutine line with inkey$ instead,
in which case the error message refers correctly to the missing close-quote.
Anyway, if you have an error message that's just crazy, look around for other errors nearby.


rem  Bug demo "inkey not found"
rem  to show how an unrepresentative error message,
rem    [variable not found], referring to a known keyword
rem     in a subroutine, can be elicited by a real syntax error
rem     in the program flow after the sub's return
rem  CreativeBasic v1.01
rem  Jim Swenson 2009-02

autodefine "OFF"

def fmt$ : string
def vwXspan : float  : vwXspan = 4

OPENCONSOLE

gosub waitkey
'print "Press a key ###" : do : until ( inkey$ <> "" )
rem   if "gosub waitkey" line above is replaced with
rem       the "do:until" line, then a correct error message
rem       refers to line 22 [fmt$=" ] below

rem intervening statement:
vwXspan = 5

'fmt$ = "" : rem  with this line, program runs as expected
fmt$ = "  : rem  <-- the real error in main program.
rem  At first gosub waitkey, an improper error-
rem     message: "line 41: variable 'inkey$' not found"

print "view_span= ", vwXspan, " meters"
gosub waitkey

print "All done, quitting when you:"
gosub waitkey

Label finish
closeconsole
end

sub waitkey
print : print "Press any key to continue..."
do
until ( inkey$ <> "" )
print
return