Κυριακή 8 Μαΐου 2016

Αναθεώρηση 9 (μικρό bug)

Υπήρχε ένα μικρό Bug, που αφαιρέθηκε στην  εντολή Διόρθωση (Edit.Doc) για το άνοιγμα αντικείμενου εγγράφου στον διορθωτή κειμένου (γίνονταν στην περίπτωση που δεν είχαμε χρωματισμένο κείμενο και δεν εμφάνιζε γραμμές, και σε μερικές περιπτώσεις προκαλούσε κατάρρευση του διερμηνευτή).





Παρασκευή 6 Μαΐου 2016

Αναθεώρηση 7 (αρκετές διορθώσεις)

Έψαξα περισσότερο το κώδικα ειδικά μετά από τις τελευταίες μεγάλες αλλαγές. Ελπίζω να τελειώσω σύντομα με τα bug.

Στα regional settings για Ελλάδα έχουμε το κόμμα για διαχωριστικό δεκαδικών. Κανονικά βάζουμε με τελεία στο κώδικα και παίρνουμε με ότι είναι (εδώ με κόμμα) στην οθόνη ως εξαγωγή.
όμως στο inventory επειδή οι τιμές διαβάζονται πότε ως αριθμός και πότε ως αλφαριθμητικό...πώς θα ερμηνεύουμε το κόμμα και πώς την τελεία;
Και τα τρία Print εδώ δίνουν 12,56 με κόμμα δηλαδή. To αλφα(300) αν διαβαστεί ως αριθμός θα δώσει το 12, γιατί το κόμμα, ο διερμηνευτής δεν το μετράει σαν διαχωριστικό δεκαδικών αλλά ως διαχωριστικό αριθμών. Εντούτοις η val() ή τιμή() διαβάζει σωστά το 12,56
Μάλιστα η Val διαβάζει τόσο με κόμμα όσο και με τελεία! Διότι πάντα περιμένει έναν αριθμό!
Τύπωσε Τιμή("12,56"), Τιμή("12.56") θα τυπώσει το ίδιο με το τωρινό διαχωριστικό π.χ.
         12,56    12,56


Το Bug ήταν στα νούμερα με τελεία όπου τα έκοβε..π.χ. το 12.56 το έκανε 12.

inventory alfa= 100:="12.56",2.3:=12.56, 300:="12,56"
Print alfa(100), alfa(2.3), val(alfa$(300))

Και άλλες λεπτομέρειες...βρέθηκαν όπως η περίπτωση της ανάγνωσης διάστασης πίνακα και μη διαγραφής ενός αντικειμένου ώστε τελικά αντί να πάρει τη διάσταση η μεταβλητή να πάρει το αντικείμενο! Διορθώθηκε και αυτό!

Πέμπτη 5 Μαΐου 2016

Αναθεώρηση 4 (διόρθωση παλαιών Bug- προ 8.1)

Βρήκα μερικά Bug, και ιδιαίτερα ένα ενοχλητικό, το οποίο δημιουργούσε κατάρρευση του διερμηνευτή κατά την διόρθωση προγράμματος. Είχα βάλει ένα hook, στο messagebox το οποίο δεν χρειάζονταν (δεν δούλευε, παρά μόνο δημιουργούσε προβλήματα), οπότε αν ξέχναγε κανείς να βάλει ένα άγκιστρο στο κώδικα άνοιγε το Msgbox...και προετοιμάζονταν για crash..
(δεν το βρήκα γιατί σπάνια έτυχε να μην βάλω σωστά τα άγκιστρα, και έτσι άργησα να το βρω).

Το άλλο λάθος ήταν στην τροποποίηση που έκανα για την γρήγορη αναζήτηση εντολών, έβαλα μια εντολή να καλεί κατά λάθος μια παρόμοια, με συνέπεια η εντολή ΑΝΑΖΗΤΗΣΗ για τις βάσεις δεδομένων να μην δούλευε! Αυτό έγινε στις τελευταίες αναθεωρήσεις, οπότε βρέθηκε...μετά από έλεγχο με δοκιμές πολλών προγραμμάτων, που χρησιμοποιώ για έλεγχο.

Προς το παρόν ο κώδικας είναι οκ.


Για τους jagged πίνακες, η Μ2000 μπορεί να περάσει με ισχνή αναφορά ένα στοιχείο πίνακα, την οποία δίνει η Ισχνή$() ή Weak$() αλλά μόνο σε πίνακες με όνομα. Οι πίνακες εντός του πίνακα Α() δεν έχουν όνομα. Επειδή όμως η ισχνή αναφορά είναι αλφαριθμητικό με το πραγματικό όνομα του πίνακα (*) μπορούμε να προσθέσουμε το δείκτη για τον δεύτερο πίνακα, εδώ το "(0)".

Dim A(10)=100
L=Lambda->{ Dim A(number) : =A()}
Module testme {
      read pointer$
      pointer$.++
      Print Eval(pointer$)
}
A(3)=L(20)
A(3)(2)=10
\\ this no work yet
\\  pointer$=weak$(A(3)(2))
pointer$=weak$(A(3))+"(2)"
Print A(3)(2) '10
testme pointer$
Print A(3)(2) '11




*(σαν να είναι γενική μεταβλητή και για το λόγο αυτό λέγεται δείκτης, δουλεύει παντού αρκεί να υπάρχει αυτό που δείχνει, και για το λόγο αυτό λέγεται ισχνή αναφορά, ο έλεγχος γίνεται μια φορά στην αρχή αλλά η σύνδεση γίνεται στιγμιαία και μπορεί να αποτύχει, αν στο μεταξύ διατηρούμε την αναφορά κάπου και έχει στο μεταξύ σβήσει, έχει χαθεί δηλαδή, το αναφερόμενο).

Αναθεώρηση 3 (Έκδοση 8.1) Jagged Arrays

Η 8.1 έκδοση υποστηρίζει jagged Πίνακες ή αλλιώς πίνακες που έχουν πίνακες. Στην αναθεώρηση 3 έφτιαξα το Dimension() ή Διάσταση() να δουλεύει και για jagged arrays.

\\ M2000 Jagged array
Dim a(3)
Function dimany {
      dim a(number)
      =a()
}
Function dim2any {
      dim a(number, number)
      =a()
}
A(0)=dimany(10)
A(1)=dimany(4)
A(2)=dimany(2)
A(0)(8)=100
Print A(0)(8)
A(1)(2)=101
Print A(1)(2)
A(2)(0)=102
Print A(2)(0)
A(0)(0)=dim2any(30,2)
A(0)(0)(5,1)=500
Print A(0)(0)(5,1)
For i=1 to Dimension(A(0)(0)())
        Print i, Dimension(A(0)(0)(),i) ' 30..2
Next i
Print Dimension(A(0)(),1) '10
Print Dimension(A(),1) '3




Δείτε και αυτό (δίνουμε αντίγραφο, όχι αναφορά σε πίνακα):
Dim A(10)=3
Dim B(3)
\\ we get a copy not a reference
B(0)=A()
      A(0)=5
B(1)=A()
Print B(0)(0), B(1)(0) ' 3...5

Τετάρτη 4 Μαΐου 2016

Πρώτη αναθεώρηση για την έκδοση 8.1 και Παράδειγμα "Πόλεις"

Σε αυτή την μικρή αναθεώρηση διόρθωσα μερικά πραγματάκια όπως το μήκος της Κατάστασης (λίστα αντικειμένων-αριθμών-λέξεων). Και έβαλα μια εντολή άμεσα να κάνει ταξινόμηση


Να και ένα ωραίο παράδειγμα στα ελληνικά. Φτιάχνουμε μια κατάσταση Πόλεις. Με εντολή Αφαίρεση Πόλεις, "Βόλος" μπορούμε να αφαιρέσουμε άμεσα μια πόλη. Η αφαίρεση κάνει το εξής...βάζει στη θέση του "Βόλος" αυτό που είναι στο τέλος της Κατάστασης. Αν μας ενδιαφέρει η σειρά, τότε θα πρέπει να κάνουμε ταξινόμηση. Όμως γενικά δεν μας ενδιαφέρει η ταξινόμηση, αλλά το αν υπάρχει κάτι και το πόσο γρήγορα το βρίσκω ώστε να πάρω πληροφορίες. Σε αυτό η Κατάσταση είναι πολύ γρήγορη αφού χρησιμοποιεί πίνακα Κατακερματισμού. (Hash Table).  Πρώτη φορά έγραψα το Hash Table σε M2000, και από τότε το εφαρμόζω με παραλλαγές και στο κώδικα της Μ2000 (δείτε εδώ)

Καθαρό

\\ επειδή μπορεί μέχρι να φτιάξουμε το πρόγραμμα να κάνουμε λάθη
\\ με την εντολή καθαρό σβήνουμε όλες τις μεταβλητές και τους πίνακες
\\  που δεν έχουν καθαρίσει λόγω σφάλματος.


\\ Εδώ είναι μια Λάμδα που παράγει ενάν αριθμό
Κωδικός=Λάμδα Κ=Τυχαίος(10000) ->{=Κ : Κ++ }


\\ Η κλάση αυτή παράγει μια ομάδα
\\ Το τμήμα με το ίδιο όνομα είναι ο κατασκευαστής της.
Κλάση Πληροφορίες {
      Κάτοικοι, Έκταση, Κωδικός
      Τμήμα Πληροφορίες {
            Διάβασε .Κάτοικοι, .Έκταση, .Κωδικός
      }
}
Κατάσταση Πόλεις="Πάτρα","Αθήνα","Βόλος","Καβάλα"
Προσθήκη Πόλεις, "Ιωάννινα"


Ταξινόμηση Πόλεις
\\ η Κατάσταση Πόλεις έχει μόνο ονόματα για την ώρα
\\ θα δούμε ότι έχει (το όνομα) και ταυτόχρονα βάζουμε και Πληροφορίες
\\ το ! στο Πόλεις$() δηλώνει ότι ο αριθμός δεν είναι κλειδί αλλά αριθμός σειράς
Για ι = 0 έως Μήκος(Πόλεις)-1
      Τύπωσε Πόλεις$(ι!)
      Επιστροφή Πόλεις :=Πληροφορίες(τυχαίος(10,50)*1000, τυχαίος(2,7)*10000, Κωδικός())
Επόμενο ι


Για Πόλεις("Αθήνα") {
      .Κάτοικοι=1000000
      .Έκταση=200000
      .Κωδικός=12345
}
Τύπωσε Πόλεις("Αθήνα").Έκταση


\\ Με ! λέμε στο διερμηνευτή ότι δίνουμε αριθμό σειράς και όχι κλειδί
Ελαχ=Πόλεις(0!).Κάτοικοι
Ελαχ_Π=0
Για ι = 1 έως Μήκος(Πόλεις)-1
      Αν Ελαχ>Πόλεις(ι!).Κάτοικοι τότε {
            Ελαχ=Πόλεις(ι!).Κάτοικοι
            Ελαχ_Π=ι
      }
Επόμενο ι
\\ τώρα δεν δουλεύει το Πόλεις$(ι!) γιατί κάθε κλειδί έχει μια ομάδα,
\\ ενώ πριν δεν είχε και έτσι έδειχνε το όνομά του!
Για Πόλεις(Ελαχ_Π!) {
      \\ αφού τώρα υπάρχει μετακίνηση του δείκτη στο σωστό
      \\ δουλεύει το Εκφρ$(Πόλεις!) που δείχνει το κλειδί
      Τύπωσε "Πόλη με λιγότερους κάτοικους:",Εκφρ$(Πόλεις!)
      Τύπωσε "Έχει: "; .Κάτοικοι
}


\\ Μπορούμε να βρούμε τον αριθμό σειράς με το κλειδί:
Αν Υπάρχει(Πόλεις, "Βόλος") τότε {
      Σ=Εκφρ(Πόλεις!)
      Τύπωσε Γραφή$(Πόλεις(Σ!).Κάτοικοι=Πόλεις("Βόλος").Κάτοικοι,";Ναί;Όχι;")
      \\ επειδή ακόμα ο δείκτης εσωτερικά δείχνει το "Βόλος"
      Τύπωσε Πόλεις().Κάτοικοι
      \\ αλλά όχι στην αριστερή θέση
      Πόλεις("Βόλος").Κάτοικοι+=2000
      Τύπωσε Πόλεις().Κάτοικοι
}


Έκδοση 8.1 νέο αντικείμενο Inventory (Κατάσταση) - διόρθωση

Προχωρημένος προγραμματισμός! Νέα έκδοση με κύρια προσθήκη το αντικείμενο Inventory ή ελληνικά Κατάσταση,


Το αντικείμενο Inventory ή ελληνικά Κατάσταση, είναι μια λίστα στοιχείων. Έχει μια φυσική διάταξη, το ένα στοιχείο μετά το άλλο, αλλά δεν θεωρείται η θέση του στοιχείου μόνιμη. Η λίστα δηλαδή δύναται να αλλάξει διάταξη, αν αφαιρέσουμε στοιχείο, ή αν ταξινομήσουμε στοιχεία. Δεν αλλάζει η διάταξη, αν αλλάξουμε όνομα κλειδιού (χωρίς να ταξινομήσουμε). Κλειδιά δέχεται αριθμούς ή γράμματα (αλφαριθμητικά), χωρίς περιορισμό στο μέγεθος. Η εύρεση ενός κλειδιού γίνεται γρήγορα, χωρίς αναζήτηση στη λίστα, αλλά με υπολογισμό της θέσης. Αν υπάρχει σύγκρουση κλειδιού τότε αυτά θα βρίσκονται σε ξεχωριστή λίστα και σειριακά αναζητάει ο αλγόριθμος από το τελευταίο εισερχόμενο πάντα. Είναι τέτοιο το μέγεθος του πίνακα κατακερματισμού που ελάχιστες συγκρούσεις υπάρχουν. Έτσι θεωρούμε ότι η αναζήτηση γίνεται σε χρόνο ανεξάρτητο του μεγέθους του πίνακα. Έτσι η Κατάσταση ή Inventory είναι ένας πίνακας αντιστοιχιών (lookup table). Μπορούμε να έχουμε πίνακα χωρίς να βάλουμε κάτι στα κλειδιά, και τότε το κλειδί δίνεται ως αποτέλεσμα. Αν δεν διαγράφουμε και δεν ταξινομούμε τότε μπορούμε να παίρνουμε τη θέση του κλειδιού, στη λίστα άμεσα, έτσι κάνει για Enumerates.
Υπάρχει τρόπος να κάνουμε αλλαγές swaps, τόσο στα περιεχόμενα δυο κλειδιών, όσο και στις θέσεις των κλειδιών (μαζί με τα περιεχόμενα). Υπάρχουν μέθοδοι και ιδιότητες που μπορούμε να χειριστούμε όπως στα COM αντικείμενα.

Σε σχέση με όλα τα άλλα αντικείμενα το Inventory ή Κατάσταση δεν αντιγράφεται άμεσα, αλλά περνάει την αναφορά του όπως τα κλασικά αντικείμενα. Ο λόγος που έγινε αυτό ήταν για να μπορούμε σε έναν πίνακα αντικειμένων να έχουμε κοινά στοιχεία με την χρήση μιας κατάστασης. Αν θέλουμε να έχουμε ξεχωριστές καταστάσεις τότε μπορούμε να αποδεσμεύσουμε την αναφορά βάζοντας μια νέα αναφορά σε νέα κατάσταση.

Στο παράδειγμα παρακάτω (το οποίο είναι παραφουσκωμένο), έχω βάλει σε μια κατάσταση alfa, μια λάμδα συνάρτηση, έναν πίνακα, ένα αντικείμενοι Ομάδα (το φτιάχνει η Κλάση, εδώ με όνομα Hello).
Επίσης έχω και μια συνάρτηση που παράγει το αντίγραφο μιας Κατάστασης. Έτσι μπορεί κανείς να δει πώς κατασκευάζεται μια κατάσταση από μια άλλη. Θα μπορούσε δώσει κανείς δυο καταστάσεις (δεν χρειάζεται η επιστροφή, ούτε η δήλωση για νέα Κατάσταση), και να κάνει συγχώνευση, με επιλογή κλειδιών. Επίσης ο ίδιος κώδικας είναι χρήσιμος γιατί με παραλλαγή μπορεί να κάνει Serialize (να βγάλει ένα προς ένα τα στοιχεία του, για αρχείο κειμένου).
Η IsObj ως λάμδα μέσα στην CopyInventory λογικά κάνει σύλληψη της alfa, και αν ήταν οτιδήποτε άλλο θα είχε αντιγραφεί, αλλά εδώ περνάει με αναφορά. Πώς έγινε; Απλά η λάμδα κάνει πάντα αντιγραφή σε ότι συλλαμβάνει, αλλά η alfa έχει αναφορά στην πραγματική Κατάσταση, και η αντιγραφή δεν δημιουργεί νέα Κατάσταση, Στην εντολή With βλέπουμε ορισμένες ιδιότητες. Αυτές έχουν τα ονόματα όπως δηλώνονται στην κλάση της VB6 FastCollection που έγραψα πριν από λίγες μέρες, για το σκοπό αυτό. Η ταξινόμηση γίνεται με την μέθοδο sort και δεν έχουμε έλεγχο στην συνάρτηση που κάνει την ταξινόμηση (μια quicksort). Όμως οι αντιγραφές γίνονται με δείκτες οπότε δεν έχουμε ουσιαστικά μεταθέσεις σε δομές όπως αλφαριθμητικά, ομάδες, πίνακες, λάμδα.

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


Οι εντολές για την Κατάσταση:
Κατάσταση όνομα_κατάστασης   [= κλειδί [:= τιμή] ,[κλειδί [:= τιμή]] ]
Προσθήκη όνομα_κατάστασης [,κλειδί [:=τιμή]]...
Αφαίρεση όνομα_κατάστασης [[, κλειδι], κλειδι...]
Επιστροφή όνομα_κατάστασης [:=τιμή για τρέχον κλειδί] | [κλειδί:=τιμή]
Συναρτήσεις
Μήκος(όνομα_κατάστασης)
Υπάρχει(όνομα_κατάστασης, κλειδί)

Κλειδί: αριθμός ή αλφαριθμητικό
Τιμή: οτιδήποτε. Αριθμός, Αλφαριθμητικό, Ομάδα, Πίνακας, Λάμδα συνάρτηση, Κατάσταση
η alfa() αφαιρέθηκε, η index κάνει την δουλειά της.

Class Hello {
      Private:
      A$="Hello"
      Public:
      Function GetA$ {=.A$}
      Module SetA {Read .A$}
}
Function CopyInventory {
      Read alfa ' we can use Read &Alfa but Inventory is always a reference
      With alfa, "index" as index, "keytostring" as kts$, "value" as v$, "value" as v, "valueobj" as vob
      IsObj=Lambda alfa ->{
            Method alfa, "IsObj" as isobj
            =isobj
      }
      ' this is the new Inventory (a new object)
      Inventory Dbl
      For i=0 to Len(alfa)-1 {
      index=i
      
                  If IsObj() Then {
                        append Dbl, kts$:=vob
                  } else {
                  If Type$(alfa(i!))="String" Then {
                        append Dbl, kts$:=v$
                  } else {
                        append Dbl, kts$:=v
                  }
                  }
      
      }
' here we pass a reference to new inventory
=Dbl
}
dim k(10)=10
CamelWord$=lambda$->{
      read a$
      if len(a$)<2 then =ucase$(a$) : exit
      =ucase$(left$(a$,1))+lcase$(Mid$(a$,2))
}
Inventory alfa=1,"Camel":=CamelWord$,3:=k(),4:=400,5:="ok", "Last":=Hello()
Inventory Dbl
Dbl=CopyInventory(alfa)
' We can use arrays from inventory
alfa(3)(4)+=10
Print Len(Dbl)
Print K(4)
Print Dbl(3)(4), alfa(3)(4)
a=lambda alfa ->alfa(number)
Print a(1)
' This is the normal way to change items
Return alfa, 1:=500, 5:="Hello There"
Print alfa(1)
Print a(1), a(4),alfa$(5)
Print Dbl(1), Dbl(4), Dbl$(5)
' We can change key
Method Dbl, "ChangeKey", "Camel", "Camel Word"
' We use lambda functions from inventory
Print Dbl$("Camel Word")("GEORGE")+" "+alfa$("Camel")("KARRAS")
' We can call function from "group" object  (we make it from Class Hello)
' and module too
alfa("Last").SetA "Bye Bye"
Print alfa("Last").GetA$() ' Bye Bye
Print Dbl("Last").GetA$() ' Hello




Δεύτερο πρόγραμμα με μερικές ακόμα εντολές.
Στην αναθεώρηση 1 διορθώθηκε και τώρα αυτό γίνεται: Return Alfa,"StringKey":=Alfa(3)+1



Inventory Alfa=1,2,3,4
Append Alfa,6,7
Delete Alfa, 1,2
Return Alfa, 3:=3000, 4:="Hello"


Print Len(Alfa)
Print Alfa(3) ' 3000
Print Alfa$(4) ' Hello
Append Alfa,"StringKey":=100
Print Alfa("StringKey") ' 100
Return Alfa,"StringKey":=Alfa(3)+1
Print Alfa("StringKey") ' 100
Print Alfa(3), Alfa$(4)


\\ Two phase reading
If Exist(Alfa, "StringKey") then Print "Ok"
\\ Use Alfa() if Alfa is readable (return "done" property)
\\ Use Eval to extract number or object from Alfa
\\ extract objects by copy  (except for Inventories)
\\ Inventory has a cursor inside (as Index)
\\ When is set then we can use to read/write


If Alfa() then Print Eval(Alfa) ' 30001
If Exist(Alfa, 4) then Print Eval$(Alfa) ' Hello
Beta=Alfa
\\ Beta is a reference to Alfa
\\ In a later revision beta may have own cursor
If Exist(Beta, 4) then Print Eval$(Beta) ' Hello
\\ Without using key, hust the index
Return Beta :="Good Morning"
Print Eval$(Beta)
Print Eval$(Beta!) ' This is the key name
Print Eval(Beta!), Eval(Beta!) ' This is the key position
p=Eval(Beta!)
Print Beta$(p!) ' print string by using position, not key


Δευτέρα 2 Μαΐου 2016

Αναθεώρηση 225

Σε αυτήν την αναθεώρηση πρόσθεσα ένα νέο αντικείμενο. Για την ώρα το χρησιμοποιώ για να βελτιώσω τους χρόνους εκτέλεσης. Έγιναν και αλλαγές που βελτίωσαν την ταχύτητα όταν χρησιμοποιούμε στατικές μεταβλητές:
Σε ένα τμήμα Α μπορούμε να βάλουμε αυτό. Τη δεύτερη γραμμή, μπορούμε να την αφαιρέσουμε. Κάθε φορά που θα τρέχει το Α η τιμή της Α θα παραμένει η τελευταία, και αν δεν την αλλάξουμε με το Α=1 τότε θα αυξάνεται. Δοκιμάστε το στην αναθεώρηση 224 και δείτε τη διαφορά στην 225.

STATIC A
A=1
PROFILER
FOR I=1 TO 10000 {
      A++
}
PRINT TIMECOUNT, A
B=1
PROFILER
FOR I=1 TO 10000 {
      B++
}
PRINT TIMECOUNT, B
LIST


Με Static A=1 δίνουμε την πρώτη τιμή της Α. (αφαιρούμε την γραμμή  Α=1)
Με Clear στη γραμμή εντολών της Μ2000 σβήνουμε όλες τις στατικές, οπότε η Α ξεκινάει από το 1
Οι στατικές μεταβλητές δηλώνονται σε αυτόν που καλεί το τμήμα. Έτσι αν το τμήμα είναι γενικό (δηλαδή το βλέπουμε με την εντολή Τμήματα ? στην γραμμή εντολών), τότε αν το καλέσουμε από δυο διαφορετικά τμήματα, όπου το ένα είναι έστω το Α1 και το άλλο το Β1 που είναι στο Α1 τότε το Β1 θα έχει δικές του στατικές στο γενικό τμήμα με τις στατικές. Αυτό το σύστημα υπάρχει γιατί στην ουσία η Μ2000 εκτελεί το κάθε τμήμα με ένα αντικείμενο εκτέλεσης, και στο τέλος εκτέλεσης αυτό "παραδίδει" μια λίστα με στατικές (αν υπάρχει). Στην επόμενη εκτέλεση θα βρεθεί η λίστα και θα ξεκινήσει με υπάρχουσες στατικές.

Δεν μπορούμε να έχουμε στατική και τοπική με το ίδιο όνομα. Το βρίσκει η Μ2000 και βγάζει λάθος!
Οι στατικές παλαιότερα δεν μπορούσαν να περαστούν με αναφορά. Στις τελευταίες εκδόσεις γίνεται να περαστούν, αλλά έχουμε το εξής "κόλπο": Ο διερμηνευτής φτιάχνει μια κρυφή τοπική, στην οποία βάζει τη τιμή της στατικής και δίνει αυτή με αναφορά. Στην επιστροφή από τη κλήση, παίρνει την τιμή από τη κρυφή μεταβλητή και την καταχωρεί στην στατική. Στην ουσία έχουμε το λεγόμενο copy in copy out. Τεχνικά οι γενικές και οι τοπικές βρίσκονται σε έναν πίνακα τύπου Hash (έχει Ο(1) σε εύρεση, διαγραφή, και εγγραφή, δηλαδή είναι πολύ γρήγορος). Ακόμα και ίδια ονόματα να έχουμε η εύρεση γίνεται από το τελευταίο που μπήκε στο πίνακα. Έτσι γίνεται η σκίαση. Όταν δίνουμε μια μεταβλητή ως αναφορά τότε σχηματίζεται ένα κλειδί στο πίνακα Hash αλλά δεν δίνεται νέα διεύθυνση/χώρος, αλλά δίνεται αυτό που λέει η αναφορά καθώς και μια σημαία λέει ότι είναι αναφορά. Όταν διαγράφονται οι τοπικές ή οι γενικές που δημιουργήθηκαν σε ένα τμήμα τότε διαγράφεται η μνήμη τους (μηδενίζεται) αλλά όχι σε αυτά που έχουν δηλωθεί ότι είναι αναφορά. Έτσι η μνήμη των μεταβλητών καθαρίζει (αν έχουμε αντικείμενα και έχουμε το τελευταίο δείκτη, τότε καθαρίζουν και αυτά). Οι στατικές μεταβλητές βρίσκονται σε μια λίστα συνδεδεμένη με το τρέχον αντικείμενο εκτέλεσης, και όχι στο πίνακα τύπου Hash. Αυτή η λίστα είναι ένα Collection της VB6 το οποίο είναι και αυτό γρήγορο αλλά διαφορετικού τύπου (μια διπλή συνδεδεμένη λίστα μαζί με ένα δένδρο b-tree για εύρεση με κλειδί). Ουσιαστικά σε Collection τα στοιχεία είναι διάσπαρτα στη μνήμη. Στο πίνακα Hash της Μ2000 έχουμε δυο πίνακες, που μπορούν να διπλασιάζονται (στην αλλαγή μεγέθους έχουμε rehashing το οποίο γίνεται γρήγορα γιατί καταχωρούνται τα ενδιάμεσα αποτελέσματα του Hash αλγόριθμου πάνω στο κλειδί, τα οποία είναι ανεξάρτητα του μεγέθους του πίνακα Hash).

Κάποια στιγμή σκέφθηκα αν θα ήταν προτιμότερο να φτιάξω όλες τις μεταβλητές να συνδέονται σε Collection τοπικά. Έτσι δεν θα υπήρχε μια ενιαία λίστα, αλλά πολλές μικρές. Το πρόβλημα θα ήταν το πώς θα γίνεται η αναφορά. Θα έπρεπε να περαστούν όνομα και λίστα. Τώρα γίνεται το εξής, κατά τη κλήση γράφουμε ένα αλφαριθμητικό που είναι το κλειδί στην ουσία στο πίνακα Hash, αυτή είναι η ισχνή αναφορά. Κατά την εκτέλεση αυτού που καλέσαμε κοιτάει το σύστημα αν υπάρχει και αν ναι φτιάχνει αυτή που ζητάμε ως τοπική με αναφορά σε αυτήν που βρήκε. Ποιο όμως είναι το πραγμαιτκό πρόβλημα με το όνομα και τη λίστα; Ότι για την λίστα (Collection) θα έπρεπε να δώσουμε τον δείκτη της. Αυτό σημαίνει ότι θα δίναμε κανονική αναφορά, και όχι ισχνή, με συνέπεια αν καταχωρηθεί κάπου να κρατάει τη λίστα "Ζωντανή". Σε αντίθεση η ισχνή αναφορά αν κρατηθεί σε πίνακα, δεν πειράζει τον πίνακα Hash. Στην περίπτωση της κανονικής αναφοράς ενδέχεται να πετύχουμε να μην μπορεί ποτέ η λίστα να διαγραφεί γιατί κάτι σε αυτήν έχει ένα δείκτη σε αυτήν! Επίσης με τις πολλές λίστες θα έπρεπε να κάνουμε ότι κάνει και η Javasctript, δηλαδή ψάχνει τη τρέχουσα, αν δεν βρει αυτό που θέλει, πάει παραπάνω, και παραπάνω μέχρι να το βρει. Αυτό στη M2000 θα γίνονταν για τις γενικές μεταβλητές. Αλλά με την χρήση του πίνακα Hash, η εύρεση γίνεται άμεσα, για οποιαδήποτε μεταβλητή, και ο τρόπος που γράφονται στο πίνακα (πάντα στο τέλος) βολεύει όταν τερματίζει ένα τμήμα ή μια συνάρτηση, ή μια ρουτίνα ή μια απλή συνάρτηση (γράφεται όπως η ρουτίνα στο τέλος και την καλούμε με @ στην αρχή), τότε διαγράφεται άμεσα το τμήμα των μεταβλητών που ορίστηκαν (επειδή κρατάει λογαριασμό η Μ2000 στο αντικείμενο εκτέλεσης), Η διαγραφή δεν σημαίνει και απόδοση μνήμης στο σύστημα εκτός αν πέσει κάτω από το μισό η χρήση του πίνακα. Έτσι ο ίδιος χώρος χρησιμοποιείται πολλές φορές κατά τις κλήσεις. Σε άλλες γλώσσες που διαφημίζουν ότι όλα είναι αντικείμενο σημαίνει ότι κάθε φορά που καλούμε κάτι με δέκα τοπικές θα πρέπει να φτιαχτούν δέκα αντικείμενα, να δεσμευτεί μνήμη και μετά να κρατηθούν οι διευθύνσεις τους σε ένα πίνακα (ή στη στοίβα εκτέλεσης). Με το τρόπο αυτό έχουμε γρήγορη εκτέλεση αλλά διάσπαρτα τα στοιχεία στη μνήμη, με συνέπεια να μην δουλεύει καλά η ειδική γρήγορη μνήμη του επεξεργαστή. Παρόλα αυτά σε τέτοιου τύπου χειρισμό μπορούμε να πετύχουμε το yield, δηλαδή το σταμάτημα μιας διαδικασίας, απόδοση τιμών και μετά συνέχιση εκτέλεσης. Στη Μ2000 δεν μπορούμε να το κάνουμε αυτό. Όμως εναλλακτικά μπορούμε να κάνουμε κλήση προς τα πίσω:

Α=100
Χ=5000
Συνάρτηση Ψεύτικη(Νέο Χ) {
// αν βγάλουμε το Νέο θα αλλάξει τιμή στη Χ,
// οπότε στο τέλος θα πάρουμε Χ=10
Α+=Χ
}
Τμήμα ΔεςΤο (&Α()) {
Για ι=1 έως 10
Κάλεσε Α(ι)
Επόμενο ι
}
ΔεςΤο οκν$(&Ψεύτικη())
Τύπωσε Α=155
Τύπωσε Χ=5000

Η συνάρτηση Ψεύτικη μέσω της Οκν$() θα εκτελείται με το τρέχον όνομα χώρου, και όχι με νέο που θα έφτιαχνε η συνάρτηση. Δείτε όμως μια διαφορά, επειδή έχουμε άλλο αντικείμενο εκτέλεσης, δεν θα έχουμε πρόσβαση σε τυχόν στατικές που θα έχει το τμήμα (αφού κατά την εκτέλεση είναι γραμμένες στο δικό του αντικείμενο εκτέλεσης).

Παρόμοιο τρόπο χρησιμοποιούν και οι συναρτήσεις που φτιάχνουμε για γεγονότα. Η διαφορά είναι ότι το όνομα δεν είναι τυχαίο αλλά έχει το όνομα του αντικειμένου που δίνει γεγονότα την κάτω παύλα και το όνομα του γεγονότος (στα COM αντικείμενα που ορίσαμε με την Όρισε και το ΜεΓεγονότα).

Όπως το προηγούμενο αλλά χωρίς τη χρήση οκν$() αλλά με χρήση γενικής συνάρτησης και γενικών μεταβλητών (εδώ δεν θέλει το Νέο Χ γιατί στην ουσία η Χ είναι τοπική). Οι γενικές καθώς και η γενική συνάρτηση θα διαγραφούν στο πέρας εκτέλεσης.
Αν βάζαμε μια Α=Α πριν την Α+=Χ τότε θα φτιάχναμε μια τοπική Α οπότε η γενική Α δεν θα άλλαζε!
Η Α<=Α όμως δεν θα φτιάξει γενική! Ο διερμηνευτής όταν βλέπει το <= τότε ψάχνει για γενική. Ενώ στα += πρώτα κοιτάει αν υπάρχει τοπική και μετά αν υπάρχει γενική, αλλά δεν δημιουργεί μεταβλητή. Μεταβλητές δημιουργούνται όταν δεν υπάρχουν με την εκχώρηση τιμής (με το =), και αν έχουμε δώσει το Γενικό ή Γενικές πριν τότε γίνονται γενικές μεταβλητές. Ακόμα και σε ένα Για ι=1 έως 100 αν θέλουμε να αλλάξει η γενική ι τότε γράφουμε Για ι<=1 έως 100. Στο παράδειγμα τυπώνουμε τη γενική ι. Στους γενικούς πίνακες δεν ισχύει το <= γιατί δεν δημιουργούμε πίνακες με το =, την εκχώρηση τιμής, αλλά με την Πίνακας για τοπικό ή τη Γενική (πχ Γενική Α(2,3)=1 δημιουργούμε γενικό πίνακα Α()). Το Α=(1,2,3,4) θα φτιάξει έναν αυτόματο πίνακα, και εμφανίζεται ως *[mArray] που σημαίνει δείκτης σε αντικείμενο mArray (είναι το αντικείμενο των αυτόματων πινάκων, το οποίο είναι μια παραλλαγή του αντικειμένου Πίνακα, με άλλη διεπαφή - interface)
γενική ι
για ι<=1 έως 10
τύπωσε ι
επόμενο
Τμήμα Δες_Λίστα{
Γενική Α(2,3)=1
Γενική Α=(1,2,3,4)
λίστα
}
Δες_Λίστα

Γενικές Α=100, Χ=5000
Συνάρτηση Γενική Α(Χ) {
Α+=Χ
}
Τμήμα ΔεςΤο (&Β()) {
Για ι=1 έως 10
Κάλεσε Β(ι)
Επόμενο ι
}
ΔεςΤο &Α()
Τύπωσε Α=155
Τύπωσε Χ=5000