Author Topic: Recursive methods  (Read 2425 times)

0 Members and 1 Guest are viewing this topic.

Brian Alvarez

  • Guest
Recursive methods
« on: May 30, 2019, 10:01:29 AM »
 Charles, how tested is recursiveness with functions? I am experiencing some issues and i am clueless right now.

« Last Edit: May 30, 2019, 10:09:46 AM by Brian Alvarez »

Charles Pegge

  • Guest
Re: Recursive methods
« Reply #1 on: May 30, 2019, 10:07:01 AM »
Well tested. O2 is packed with recursions, but It makes debugging a real challenge. You need to be able to monitor your recursion route, especially with indirect recursions.

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #2 on: May 30, 2019, 10:32:47 AM »
This code:

Code: [Select]
FUNCTION RECURSIVE(BYVAL INT LVL) AS LONG


    IF LVL > 5 THEN
        RETURN 0
    END IF

    INT I = 0
    REDIM STRING LS(5)
   
    FOR I = 1 TO 5
        LS[I] = "LEVEL " + str(LVL) + " STRING"
    NEXT I       
   
    print space(LVL*5) " before going deeper: " + LS[1] chr(13, 10)
    RECURSIVE(LVL+1)
    print space(LVL*5) " after going deeper: " + LS[1] chr(13, 10)
   
END FUNCTION

RECURSIVE(0)

Outputs this:

Code: [Select]
before going deeper: LEVEL 0 STRING
      before going deeper: LEVEL 1 STRING
           before going deeper: LEVEL 2 STRING
                before going deeper: LEVEL 3 STRING
                     before going deeper: LEVEL 4 STRING
                          before going deeper: LEVEL 5 STRING
                          after going deeper: LEVEL 5 STRING
                     after going deeper: LEVEL 5 STRING
                after going deeper: LEVEL 5 STRING
           after going deeper: LEVEL 5 STRING
      after going deeper: LEVEL 5 STRING
 after going deeper: LEVEL 5 STRING

After going deeper, all strings are overwritten....

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #3 on: May 30, 2019, 11:10:23 AM »
Code: [Select]
STRING LS[5]
and

Code: [Select]
DIM STRING LS(5)
Both work fine, but you have to know how many strings to allocate, because only literals are alllowed...

In my program i do this:

Code: [Select]
    LONG NELEMS = PARSECOUNT(O, 0, ";")-1   
   
    REDIM STRING LS(NELEMS)

Allocating space for hundreds of lines (to be safe) when only one is required is not very efficient... what can i do when speed is crucial?

Charles Pegge

  • Guest
Re: Recursive methods
« Reply #4 on: May 30, 2019, 12:45:10 PM »
Hi Brian,

redim currently creates static arrays (when inside a function), but I think it would be generally safe to remove the static constraint.

  #ifndef %2_buffer
    dim static string %2_buffer = ""
    dim static %1 byref %2
  #endif


This is the core redim macro. You can override it:
Code: [Select]
def redim
  #ifndef %2_buffer
    dim static string %2_buffer = ""
    dim static %1 byref %2
  #endif
  scope
    int _qb_ = %3
    int _le_ = len %2_buffer
    int _qn_ = _le_ / sizeof(%1)
    #if match "%4","clear"
      int _i_
      for _i_=1 to _qn_
        #if typecodeof(%2)>=0x200
          #ifdef %1.destructor
            %2[_i_].destructor
          #endif
        #elseif typecodeof(%2)>=0xa0
          %2[_i_]=""
        #else
          %2[_i_]=0
        #endif
      next
    #endif
    #if typecodeof(%2)>=0xa0
      if _qb_<_qn_
        _qb_=_qn_ 'disallow reduction
      endif
    #endif
    if _qb_ > _qn_
      %2_buffer += nuls( sizeof(%1) * (_qb_ - _qn_))
    elseif _qb_ <  _qn_
      %2_buffer = left( %2_buffer, sizeof(%1) * _qb_ )
    endif
    @%2=strptr(%2_buffer)
  end scope
end def
« Last Edit: May 30, 2019, 12:52:44 PM by Charles Pegge »

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #5 on: May 30, 2019, 03:34:38 PM »
Ok, thanks Charles!

 Is it safe if i (instead of overriding it) make a copy of it with.. lets say... the name "redim2" with the static removed?
I use REDIM in other areas of the program and i dont want to disrupt their actual behaviour.

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #6 on: May 30, 2019, 05:19:26 PM »
It is indeed well tested. And pretty fast! I can make 10000 recursions to my complex function in 0.2 seconds.... not bad!!! :D

Charles Pegge

  • Guest
Re: Recursive methods
« Reply #7 on: May 30, 2019, 08:50:53 PM »
If a variable is first redimed in global space, it will always be 'static' anyway. Are there any instances where you need an implicitly static redim?

There is the issue of using static variables in threadable functions.

Also, do any of your classes use redim?

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #8 on: May 30, 2019, 10:16:54 PM »
 Hello Charles, No... not anymore. None of them use DIM or REDIM anymore.  For the moment i used a clever alternative that i hope you can see soon.
The recursive feature was for improving the JSON features. Now any UDT can be used for working with JSON. Yeah!

 Plus i added a new datatype... JSON. It works pretty nice! I hope the world can see it soon. :) It can parse any JSON string and allow the compiler to
use it in an Object-oriented way. No need to declare its nodes!

Code: [Select]
LOCAL J AS JSON = "{""somestring"" : ""THIS IS THE DATA CONTAINED HERE""}"

STDOUT J.somestring

 ;D

Added:
 The data source for JSON variables does not need to be a string literal, obviously. The engine does not parse literal strings to "guess" its members.
The data source can be a string, or something downloaded from internet. Everything is procesed at run time, not compilation time.




« Last Edit: May 30, 2019, 10:24:23 PM by Brian Alvarez »

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #9 on: May 30, 2019, 10:21:04 PM »
By the way... what is the issue with STATIC and THREADABLE functions?
« Last Edit: May 30, 2019, 11:05:56 PM by Brian Alvarez »

Charles Pegge

  • Guest
Re: Recursive methods
« Reply #10 on: May 31, 2019, 01:20:25 AM »
Functions which may be accessed by more than one thread at the same time, generally need to avoid using static variables. They will produce the same over-writing conflicts that you found with recursion.

PS: JSON is new to me. I will have to study further.

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #11 on: May 31, 2019, 10:07:43 AM »

 Well... how about converting STATIC variables into THREADED variables when declared nside a THREADED function?
I already implemented them, so, it should be no problem.

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #12 on: May 31, 2019, 08:16:12 PM »
Charles, if you want, you can implement threaded variables fairly easy, take a look at:

  • TlsAlloc()
  • TlsFree()
  • TlsSetValue()

Basically all you need to do is have TLS pointer and a Global array, each thread will point to a different slot in the global array. Here's how i did it, this class works for string and wstring:

Code: [Select]
MACRO ¤TYPE_STR_TRV(dtype)
    ¤TRV_NAME_DEF(dtype)
   
        dim ss(200) as dtype
        int siz = 0 
        sys adr = 0
        int ntm = 0
        int ta  = 0
        int gix = 0       
       
        method constructor(int sv, av, nt)
            siz = sv
            adr = av
            ntm = nt
            ta  = ¤TlsAlloc()
        end method
       
        method destructor()
            int i
            for i = 1 to 200
                ss[i] = ""           
            next i
            ¤TlsFree(this.ta)
                               
        end method
       
        method alloc() as int
            this.gix += 1
            ' to do: redim ss if necessary!                               
            ¤TlsSetValue(this.ta, this.gix)
            ss[this.gix] = ""
            return this.gix
        end method
       
        function w(dtype v)
            int ix = ¤TlsGetValue(this.ta)
            if (ix=0) then ix = this.alloc()
            ss[ix] = v
        end function
       
        function r() as dtype
            int ix = ¤TlsGetValue(this.ta)
            if (ix=0) then ix = this.alloc()
            return ss[ix]
        end function
       
        function p() as sys
            int ix = ¤TlsGetValue(this.ta)
            if (ix=0) then ix = this.alloc()
            return @ss[ix]
        end function
       
    end class
END MACRO

This is an old version that still uses DIM, but you can use any method of storing strings. I currently use getmemory(), but that class is more complex and is not as clear of an example of the TLS functions. This old one is clearer.



:)
« Last Edit: May 31, 2019, 09:13:58 PM by Brian Alvarez »

JRS

  • Guest
Re: Recursive methods
« Reply #13 on: June 01, 2019, 10:01:04 AM »
Quote
Plus i added a new datatype... JSON. It works pretty nice! I hope the world can see it soon.  It can parse any JSON string and allow the compiler to
use it in an Object-oriented way. No need to declare its nodes!

I have been using the MySQL server as my JSON parsing engine. The project is mirroring a remote DB which I convert from JSON data to standard table schemas.

Brian Alvarez

  • Guest
Re: Recursive methods
« Reply #14 on: June 01, 2019, 10:18:24 AM »
John, can you show me an example of what you do with JSON? I would like to see if im covering all the needs with it.