Παρασκευή, 12 Μαΐου 2017

Αναθεώρηση 23 (Έκδοση 8.7)

Σε αυτήν την αναθεώρηση βρήκα επιτέλους την τέλεια λύση για τον συλλέκτη σκουπιδιών. Τα αντικείμενα που τα χειριζόμαστε με αναφορά με δείκτη (και σε αυτές υπάρχει μετρητής αναφορών, ως γνήσια αντικείμενα), τα χρησιμοποιώ μέσω ενός αντικειμένου mHandler, το οποίο έχει κάποιες ενδιαφέρουσες δυνατότητες, μια εκ των οποίων είναι ότι τερματίζει πρώτα αυτό και στο terminate (deconstructor) ενώ έκανε απλά αποδέσμευση της αναφοράς στο αντικείμενο, τώρα κοιτάει αν στον συλλέκτη σκουπιδιών έχει αναφορά (δεν έχουν όλα), και αν ναι τότε κοιτάει τον μετρητή, και αν δει ότι είναι δυο, μία του συλλέκτη και μια του mHandler, τότε το καθαρίζει από το συλλέκτη και μετά καθαρίζει και το δικό του στο τέλος. Ο τελευταίος καθαρισμός μπορεί να προκαλέσει καθαρισμούς και σε άλλους mHandler που μπορεί να ήταν αποθηκευμένοι σε αυτό το αντικείμενο. Τα αντικείμενα που έχουν "παρουσία" στο συλλέκτη είναι πίνακες, καταστάσεις, σωροί, και αυτά μπορούν να έχουν αναφορές σε άλλα τέτοια αντικείμενα.
Ο συλλέκτης σκουπιδιών μπήκε για να βρίσκει τις κυκλικές αναφορές, δηλαδή αν ένα αντικείμενο έχει στα περιεχόμενά του αναφορά στο ίδιο, ή έχει αναφορά σε άλλο και το άλλο στο  πρώτο. Η εντολή Λίστα μας δείχνει εκτός από τις τρέχουσες μεταβλητές και τον αριθμό αντικειμένων που έχει ο συλλέκτης (αν έχει δείχνει). Υπάρχει εντολή Άδειασε Σκουπίδια η οποία κάνει το εξής: Πρώτα μαζεύει σε ένα δεύτερο αντικείμενο "συλλέκτη σκουπιδιών" μόνο τους δείκτες χωρίς να είναι "ενεργοί", δηλαδή απλά τους κάνει κλειδιά, και για κάθε αντικείμενο δίνει τον καθαρισμό τους. Μόλις τελειώσει το μάζεμα, κοιτάει τον κανονικό συλλέκτη σκουπιδιών, και καθαρίζει ότι έχει μείνει. Επειδή την εντολή θα την δώσουμε μέσα από τμήμα, ενδέχεται κάποια αντικείμενα να μην μπορούν να καθαρίσουν, γιατί υπάρχει στο χώρο μεταβλητών, ή στο σωρό του τμήματος μια αναφορά τους.  Με την επιστροφή από το τμήμα οι αναφορές από το χώρο μεταβλητών θα διαγραφούν (και όπως το έφτιαξα θα διαγραφεί και η τελευταία αναφορά από το συλλέκτη). Και η Καθαρό (Clear) καθαρίζει τον συλλέκτη σκουπιδιών, αλλά εδώ με ένα πέρασμα, όχι με το διπλό όπως η Άδειασε Σκουπίδια (Flush Garbage). Αν γνωρίζουμε ότι κάποιες Καταστάσεις έχουν αναφορές σε άλλες, τότε μπορούμε να δίνουμε το Καθαρό όνομα_κατάστασης και αυτή καθαρίζει με τρόπο όλα τα στοιχεία. Αυτή η εντολή καθαρίζει στοχευμένα τα αντικείμενα, ενώ η Άδειασε Σκουπίδια και η Καθαρό καθαρίζουν τα αντικείμενα, απ΄όποιο τμήμα και αν φτιάχτηκαν. Όπως και να έχει τα "σκουπίδια" καθαρίζονται στο τερματισμό της εφαρμογής, μια φορά από το συλλέκτη σκουπιδιών (και αυτός είναι αντικείμενο).

Βρήκα επίσης και ένα σφάλμα που είχε να κάνει με τους τελεστές και μέσα σε ένα μπλοκ Για Αυτό {} δεν λειτουργούσαν! Διορθώθηκε και αυτό.

Παρακάτω έχω δυο προγράμματα στα αγγλικά. Ένα δείχνει πώς μια λάμδα συνάρτηση με κλείσιμο ενός αντικειμένου σωρού, μπορεί να λειτουργήσει για να παίρνει και να δίνει στοιχεία! Στο παράδειγμα παίρνει και δίνει και αντικείμενα! (σε αυτό βρήκα το θέμα με τους τελεστές).

Clear  \\  clear and empty garbage collector - not needed always
Flush  \\ empty
\\ using Stack to process data in Lambda function
a=Lambda st -> {
      Read cmd
      \\ Select case need one statement in next line from a Case
      \\ (no second in row allowed), otherwise use { } for any code
      Select Case cmd
      Case 0
            st=Stack
      Case 1 ' is empty
            =Len(st)=0
      Case 2 ' len
            =Len(st)
      Case 3 ' merge To bottom
            {
                  N=[] \\ get current Stack, and leave it empty
                  Stack st {
                         Stack N
                  }
                  =True
            }
      Case 4
            =Stackitem(st, Number) \\ second parameter passing to lambda, read from function stack.
      Case 5
            Stack st {=[] } \\ return a Stack object by swaping  st and an empty one.
      Case 6
      {
            Stack st { Stack } \\ display Stack (current, is st)
            =True
      }
      Case 7 '' change item
      {
            Stack st
            Read Where
            Shift Where+1 : Drop
            Shiftback Where
            st=[]
      }
      Case 8
            Stack st {Flush}
      Case 9 ' copy2new
            st=Stack(st)
      Case Else
            =False
      End Select
}
m=a(0)
merge_stack=3
show_stack=6
show_item=4
change_item=7
show_len=2
empty_stack=8
copy2new=9
m=a(merge_stack,1,2,3,4,5)
m=a(merge_stack,11,12,13,14,15)
m=a(show_stack)
For i=1 To a(show_len) {
      Print a(show_item, i),
}
Print
For This {
      \\ block for temporary definitions
      Group Alpha {
            x=1, y=2
            Operator "<>" (N) {
                  Push N.x<>.x or N.y<>.y
            }
            Operator "++" {
                  .x++
                  .y++
            }
      }
      m=a(merge_stack,Alpha)
}
pos_alpha=a(show_len)

Print "position of alpha", pos_alpha
beta=a(show_item, pos_alpha)
Print Type$(beta)
Print beta.X, beta.y
beta.x+=100
m=a(change_item, pos_alpha, beta)
For i=9 To a(show_len) {
      For this {
            Local N=a(show_item, i)
            Print Type$(N), i
      }
}
For beta {.x=0 : .y=0}
delta=a(show_item, pos_alpha)
Print Type$(delta)
For delta {
      Print .x, .y
}
a2=a
\\ now [a2] and [a] reference same Stack
m=a2(9)
\\ but not now.
Print a2(show_len), a(show_len)
\\m=a(empty_stack)
\\Print a2(show_len), a(show_len)
m=a(change_item, pos_alpha, beta)

For This {
       \\ block for temporary variables/modules/functions
      delta10=a2(show_item, pos_alpha)
      delta20=a(show_item, pos_alpha)
      Print delta20<>delta10
      \\ Also now work for items in evaluator only
      Print a2(show_item, pos_alpha)<>a(show_item, pos_alpha)
      delta10++
      delta20++
      Print delta10.x, delta10.y
      Print delta20.x, delta20.y
      delta10=delta20
      Print delta20<>delta10
}



.
Το δεύτερο λέγεται Funny Loops. Και εδώ έχουμε λάμδα συναρτήσεις, και κάνουμε το εξής: Θέλουμε κώδικας από λάμδα συνάρτηση να τρέξει σε μια άλλη λάμδα συνάρτηση μαζί με μια τρίτη που θα κανονίζει το πόσες φορές θα τρέχει (με αρχική τιμή, τελική και βήμα, το βήμα προαιρετικό). Δεν μιλάμε για απλές επαναλήψεις. Είναι τέσσερις "ειδικές". Στην πρώτη έχουμε μια διακοπή βάσει ενός ορίου (ας το θεωρήσουμε ως γεγονός), και μετά συνέχιση από το σημείο που σταμάτησε, συνεχίζοντας να χρησιμοποιούμε το αντικείμενο επανάληψης (τη λάμδα για τον σκοπό αυτό). Η δεύτερη πάλι με το όριο, το αναπρογραμματίζει σε κάθε εκτέλεση και έτσι κάνει βηματική εκτέλεση. Η τρίτη δεν ενδιαφέρεται για την μεταβλητή που απαριθμεί το αντικείμενο επανάληψης, αλλά έχει μια εσωτερική στατική μεταβλητή και αυτή αλλάζει σε κάθε επανάληψη. Στην τέταρτη περίπτωση έχουμε ένα αντικείμενο που δίνει μια δική του συνάρτηση με αναφορά και σε κάθε χρήση της εσωτερικά στην λάμδα "μηχανή επανάληψης", αλλάζει μια μεταβλητή του αντικειμένου που ανήκει η συνάρτηση. Ταυτόχρονα όπως είναι η δομή While (Ενώ) σε κάθε επανάληψη εκτελείται και το μπλοκ εντός της While (ενώ ο κώδικας που εκτελείται για να βγάλει το τι θα κάνει η While, εκτελεί το κώδικα της συνάρτησης του αντικειμένου). Οπότε σε αυτό το μπλοκ έβαλα να περιστρέφεται ένα αντίγραφο που βγάζει άμεσα ο διερμηνευτής της εικόνας με διαφάνεια στο ματζέντα (5) 100% και μερική διαφάνεια στο υπόλοιπο, και μπορούμε με το ποντίκι καθώς περιστρέφεται να το μετακινήσουμε ενώ το νούμερο από το μετρητή τον βλέπουμε σε μια "μπάρα πλήρωσης" όπου το φωτεινό μέρος θα καλύψει το σκούρο στο 100%.



Clear \\ clear static too
FKey 1, "Cls, 0 : Edit "+module$
FKey 5, module$
Font "Verdana"
Form 70,35
Cls 3
Pen 14
Double
Report 2, "Funny Loops.."
Normal
Cls 5,2
old_italic=Italic
Italic 1
Pen 15 {Report 1, {Look how we can mix proportional font with same font  as monospace font} }
Italic old_italic ' restore italic to old value
\\ iterator
ForEach=lambda (x, x1) -> {
      st=1 \\ this is optional
      read ? st
      =lambda x ,x1, st (&n) -> {
            =true
            if x<=x1 then {
                  n=x : x+=st
            }  else =false
      }
}
\\ execution of a lambda function by iterator
\\ get more parameters, from stack (using call statement)
Lcode=lambda i (&m) -> {
\\ choose to use  a lambda by value
\\ or any function by reference, using islet (is letter)
\\ check head of stack if is string (function references in M2000 are strings)
      If islet then { read &cd() } else read cd
      =false
      if m(&i) then {
            Try ok {
                  call cd(i)
            }
            if not ok then exit
            =true
       }
}
Z=Foreach(60,80,2)
CodeW=lambda (i) -> {
      Let limit=1 \\ this is optional
      Read ? limit
      Print i, limit
      if i>limit then =i ' error
}
\\ print prints with transparent background for fonts
\\ Print Over erase a line before, and set all line one field (temporary)
Print Over "Try iterate code using an iterator and  a secondary limit, if limit break then recalibrate iteration using other data, here other limit"
\\ but Print Over leave one line, so we can fill this line with Print Unter (also change line)
Print Under
\\ Print Over, Print Part and Print Under can be used for making columns with diffrent width
\\ Here is the first loop (empty block)
While Lcode(&z, CodeW,75) {}
n=error
If n>75 then {
      Print "out of scope...recalibrate"
      while Lcode(&z, CodeW,100 ) {}
}
Print Under
Print Over "Example of step by step execution"
Print Under
Z=Foreach(10,15)
n=0
\\ Pen { } change temporary pen to black
\\ using loop we mark block for loop at the end of block execution
\\ Calling a function with Call return error if function return non zero value.
\\ so here we get Error and if is not zero then we do next loop
Pen 0 {
     Print Over ~(0,7,14),$(0,8), "Step"+str$( n+1),@(tab),
     \\ also here we have an empty block
      while Lcode(&z, CodeW,n) {}
      n=error
      if n<>0 then loop
}
\\ here is the lambda with static variable
\\ static variables are per execution object (attached to parent object), no per function (as code)
\\ so if this lambda ...moved to another execution object, passing as parameter
\\ then static i get 1 and start new count.
CodeW=lambda -> {
      Static i=1
      Print Over ~(14,8),$(4,8),"just run, no need iteration number ", i
      i++
}
Z=Foreach(1,5)
Print Over "Simple iteration , using static counter inside code"
\\ Here we have a repeat {} until block
Repeat {Print Under} Until Not Lcode(&Z,Codew)
Print Over "Iteration using group's function, passing by reference, altering group member counter"
Print Under \\ print underline and change line too
Group Alfa {
      counter
     Function M {
            .counter++
      }
}
Z=Foreach(200,499)
y=row
\\ we use a$ for image holder
a$=""
Mouse.icon Hide
Print $("0.00%"),
\\ and here is the "game"
While Lcode(&Z, &Alfa.M()) {
    FeedBack(y, Alfa.counter/300, "  press space to exit early")
    Move 0, 0
    copy scale.x,scale.y to a$
    Move mouse.x, mouse.y
    Sprite A$,, Alfa.counter,40,80 \\ leaving 2nd parameter, to automatic  match the paper color for 100% transparent
    If keypress(32) then exit
    Refresh 5000 \\ rfefresh now and reset counter for next refresh  5 sec later (never happen)
    Sprite Sprite$ \\ when Sprite write, altered background saved to Sprite$, so now sprite erased
    \\ Hold take all screen, and Release restore screen to that we take with Hold. But here we use Sprite Sprite (we have only one)
    Wait 5+Random(1,11-Alfa.counter/30)*2
}
Print
Print $(""),
Print "Counter:";Alfa.counter
Cls ,Row
Mouse.Icon Show
Sub FeedBack(y, val, msg$)
     local N
     Pen 15 {
          Cursor 0, y
          N=round(val*100,0)
          Print Over $(0,8), val, @(tab),$(4), ~(7);string$("[]",50);msg$;@(tab), ~(11),string$("[]", N div 2)+string$("[", N mod 2);
    }
End Sub