Τετάρτη 3 Φεβρουαρίου 2016

To goto or not to goto Αυτό είναι το ερώτημα!

Υπάρχουν περιπτώσεις που η χρήση goto δίνει πιο συμπαγή και κατανοητό κώδικα.

Από ένα αλφαριθμητικό θέλουμε να βγάλουμε τους αριθμούς. Έχουμε φτιάξει έναν parser..δηλαδή ένα πρόγραμμα που διαβάζει τους χαρακτήρες και βλέπει αν έχουν αριθμό. Αυτό που δεν κοιτάει εδώ είναι το πόσα ψηφία σε κάθε νούμερο δίνουμε. Δεν μας πειράζει γιατί απλά το εμφανίζουμε στην οθόνη. Ένας αριθμός μπορεί να έχει πρόσημο ή όχι, να έχει ή όχι μία μόνο τελεία που να δείχνει τα δεκαδικά που μπορεί να είναι σε οποιαδήποτε θέση, αλλά σίγουρα μετά το πρόσημο. Ακολουθεί αριθμός αν υπάρχει διάστημα ή κόμμα. Τα αρχικά διαστήματα τα αφαιρούμε αλλά δεν δεχόμαστε διαστήματα χωρίς να ακολουθεί αριθμός, όπως και κόμμα δεν δεχόμαστε αν δεν ακολουθεί αριθμός.!

Και τα δύο προγράμματα είναι ισοδύναμα (δοκιμάστηκε και στη υπό δοκιμή 151 στη κανονική 147)

Δείτε μια μικρή ανάλυση του προβλήματος: Αν θέλουμε να βάλουμε για παράδειγμα έναν ακόμα έλεγχο, π.χ. να κοιτάμε αν υπάρχει το e για να πάρουμε επιστημονική μορφή (με e και πρόσημο) το δεύτερο πρόγραμμα χωρίς goto μεγαλώνει πολύ! Όμως το πρώτο με τα goto δεν θέλει πολλές αλλαγές! Και η απόδειξη είναι στο τέλος!



Παράδειγμα με Goto  (38 γραμμές)

Α$=" +.12, 1324342,+342.3, -1123.,13123.12323,.456,-.23423"
      Κ=Μήκος(Α$)
      Αν Κ=0 τότε έξοδος
      ι=1 
πάλι:
      Β$=Μεσ$(Α$,ι,1)
      προ=ψευδές
      δεκ=ψευδές
      κενά=ι
οκ5:
      Αν Β$=" " τότε κενά++ : προς οκ0
οκ4:
      Αν προ η δεκ Αλλιώς Αν Β$ ~ "[+-]" τότε προ~ : προς οκ1
      προ=αληθές
οκ3:
      Αν δεκ Αλλιώς Αν Β$ = "." τότε δεκ~ : προς οκ1
οκ2:
      Αν Β$ ~ "[1234567890]"  Αλλιώς Αν  ι=κ ή όχι Β$ ~ "[ ,]"  Τότε { λαθος "οχι αριθμός"} Αλλιώς Προς Άλλο
οκ1:
      ι++
      Αν ι>κ τότε Προς Άλλο
      Β$=Μεσ$(Α$,Ι,1) 
      Αν προ και όχι δεκ τότε προς οκ3
      Αν προ και δεκ τότε προς οκ2
      προς οκ4
οκ0:
      Αν ι<κ τότε ι++ : Β$=Μεσ$(Α$,Ι,1) : Προς οκ5
Άλλο:      
      Αν ι=κενα+1 και δεκ τότε Λαθος "μόνο τελεία"
      Αν ι=κενα+1 και προ τότε Λαθος "μόνο πρόσημο"
      Αν ι=κενα+2 και δεκ και προ τότε Λάθος "Δεν έχω αριθμό"
      Αν ι<=κενα τότε Λάθος "Δεν έχω αριθμό"
      Τύπωσε "Σωστός Αριθμός", Μες$(Α$, κενά, ι-κενά)
      ι++
      Αν ι<=κ τότε προς πάλι



Περίπτωση χωρίς Goto (59 γραμμές)

Α$=" +2123, 13.24342,+342.3, -1123.,13123.12323,.456,-.23423"
Κ=Μήκος(Α$)
Αν Κ=0 τότε έξοδος
ι=1
Ενώ ι<κ {
      Β$=Μεσ$(Α$,ι,1)
      κενά=ι
      προ=ψευδές
      δεκ=ψευδές
      εξ1=Ψευδές  \\ ειδική μεταβλητή
      Ενω Β$=" " και ι<κ {
            κενά++
            ι++
            Β$=Μεσ$(Α$,ι,1)
      }
      Αν Β$ ~ "[-+]" τότε  {
            προ=αληθές
            αν ι<κ τότε {
                  ι++ : Β$=Μεσ$(Α$,ι,1)
            } Αλλιώς { 
                  Λαθος "μόνο πρόσημο" 
            }
      }
      Αν Β$ = "." τότε {
            δεκ=Αληθές
            αν ι<κ τότε { 
                  Επανέλαβε {
                        ι++ : Β$=Μεσ$(Α$,ι,1) 
                        Αν Β$ ~ "[1234567890]"  Τότε {
                        \\ τίποτα
                        } Αλλιώς.Αν  ι=κ ή όχι Β$ ~"[, ]" Τότε {
                              Λάθος "Δεν έχω αριθμό"
                        } Αλλιώς εξ1=Αληθές : Έξοδος
                  } Μέχρι ι>=κ
            } Αλλιώς {
                  αν προ Αλλιώς Λαθος "μόνο τελεία"
                  Λάθος  "Δεν έχω αριθμό"
            }
      } αλλιώς {
      ι--
      }
      αν ι<κ και όχι εξ1 τότε { 
            Επανέλαβε {
                  ι++ : Β$=Μεσ$(Α$,ι,1) 
                  Αν Β$="." και όχι δεκ Τότε { 
                        δεκ=Αληθές
                  } Αλλιώς.Αν Β$ ~ "[1234567890]"  Τότε {
                  \\ τίποτα
                  } Αλλιώς.Αν  ι=κ ή όχι Β$ ~"[, ]" Τότε {
                        Λάθος "Δεν έχω αριθμό"
                  } Αλλιώς Έξοδος
            } Μέχρι ι>=κ
      }
      Αν ι=κενά+1 και δεκ τότε Λαθος "μόνο τελεία" 
      Αν ι=κενά+1 και προ τότε Λαθος "μόνο πρόσημο" 
      Αν ι=κενά+2 και προ και δεκ τότε Λάθος "Δεν έχω αριθμό"
      Τύπωσε "Σωστός Αριθμός", Μες$(Α$, κενά, ι-κενά)
      ι++
}
Με 5 γραμμές (σύνολο 43) επεκτάθηκε το πρόγραμμα με το Goto για να διαβάζει και επιστημονική μορφή (δέχεται πρόσημο μετά το e αλλά όχι τελεία). Ούτε θέλω να φανταστώ πώς θα αλλάξει το πρόγραμμα χωρίς τα goto για να δέχεται και αριθμούς με επιστημονική μορφή!

      Α$=" +.12, 13.24e-32,+342.3, -1123.,13123.123e+23,.456,-.23423"
      Κ=Μήκος(Α$)
      Αν Κ=0 τότε έξοδος
      ι=1 
πάλι:
      εκθ=ψευδές
      αριθ=ψευδές
      δεκ=ψευδές     
      κενά=ι
πάλι1:
      Β$=Μεσ$(Α$,ι,1)
      προ=ψευδές
οκ5:
      Αν Β$=" " τότε κενά++ : προς οκ0
οκ4:
      Αν προ η ( δεκ και όχι εκθ ) Αλλιώς Αν Β$ ~ "[+-]" τότε προ~ : προς οκ1
      προ=αληθές
οκ3:
      Αν δεκ και όχι εκθ Αλλιώς Αν Β$ = "." τότε δεκ~ : προς οκ1
οκ2:
      Αν Β$="e" και αριθ και όχι εκθ Τότε {
            εκθ=αληθές 
            Αν ι>=κ Τότε { λαθος "οχι αριθμός"}  αλλιώς  ι++ : Πρός πάλι1
      }
      Αν Β$ ~ "[1234567890]"  Αλλιώς Αν  ι=κ ή όχι Β$ ~ "[ ,]"  Τότε { λαθος "οχι αριθμός"} Αλλιώς Προς Άλλο
      αριθ=αληθές
οκ1:
      ι++
      Αν ι>κ τότε Προς Άλλο
      Β$=Μεσ$(Α$,Ι,1) 
      Αν προ και όχι δεκ τότε προς οκ3
      Αν προ και δεκ τότε προς οκ2
      προς οκ4
οκ0:
      Αν ι<κ τότε ι++ : Β$=Μεσ$(Α$,Ι,1) : Προς οκ5
Άλλο:      
      Αν ι=κενα+1 και δεκ τότε Λαθος "μόνο τελεία"
      Αν ι=κενα+1 και προ τότε Λαθος "μόνο πρόσημο"
      Αν ι=κενα+2 και δεκ και προ τότε Λάθος "Δεν έχω αριθμό"
      Αν ι<=κενα τότε Λάθος "Δεν έχω αριθμό"
      Τύπωσε "Σωστός Αριθμός", Μες$(Α$, κενά, ι-κενά)
      ι++
      Αν ι<=κ τότε προς πάλι









Τρίτη 2 Φεβρουαρίου 2016

"Scope" ή αλλιώς εμβέλεια αναγνωριστικών!

Δείτε το παρακάτω πρόγραμμα σε C++. Στη C++ ότι είναι εκτός μπλοκ είναι γενική μεταβλητή. Αν θέλουμε να ξεχωρίσουμε κάτι πρέπει να το δηλώσουμε ή τοπικό (που σκιάζει το γενικό) ή με χρήση ονόματος χώρου.

// namespaces
#include <iostream>
using namespace std;

namespace foo
{
  int value() { return 5; }
}

namespace bar
{
  const double pi = 3.1416;
  double value() { return 2*pi; }
}

int main () {
  cout << foo::value() << '\n';
  cout << bar::value() << '\n';
  cout << bar::pi << '\n';
  return 0;
}


Στην Μ2000 έχουμε γενικές όταν αναθέτουμε τιμές σε επίπεδο γραμμής εντολών. Σε ένα τμήμα είμαστε ήδη σε μπλοκ, άρα όλα εκεί εξ ορισμού είναι τοπικά, εκτός αν τα δηλώσουμε γενικά (και μένουν γενικά (σκιάζοντας ότι προηγούμενο) για όσο χρόνο το τμήμα τρέχει (μετά διαγράφονται).
Για να αλλάξουμε γενική μεταβλητή πρέπει να δώσουμε αυτό <= γιατί το = δημιουργεί τοπική.

Ενώ στη C++ μπορούμε να ορίσουμε μεταβλητές τοπικές σε κάθε μπλοκ, στη Μ2000 μπορούμε να το κάνουμε όποτε θέλουμε με τη χρήση της εντολής τοπική (ή και τοπικές αν θέλουμε πολλές να δημιουργήσουμε) και αν υπάρχει ήδη μια τοπική τότε σκιάζεται. Για το λόγο αυτό τοπικές κάνουμε μόνο σε μπλοκ που κάνει ότι και η C++, δημιουργούν τις προϋποθέσεις για προσωρινές μεταβλητές. Αυτό λοιπόν γίνεται σε μπλοκ που κάνουμε με την Για, π.χ. Για Αυτό {  } και Για όνομα_ομάδας { } και Για Πίνακας_με_κλειστές_ομάδες(δείκτης)  {  }, καθώς και σε ρουτίνες.

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

Η C++ έλυσε το θέμα με τη χρήση των namespace. Φτιάχνεις δηλαδή ένα namespace και βάζεις μεταβλητές και συναρτήσεις μέσα! Η Μ2000 όμως έκανε τα namespace αντικείμενα!
Το παραπάνω πρόγραμμα σε M2000 (έχει επιπλέον μια γραμμή που δείχνει τη Pi ή Πι την σταθερά που γνωρίζει η Μ2000).
Η ομοιότητα είναι ότι τα Group (Ομάδα) μπορεί να έχουν και άλλα Group φωλιασμένα

Η διαφορά με τη Μ2000 είναι ότι τα group μπορούν να αντιγραφούν σε νέα Group...ή σε στοιχεία πίνακα ή να γυρίσουν ως αποτέλεσμα!
π.χ. Α=foo θα κάνει μια νέα συνάρτηση Α.value()
Σε ένα τμήμα έστω ΚΑΤΙ μπορούμε να περάσουμε με τιμή την foo
KATI foo
Η ομάδα foo θα βγει αντίγραφο σε μια κλειστή ομάδα στο σωρό τιμών του αντικείμενου εκτέλεσης της ΚΑΤΙ (που δημιουργείται όταν την καλέσουμε). Με μία Διάβασε FooInKati θα δημιουργηθεί η ομάδα FooInKati με τη συνάρτηση FooInKati,value()

Επίσης μπορούμε να τα περνάμε με αναφορά (ακόμα και τα γενικά). Π.χ, για ένα τμήμα ΑΛΦΑ το παρακάτω:
ΑΛΦΑ &bar
θα βάλει στη κορυφή στο σωρό τιμών της ΑΛΦΑ (στο αντικείμενο εκτέλεσης που θα δημιουργηθεί), το όνομα της bar (ισχνή αναφορά) και με μια:
Διάβασε &barInAlfa
θα έχουμε την ομάδα barInAlfa, την μεταβλητή barInAlfa.pi και την συνάρτηση barInAlfa.value()
Αν δηλώσουμε τοπική την Pi στο Group bar τότε στο πέρασμα με αναφορά δεν θα υπάρχει το barInAlfa.pi (ουσιαστικά τα αναγνωριστικά δείχνουν τις πραγματικές τιμές). Αν καλέσουμε την  barInAlfa.value()  π.χ. σε μια Τύπωσε τότε θα τρέξει σαν να είναι στην ομάδα bar και θα δει την pi παρόλο που δεν θα τη βλέπουμε στο ΑΛΦΑ,.


Η Μ2000 δεν χρειάζεται την Main για να τρέξει. Το παρακάτω το γράφουμε σε ένα τμήμα Α οπότε ήδη τρέχει...φτάνει στην κλήση της Main (απλά μπήκε εδώ για να φαίνεται...σαν την C++)

Μπορούμε να βγάλουμε τα global από τα group και να αφαιρέσουμε το Module main και την κλήση στη Main στο τέλος (και να αφήσουμε το μπλοκ δεν πειράζει)
Απλά σε ένα τμήμα δεν μπορεί να φανεί κάτι αν δεν είναι τοπικό ή δεν είναι γενικό. Αν υποθέσουμε ότι το παρακάτω είναι στο τμήμα Α, αν αφαιρέσουμε τα global στα group θα έχουμε τοπικές τις foo και bar. Τα αντικείμενα της Μ2000 έχουν όνομα χώρου και συμπληρώνουν το υπάρχον

\\ need to set groups to global to make global
\\ by default anything in a module is local

global group foo {
  function value { =5 }
}


global group bar {
      pi = 3.1416
      function value {=2*.pi} ' because a name has a . is a user id so is not the costant pi
}


Module main {
  Print foo.value()
  Print bar.value()
  Print bar.pi
  Print pi ' this is the M2000 costant pi
}
main


εδώ χωρίς Module main (μπήκε για ομορφιά)

group foo {
  function value { =5 }
}


group bar {
      pi = 3.1416
      function value {=2*.pi} ' because a name has a . is a user id so is not the costant pi
}


{
      Print foo.value()
      Print bar.value()
      Print bar.pi
      Print pi ' this is the M2000 costant pi
}


και εδώ με πέρασμα με αναφορά

group foo {
  function value { =5 }
}


group bar {
      pi = 3.1416
      function value {=2*.pi} ' because a name has a . is a user id so is not the costant pi
}


Module Other {
      Read &foo1, &bar1
      Print foo1.value()
      Print bar1.value()
      Print bar1.pi
      Print pi ' this is the M2000 costant pi
}
Other &foo, &bar


Πέρασμα με αντιγραφή, και επιστροφή με ένωση! H Push ή Βάλε, βάζει τιμές στο σωρό τιμών. Τα τμήματα καλούν άλλα τμήμα δίνοντας στο αντικείμενο εκτέλεσης του νέου τμήματος το σωρό τιμών του και βάζοντας στη κορυφή του τις τιμές που δίνουμε ως παραμέτρους. Στην επιστροφή λοιπόν θα υπάρχει στο σωρό του τμήματος ότι αφήσει το τμήμα που καλούμε! Για το λόγο αυτό τα τμήματα δεν προκαθορίζουν τι θα πάρουν αλλά οργανώνεται στο κώδικα το τι ακριβώς θα πάρουμε και το τι θα αφήσουμε! Οι συναρτήσεις ξεκινούν με δικό τους σωρό τιμών που περιέχει τις τιμές που περνάμε στη κλήση και στο πέρας της κλήσης τους ότι υπάρχει στο σωρό τους διαγράφεται μαζί με το αντικείμενο εκτέλεσης. Οι ρουτίνες είναι μέρη των τμημάτων και των συναρτήσεων και δεν έχουν δικό τους αντικείμενο εκτέλεσης, δεν έχουν δικό τους όνομα χώρου και δικό τους σωρό τιμών. Για το λόγο αυτό όταν δηλώνουμε σε ρουτίνες μεταβλητές για εισαγωγή ουσιαστικά δηλώνουμε νέες τοπικές με τις τιμές που δίνουμε.

Οι στατικές μεταβλητές στη Μ2000  είναι εκτός από το σύστημα ονομάτων χώρου και ανήκουν στα αντικείμενα εκτέλεσης...(το πατρικό κρατάει πακέτο των στατικών του κάθε "παιδιού" αντικείμενου εκτέλεσης).

group foo {
  checkme=1000
  function value { =5 }
}

group bar {
      pi = 3.1416
      function value {=2*.pi} ' because a name has a . is a user id so is not the costant pi
}


Module Other {
      Read foo1, bar1
      Print foo1.value()
      Print bar1.value()
      Print bar1.pi
      Print pi ' this is the M2000 costant pi
      foo1.checkme+=100
      bar1.pi=pi
      Push bar1, foo1
}
Other foo, bar
\\ union new foo with old one
Read foo, bar
Print foo.checkme, bar.pi





Σύγκριση αναθεωρήσεων - Γραμμική με Εκθετική Μεταβολή.

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

Στο τμήμα Β κάνουμε κλήση με αναδρομή σε τμήμα (κανονικά δε γίνεται αλλά με την χρήση της εντολής Κλήση που την μετατρέπει σαν κλήση συνάρτησης γίνεται).

Έχουμε λοιπόν την νέα Αναθεώρηση 151 (δεν την δίνω ακόμα στο κεντρικό σημείο "Κώδικας Γλώσσας" για να αντικαταστήσει την 147, γιατί είναι ακόμα υπό έλεγχο, λόγω εκτεταμένων αλλαγών, οπότε μπορεί να την πάρει κανείς από εδώ) όπου έχω χρησιμοποιήσει άλλο τρόπο καταχώρησης μεταβλητών, πινάκων, τμημάτων/συναρτήσεων.

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

Δοκιμάζοντας τα παρακάτω διαπιστώνουμε εκπληκτικές αποδόσεις με την χρήση του πίνακα κατακερματισμού. Δεν είναι μόνο η εύρεση μεταβλητής που γίνεται άμεσα, αλλά και ότι μπαίνει η καθεμία σε ξεχωριστό αλφαριθμητικό, άρα δεν απαιτείται αντιγραφή όλων των λέξεων για τη προσθήκη μιας! Επειδή εδώ δεν κάνουμε πολλές διεργασίες στις ρουτίνες/τμήματα, ο χρόνος εξαρτιέται από τον τρόπο που καταχωρούνται και αποδεσμεύονται οι ,μεταβλητές/πίνακες.

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

Για την υπό δοκιμή αναθεώρηση 151
Έχουμε λοιπόν για το Α 11246 μια μέση τιμή (τιμή σε χιλιοστά δευτερολέπτου)
Για το Β 10025 μια μέση τιμή, περίπου 12% πιο γρήγορο η κλήση τμήματος

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

Για την τρέχουσα αναθεώρηση 147
Έχουμε λοιπόν για το Α 68544 μια μέση τιμή (τιμή σε χιλιοστά δευτερολέπτου)
Για το Β 120792 μια μέση τιμή, περίπου στο μισό της ταχύτητας του Α, και σε σύγκριση με την αναθεώρηση 151,  12 φορές πιο αργό!

Εκπληκτική διαφορά!
Η εξήγηση είναι ότι
1. Στην  147: Λογικά το Β αργεί σε σχέση με το Α επειδή στο Β οι μεταβλητές γράφονται με μια αρίθμηση σε σχέση με το βάθος κλήσης, ενώ στο Α όλες έχουν το ίδιο όνομα, απλά η ρουτίνα βλέπει πάντα τις νεότερες! Άρα το αλφαριθμητικό στη Β περίπτωση είναι μεγαλύτερο! Και αυτό σημαίνει ότι όταν μεγαλώνει αντιγράφει περισσότερα στοιχεία!
Αν πάμε στις 3000 κλήσεις ο χρόνος στο Β πάει στο 31042 δηλαδή στο 1/4 (φαίνεται ότι έχουμε εκθετική αύξηση όσο περισσότερες κλήσεις κάνουμε).
2. Στην 151: Και στις δυο περιπτώσεις χρησιμοποιούμε πίνακα κατακερματισμού αλλά στην περίπτωση της Α έχουμε ίδια κλειδιά, άρα έχουμε συγκρούσεις! Όμως η αύξηση του πίνακα και στις δυο περιπτώσεις γίνεται τμηματικά και όχι με νέο αντίγραφο.
Αν πάμε στις 3000 κλήσεις ο χρόνος στο Β πάει στο 4926 δηλαδή στο μισό (τα λίγα χιλιοστά τα τρώει ή τα βάζει το σύστημα δεν μετράνε), άρα βλέπουμε ότι έχουμε γραμμική αύξηση όταν αυξάνεται ο όγκος των δεδομένων.

Αναθεώρηση
151: Β:  3.000 κλήσεις 4.926 mSec 6.000 κλήσεις 10.025 mSec  Γραμμική μεταβολή
147: Β:  3.000 κλήσεις 31.042mSec 6.000 κλήσεις 120.792mSec  Εκθετική μεταβολή

το παρακάτω πρόγραμμα δημιουργεί δυο συναρτήσεις μιας γραμμής. που δίνουν περίπου τα παραπάνω αποτελέσματα. Βλέπουμε ότι κάθε μια έχει μια περιγραφή (η εκθετική είναι η Χ**2, θα μπορούσαμε να το γράψουμε και ως Χ^2 είναι το ίδιο στη Μ2000).
Οι σταθερές .00335 και 1.667 μπήκαν για να φέρουν το αποτέλεσμα στο μέγεθος της κάθε περίπτωσης. Αυτό που μας ενδιαφέρει είναι ότι αλλάζοντας το Χ έχουμε περίπου τα ίδια αποτελέσματα. Τότε οι τύποι είναι σωστοί (στη σύγκριση σε διάφορα δεδομένα να έχουμε περίπου ίδια αποτελέσματα, το περίπου εδώ σχετίζεται με μικροδιαφορές που δεν έχουν υπολογιστεί και μπορεί να είναι και εξωτερικοί παράγοντες, που αλλάζουν ελαφρώς το αποτέλεσμα της μέτρησης).

def o1(x)= (x**2)*.00335
Print o1(3000),o1(6000)
def o2(x)=x*1.667
Print o2(3000),o2(6000)



Σε πολλές περιπτώσεις προγράμματα της 147 έχουν την ίδια ταχύτητα με αυτά της 151. Αυτό συμβαίνει όταν έχουμε μικρό μέγεθος αλφαριθμητικών (που κρατάνε τις λίστες αναγνωριστικών), η σειριακή αναζήτηση κοντράρει τη χρήση συναρτήσεων κατακερματισμού. Για να δουλέψει ο πίνακας κατακερματισμού πρέπει στην αναζήτηση να βγάλουμε το νούμερο από τη συνάρτηση κατακερματισμού για να πάμε στη θέση που θα μας δείξει να δούμε αν υπάρχει το αλφαριθμητικό και αν ναι τότε βρίσκουμε ποια μεταβλητή δείχνει. Στη σειριακή αναζήτηση,σ την 147, η Μ2000 κάνει το εξής..κοιτάει πάντα από τα τελευταία που μπήκαν, και αν δεν χρησιμοποιούμε γενικές τότε βρίσκει άμεσα την μεταβλητή που ζητάμε (πέναλτι έχουμε αν δεν υπάρχει η μεταβλητή αλλά δεν μας πειράζει..θα βγάλουμε λάθος και θα σταματήσει το πρόγραμμα). Και δείτε και αυτό..αν καλούμε σε βάθος κλήσεων έχουμε θέμα, αν όμως περιορίσουμε τις κλήσεις σε μικρό βάθος τότε οι μεταβλητές που μένουν στο αλφαριθμητικό είναι λίγες!

Για να τρέξετε τα τεστ αρκεί μια επικόλληση σε δυο διαφορετικά τμήματα. Δώστε Σώσε Τεστ1 και μπορείτε να τα πάρετε πάλι με Φόρτωσε Τεστ1

 (Δοκιμάστε με εντολές στην γραμμή εντολών: Γρήγορα και Γρήγορα! όπως και με Αργά, είναι οι τρεις διαφορετικές ταχύτητες της Μ2000, στο Γρήγορα! δεν βλέπουμε ανανεώσεις οθόνης εκτός αν το θέλουμε με την εντολή Ανανέωση, στο Γρήγορα είμαστε στο κανονικό και στο Αργά αλλάζει τρόπο λειτουργίας, και δίνει η Μ2000 περισσότερες φορές χρόνο στο σύστημα, που καμιά φορά είναι υπέρ...και έρχεται η ταχύτητα στο ίδιο με το Γρήγορα).

Σε ένα τμήμα έστω Α
Αναλυτής
Έλεγχος(6000)
Τύπωσε Φόρτος


Ρουτίνα Έλεγχος(ι)
      Τοπικές α,β,γ,δ, α(30)
      Αν ι<1 Τότε Έξοδος Ρουτίνας
      Τύπωσε 6001-ι
      Έλεγχος(ι-1)
Έξοδος Ρουτίνας



Σε ένα τμήμα έστω Β
Τμήμα Έλεγχος {
      Διάβασε ι
      Τοπικές α,β,γ,δ, α(30)
      Αν ι<1 Τότε Έξοδος
      Τύπωσε 6001-ι
      Κάλεσε Έλεγχος ι-1
}
Αναλυτής
Κάλεσε Έλεγχος 6000
Τύπωσε Φόρτος






Αυτό εδώ είναι πιο τεχνικό ακόμα και το έχω ξεκόψει από τα προηγούμενα!

Οι στατικές μεταβλητές, και στις δυο εκδόσεις είναι εκτός από τις καταχωρήσεις αναγνωριστικών που έχουν να κάνουν με όνομα χώρου (αλφαριθμητικά στην 147-πίνακες κατακερματισμού στη 151), και χρησιμοποιούν ένα πιο γρήγορο τρόπο αποθήκευσης, που εσωτερικά έχει δικό του πίνακα κατακερματισμού, αλλά έχει το μειονέκτημα να μην παίρνει "διπλά" κλειδιά, και για το λόγο αυτό χρησιμοποιώ δικό μου σύστημα (το καλό σύστημα είναι το Collection της VB6, αλλά δεν παίρνει διπλά κλειδιά όπως επίσης δεν παίρνει Types (ή Structs στη C ), αλλά παίρνει αντικείμενα ή Variants (μεταβλητές που μπορεί να είναι οτιδήποτε, αλλά όχι UDT user defined types)..

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

Οι στατικές μεταβλητές (όχι πίνακες όμως), εγγράφονται ανά αντικείμενο εκτέλεσης. και δείτε τι γίνεται. Οι μεταβλητές εγγράφονται σε ένα αντικείμενο. Αν υπάρχουν στατικές μεταβλητές και το αντικείμενο τερματίζει (επιστρέφει δηλαδή) το αντικείμενο εγγράφεται ως στατική μεταβλητή στο αντικείμενο εκτέλεσης εκείνου που κάλεσε αυτό που τερματίζει. Έτσι την επόμενη φορά που θα το καλέσει θα του δώσει τις μεταβλητές απλά δίνοντας μια αναφορά στο νέο αντικείμενο. Τα νήματα έχουν δικά τους αντικείμενα εκτέλεσης, οπότε αν θέλουν να χρησιμοποιήσουν το ίδιο τμήμα (επειδή ανήκουν στο ίδιο όνομα χώρου, μπορούν χωρίς να είναι γενικό), θα το καλέσουν με τις δικές τους στατικές για αυτό! Τα νήματα δεν επιστρέφουν στο "πατρικό" πακέτα στατικών διότι τα νήματα είναι αντικείμενα που δεν επιστρέφουν, απλά σταματάνε ή και διαγράφονται (πάντα διαγράφονται αν το πατρικό τερματίσει...αλλά γίνεται να έχουμε μια αργοπορία εδώ).
Αφού λοιπόν τα νήματα μπορούν να έχουν στατικές μεταβλητές σε ίδιο όνομα χώρου..πως γίνεται ένα άλλο τμήμα να αλλάξει τιμές σε συγκεκριμένο τμήμα; Απλά μπορούμε από ένα αντικείμενο εκτέλεσης να εκτελέσουμε εντολή σε άλλο αντικείμενο εκτέλεσης! Ενώ όλα τα νήματα βλέπουν τις μεταβλητές του τμήματος που είναι στον ίδιο χώρο, για να αλλάξουν τιμές σε στατικές πρέπει να δώσουν εντολή με αριθμό νήματος (δεν μπορούν να δώσουν στο τμήμα, γιατί το τμήμα δεν έχει αριθμό (προσβάσιμο), αλλά γίνεται μόνο το τμήμα να δώσει εντολές στα νήματα, και τα νήματα μεταξύ τους! Τα νήματα όμως μπορούν να πειράξουν όλες τις μεταβλητές του τμήματος εκτός από τις στατικές.

Το όνομα χώρου χρησιμοποιείται και εκτός τμημάτων στα αντικείμενα (κάθε ομάδα έχει το δικό της όνομα χώρου, αλλά όχι το αντικείμενο εκτέλεσης. Μια μέθοδος σε μια ομάδα αν κληθεί σχηματίζει αντικείμενο εκτέλεσης, αλλά σε μεθόδους και συναρτήσεις σε ομάδες δεν επιτρέπεται η χρήση στατικών - (δεν έχει νόημα αφού μπορούμε να δούμε τις μεταβλητές της ομάδας ως στατικές).
Ομάδες που κλείνονται σε στοιχεία πίνακα μπορούν να έχουν άλλες ομάδες και αυτές άλλες ομάδες εσωτερικά με πίνακες και ότι άλλο θέλουμε, αλλά θα είναι "κλειστά" δηλαδή θα ανήκουν σε ένα αντικείμενο που δεν θα "πατάει" κάπου παρά μόνο μέσω μιας μοναδικής σύνδεσης, στο στοιχείο πίνακα. Επειδή λοιπόν ο πίνακας αυτός μπορεί να μεταφερθεί (π.χ. να γίνει επιστροφή πίνακα σε μια συνάρτηση - οι συναρτήσεις επιστρέφουν μεταβλητές, ομάδες και πίνακες), χωρίς να υπάρχει αντικείμενο εκτέλεσης η όποια χρήση στατικών σε αυτά δεν δικαιολογείται! Οι στατικές έχουν νόημα όσο υπάρχει αντικείμενο εκτέλεσης να τις "κρατάει".

Με το όνομα χώρου η Μ2000 κάνει "παιχνίδια" δηλαδή μπορεί να δώσει μια συνάρτηση Α() από ένα τμήμα Β να τρέξει μέσα σε ένα τμήμα Γ ενώ θα νομίζει ότι είναι κώδικας από το  τμήμα Β! Εκεί δηλαδή που γνωρίζουμε τα περάσματα με αναφορά μεταβλητών, τώρα γίνεται να περάσει ένα περιβάλλον σε ένα νέο αντικείμενο εκτέλεσης και σε αυτό να εφαρμοστεί σε ένα νέο αντικείμενο εκτέλεσης που θα μιμείται το αρχικό! Δηλαδή  το τμήμα Γ μπορεί να επιστρέφει διαδοχικά τιμές στο Β και να εκτελεί κώδικα του Β, χωρίς να τερματίσει ως Γ. Αυτό οι απλές διαδικαστικές γλώσσες δεν το κάνουν! υπάρχει παράδειγμα εδώ (από 22 -12-2015, τρέχει κανονικά και στην 151 αναθεώρηση).

Ένας άλλος τρόπος μεταφοράς ονόματος χώρου είναι το πέρασμα με αναφορά συνάρτησης μιας ομάδας. Για να δώσουμε αναφορά σε κλειστή ομάδα πρέπει να την ανοίξουμε πρόσκαιρα με την Για {} και τότε ο διερμηνευτής αποδίδει αυτόματα όνομα χώρου σε όλα τα στοιχεία της ομάδας. Κανονικά η αναφορά συνάρτησης είναι αντιγραφή του κώδικα και η νέα συνάρτηση που δημιουργείται λειτουργικά κάνει ότι και η αρχική. Η διαφορά με τις συναρτήσεις ομάδων είναι ότι δίνουν και το όνομα χώρου μετά τον ορισμό (στον ίδιο χώρο, όπου θα διαβαστεί από το διερμηνευτή), και έτσι η νέα συνάρτηση θα έχει πρόσβαση στις συναρτήσεις, τις μεταβλητές, τους πίνακες και τα τμήματα της ομάδας. Άρα και με αυτόν το τρόπο έχουμε πέρασμα σε αντικείμενο εκτέλεσης, ολόκληρο "πληροφοριακό" σύστημα, όπως είναι μια ομάδα, αλλά με την διαφορά ότι δεν έχουμε το αντικείμενο εκτέλεσης, παρά μόνο τα δεδομένα και το λογισμικό τους. Αντί να δώσουμε αναφορά σε συνάρτηση ομάδας μπορούμε να δώσουμε αναφορά στην ομάδα. Εδώ αν η ομάδα έχει τοπικές μεταβλητές, πίνακες, τμήματα ή και συναρτήσεις, τότε αυτά δεν θα υπάρχουν στο νέο όνομα που θα συνδέεται με την ομάδα. Όμως εσωτερικά αν χρησιμοποιούν κάποια τοπική, θα μπορούν να το κάνουν!

Όλα αυτά δεν έχουν να κάνουν με το πώς καταχωρούμε τις μεταβλητές αλλά πως ο διερμηνευτής εκμεταλλεύεται με χρήση αντικειμένων την υποδομή των μεταβλητών/πινάκων/τμημάτων/συναρτήσεων. Εκεί που είχαμε συναρτήσεις και τμήματα ανά αντικείμενο εκτέλεσης, οι ομάδες έφεραν τις συναρτήσει και τα αντικείμενα ανά όνομα χώρου, ξεφεύγοντας από το αντικείμενο εκτέλεσης. Η χρήση των ομάδων (με υποομάδες και όλα τα σχετικά) μπήκε στην έκδοση 7 η οποία έφτασε  στην 18η αναθεώρηση και μετά έγινε έκδοση 8. Η 8 απέκτησε πολλά νέα πράγματα, όπως δείκτες (αλφαριθμητικά που γράφουν το όνομα της μεταβλητής με το όνομα χώρου) ως ισχνές αναφορές, και έφτασε στην έκδοση 147, όπου αλλάζει με την 151 να είναι μέρος της έκδοσης 8.1 (λόγω του ότι αλλάζω το υποσύστημα και όχι κάτι πιο μεγάλο).


Επίλογος
Με την χρήση πινάκων κατακερματισμού έχει ολοκληρωθεί η Μ2000 σε σχέση με την γραμμική απόκριση στην δημιουργία, αναζήτηση και διαγραφή των μεταβλητών.
Χρειάζεται ακόμα έλεγχος λόγω πληθώρας εντολών και δυνατοτήτων! Πάντως προς το παρόν έχω τρέξει αρκετά παραδείγματα από το Blog και ακόμα δεν βρήκα θέμα. (στην 151). Αλλά ακόμα έχω δουλειά!





Δευτέρα 1 Φεβρουαρίου 2016

Περί της 8.1 έκδοσης και πώς λειτουργεί!


Εδώ είναι  ο κώδικας της ανεπίσημης 8.1 (θα πάρει νούμερο όταν θα έχει ελεγχθεί διεξοδικά)
Αναθεώρηση 151 (έχει ανέβει η 152 και μπορεί κανείς να την πάρει από το Κώδικας Γλώσσας


Η παρούσα έκδοση, 8, είναι στην αναθεώρηση 147 και το πολύ να πάρει άλλες δύο (χλωμό το βλέπω). Έτσι θα προχωρώ την 151 μέχρι να αποφασίσω ότι ολοκληρώθηκε! Αυτή θα είναι η 8.1.

Το διαφορετικό αυτής της έκδοσης είναι ότι οι μεταβλητές, οι πίνακες και τα τμήματα αναζητούνται με πίνακα κατακερματισμού και όχι σειριακά. Δείτε όμως μια ιδιαιτερότητα: Μπορούν να υπάρχουν ίδια κλειδιά! Σε αυτή την περίπτωση διαβάζουμε το τελευταίο που μπήκε. Επιπλέον πρέπει να σβήνουμε τις Χ τελευταίες μεταβλητές, άρα να κάνουμε νέο κατακερματισμό. Αυτό χρειάζεται όταν τερματίζει κάτι που δημιουργεί προσωρινές-ιδιωτικές μεταβλητές/πίνακες/τμήματα. Αυτό πετυχαίνεται με το να κρατάμε μερικά αποτελέσματα της συνάρτησης κατακερματισμού. Η συνάρτηση έχει δυο στάδια, και το δεύτερο έχει να κάνει με το μέγεθος του πίνακα.
Η υλοποίηση γίνεται με ένα αντικείμενο hash  για μεταβλητές και πίνακες, και ένα sbhash για τα τμήματα και τις ρουτίνες. Επιλέχθηκε αυτός ο τρόπος γιατί σε κάθε αντικείμενο δίνουμε το πίνακα των καταχωρήσεων για να τις σβήνει όταν χρειάζεται. Οπότε επειδή έχουμε δυο διαφορετικούς πίνακες, θα έχουμε και δυο διαφορετικά αντικείμενα!

Μια ιδέα αρκεί για να αντιληφθεί κανείς την πολυπλοκότητα. Έχουμε ουσιαστικά τρεις πίνακες που σχετίζονται με μια μεταβλητή. Ο πίνακας που βρίσκεται η τιμή της, ο πίνακας που βρίσκεται το όνομά της και κάποια πρόσθετα στοιχεία για αυτήν, και ο πίνακας κατακερματισμού. Οι δυο τελευταίοι είναι σε ένα αντικείμενο. Ο πρώτος είναι γενικός, όπως και το αντικείμενο που έχει τους άλλους δυο. Δείτε στη συνέχεια:

Μια μεταβλητή (ως όνομα)  στην ουσία είναι αναφορά σε μια τιμή (στον πρώτο πίνακα).  Στη Μ2000 μπορούμε να έχουμε πολλές αναφορές σε μια τιμή. Αυτό που δεν γίνεται εύκολα είναι να αλλάζουμε αναφορά σε ένα όνομα! Άρα ο πρώτος πίνακας μπορεί να έχει Ν τιμές αλλά να υπάρχουν Ν+Μ ονόματα όπου τα Μ θα είναι οι αναφορές που δείχνουν κάπου στις Ν τιμές. 
Ο πίνακας κατακερματισμού έχει για καλή λειτουργία παραπάνω τιμές από όσες οι Ν+Μ. Ουσιαστικά το αντικείμενο δίνει σε μια ιδιότητα count τον αριθμό των ονομάτων, ενώ έχει δική του μια μεταβλητή με το μέγεθος του πίνακα κατακερματισμού. Αν κάποιο όνομα πέσει πάνω σε άλλο τότε πιάνει αυτό την θέση του, και το άλλο βγαίνει από τον πίνακα. Δεν χάνεται όμως, γιατί μπαίνει σε μια λίστα που σχηματίζεται από αυτό που μπήκε και προς τα πίσω..σε αυτά που βγήκαν. Έτσι ουσιαστικά ο πίνακας κατακερματισμού ακόμα και να ήταν ένα στοιχείο θα δούλευε ως μια λίστα συνδεδεμένων "ονομάτων" (μάλλον δεικτών σε ονόματα, γιατί ο πίνακας αυτός είναι μόνο Long, δηλαδή κρατάει μόνο το νούμερο του στοιχείου, εκείνου που έχει το όνομα).


Μέσα λοιπόν στο αντικείμενο του πίνακα κατακερματισμού, υπάρχει μια δομή σε πίνακα όπου κάθε στοιχείο έχει κλειδί (όχι μόνο το όνομα, αλλά όλο το μονοπάτι, το name space, ή όνομα χώρου), θέση τιμής στον πίνακα τιμών, αν είναι αναφορά (το χρειάζεται για να ξέρει αν θα σβήσει την τιμή στην θέση τιμής ή όχι. όταν χρειαστεί), μια υπολογισμένη τιμή Hash1 (που έχει να κάνει με το κλειδί και οχι με το μέγεθος του πίνακα), και η τελευταία θέση στο πίνακα. Δηλαδή κάθε όνομα, έχει και ένα δείκτη πρός τη τελευταία θέση (μπορεί όπως είδαμε ένα όνομα να μην είναι στο πίνακα κατακερματισμού αλλά να είναι στην ουρά κάποιου άλλου, απλά και μόνο επειδή η συνάρτηση δίνει την ίδια θέση στον πίνακα). Ας λέμε το πίνακα με τα ονόματα PriveName() και τον πίνακα κατακερματισμού hash()

Όλα τα ονόματα στο πίνακα PriveName() γράφονται με την σειρά παρουσίας. Και όλα σβήνουν με την ανάποδη σειρά. Οπότε ο πίνακας καθώς διαγράφει στοιχεία, βάζει τυχόν ονόματα που κόβονται από την ουρά ενός διαγραμμένου που ήταν πάνω στο Hash() με ευκολία. Αν ο πίνακας ονομάτων  πέσει κάτω από έναν αριθμό ή αν χρειάζεται να βάλουμε περισσότερα ονόματα και δεν θέλουμε να συσσωρεύονται σε λίστες, τότε γίνεται ανακατασκευή του πίνακα Hash(). Για την ανακατασκευή χρειάζονται μόνο δυο πράγματα: να διατρέξουμε όλα τα στοιχεία από το πρώτο που μπήκε, και αυτό μπορούμε να το κάνουμε, με το πίνακα PriveName() και αντί να ασχοληθούμε με το όνομα, παίρνουμε την υπολογισμένη τιμή Hash1 και εκτελούμε την δεύτερη συνάρτηση που σχετίζεται με το μέγεθος και φτιάχνουμε τις επιμέρους λίστες (αν έχουμε συγκρούσεις). Επειδή επιλέγουμε μεγαλύτερο χώρο, οι συγκρούσεις θεωρητικά σπανίζουν. Έτσι έχουμε ένα σύστημα που για ένα όνομα βρίσκουμε με πράξεις! Ουσιαστικά μια σύγκριση θα έχουμε αν έχουμε καλό μέγεθος στον πίνακα.

Στους πίνακες γράφονται ότι έχει διαβαστεί στο κώδικα. Δηλαδή ο κώδικας που δεν έχει εκτελεστεί μπορεί να γράψει τμήματα, συναρτήσεις, μεταβλητές. Η Μ2000 μπορεί να φορτώνει κατ' απαίτηση κώδικα. Δηλαδή μπορούμε να χρησιμοποιούμε βιβλιοθήκες, οι οποίες φορτώνονται και τερματίζουν όταν το τμήμα που τις φόρτωσε τερματίσει. Έτσι αν θέλουμε κάτι πιο μόνιμο μπορούμε να το δώσουμε σε εντολές κατά την φόρτωση του αρχικού προγράμματος, πριν από την εκτέλεση κάποιου τμήματος (για το σκοπό αυτό η εντολή συγγραφή ή σ με παράμετρο σε εισαγωγικά και κατάλξη gsb  ανοίγει για διόρθωση απ΄ευθείας από το δίσκο, και προσθέτουμε εντολές, π.χ. Πίνακας Α(100) για δημιουργία  γενικού πίνακα, που θα σβήσει μόνο στο τερματισμό ή με εντολή "καθαρό", ή άλλες όπως τη Φόρτωσε/Load και Σενάριο/Script)

Η Μ2000 στις στατικές μεταβλητές (δεν έχει πίνακες εδώ) χρησιμοποιεί άλλο τρόπο αποθήκευσης, που δεν έχει να κάνει με τους πίνακες παραπάνω, αλλά με συλλογή μεταβλητών σε ένα αντικείμενο "συλλογή" το οποίο εκτός από τιμές μαζεύει και πακέτα από άλλα τμήματα και συναρτήσεις, με "συλλογές" και άλλα πακέτα. Όταν δηλαδή επιστρέφουμε στην γραμμή εντολών το πακέτο μπορεί να πέριεχει δυο τρία άλλα, που θα περιέχουν επίσης άλλα...Όλα τα πακέτα σχετίζονται με το αντικείμενο εκτέλεσης. Αν ένα τμήμα, όπως αυτά που φτιάχνουμε με την Σ ή Συγγραφή, που είναι γενικά και μπορούν να κληθούν από παντού, έχουμε στατικές μεταβλητές τότε κάθε άλλο τμήμα που καλεί το τμήμα αυτο θα δημιουργεί δικό του πακέτο στατικών μεταβλητών. Τα αντικείμενα στις συναρτήσεις-τμήματα δεν επιτρέπουν στατικές μεταβλητές, αφού στατικές έχουν κατά ένα τρόπο τις μεταβλητές του αντικειμένου (είναι σχεδόν το ίδιο ενώ οι στατικές κρατάνε τη πληροφορία και αφού τερματίσει το τμήμα ή συνάρτηση, το ίδιο συμβαίνει με τα τμήματα/συναρτήσεις ενός αντικειμένου, όπου αλλάζουν τις τιμές του. Η διαφορά είναι ότι το αντικείμενο θα διαγραφεί όταν ο δημιουργός του τερματίσει - σώνεται αν το δώσουμε ως επιστροφή, δεν θα επεκταθώ εδώ - ενώ οι στατικές θα σβήσουν μόνο με εντολή Καθαρό / Clear από την γραμμή εισαγωγής, ή μέσα από το τμήμα)

Όταν καλούμε ένα τμήμα γίνεται το εξής: Μια φορά αναζητείται σαν να είναι τοπικό (1). Αν δεν βρεθεί αναζητείται χωρίς όνομα χώρου (2). Δείτε εδώ όμως τι συμβαίνει. Αν το τμήμα είναι μέσα σε αντικείμενο, τότε οι μεταβλητές με τελεία αναφέρονται στις μεταβλητές του αντικειμένου, διότι έχει άλλο όνομα χώρου. Αν το αντικείμενο είναι γενικό ή τοπικό, σημαίνει ότι θα έχουμε μια από τις 1 ή 2 περιπτώσεις και στο όνομα θα έχουυμε το όνομα του αντικειμένου.
Το όνομα του αντικειμένου είναι και αυτό μια μεταβλητή και τα επιμέρους στοιχεία του είναι και αυτά στο πίνακα κατακερματισμού, εκτός από την περίπτωση που το αντικείμενο είναι κλειστό, ή ανώνυμο, ή πτητικό (επειδή μπορεί να φύγει από το τμήμα ή τη συνάρτηση που βρίσκεται). Το κλειστό αντικείμενο πρέπει να ανοίξει (παίρνει εσωτερικά ένα όνομα αυτόματα) για να το χειριστούμε. Όταν ανοίγει τότε έχει θέση στους πίνακες, μεταβλητών, πινάκων και τμημάτων/συναρτήσεων!

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

Το μόνο θέμα που δεν έχει επιλυθεί ακόμα είναι να τρέχουν νήματα σε διαφορετικά ονόματα χώρου, και να θέλουμε να δημιουργήσουμε μεταβλητές. Η Μ2000 θα το κάνει. Αλλά αν τερματίσει το ένα τμήμα πριν τερματίσει το άλλο, τότε θα καθαρίσει και τις μεταβλητές που έκανε το πρώτο (μέσα από νήμα). Δεν έχω βάλει επιπλέον λογική γι΄αυτό για να μην επιβαρύνω το σύστημα (ακόμα και αν δεν θες να γίνει κάτι, χρειάζεται κάτι για να το πετύχεις). Μια άλλη προσέγγιση είναι η χρήση στατικών μεταβλητών. Αυτές οι στατικές (σε νήμα) καθαρίζουν όταν το νήμα τερματίζει. Το νήμα είναι ένα αντικείμενο εκτέλεσης που δανείζεται ένα όνομα χώρου, βλέπει τις μεταβλητές του, και τρέχει όταν το επιτρέπουν συνθήκες (που δεν θα περιγράψω εδώ).

Συνοψίζοντας: Η Μ2000 έχει το μοντέλο των αντικειμένων εκτέλεσης, που καταναλώνουν κώδικα, έχουν ένα πακέτο στατικών μεταβλητών, έχουν ένα σωρό τιμών  (ως FIFO και LIFO),  μια στοίβα επιστροφών για ρουτίνες, και παράλληλα υπάρχουν δυο μεγάλοι πίνακες κατακερματισμού, ο πίνακας τμημάτων/συναρτήσεων και ο πίνακας μεταβλητών/πινάκων.

Από κώδικα που είναι γραμμένος σε αρχείο κειμένου UTF ...φτιάχνονται μια σειρά τμημάτων/συναρτήσεων στο επίπεδο 0 (γενικό, το βλέπουν παντού). Η εκτέλεση ενός τμήματος ή συνάρτησης δημιουργεί νέο αντικείμενο εκτέλεσης. Το αρχικό αντικείμενο εκτέλεσης, είναι αυτό της γραμμής εντολών, το οποίο δεν μπορεί να φτιάξει στατικές (αλλά ακριβώς αυτό είναι ότι κάνει, δηλαδή μια Α=4 θα παραμείνει ως γενική, μια Α=5 σε ένα τμήμα θα φτιάξει τοπική ενώ η Α<=5 θα αλλάξει τιμή στη γενική. Οι πίνακες δεν θέλουν το <= γιατί δεν ορίζονται όπως οι μεταβλητές).

Για να βελτιωθεί η ταχύτητα υπάρχουν τρόποι. Αλλά κάθε τρόπος που βελτιώνει την ταχύτητα μειώνει τις "Ελευθερίες". Δηλαδή η ταχύτητα παράλληλα περιορίζει! Ελευθερία στο προγραμματισμό είναι στο τρόπος οργάνωσης και στο πώς αυτός εξυπηρετεί καλύτερα.
Πριν από αυτή την έκδοση δεν υπήρχαν πίνακες κατακερματισμού αλλά δυο μόνο αλφαριθμητικά. Που κάθε φορά μεγάλωναν ή μίκραιναν. Επειδή η αναζήτηση γίνονταν από το τελευταίο (που γραφόταν πρώτο)  μπορούσε να γίνει γρήγορα (και όντως η ταχύτητα στη 8.1 δεν φαίνεται πόσο καλύτερη είναι αν συνεχίζει κανείς να κάνει μικρά προγράμματα με λίγες μεταβλητές). Αυτό το σύστημα υπήρχε από τις πρώτες εκδόσεις, απλά άλλαξαν επιμέρους πράγματα (π.χ έφυγαν οι πίνακες από το χώρο των μεταβλητών, και τώρα στην νέα έκδοση...ξαναγύρισαν).

Αυτά για την ώρα!
ΓΚ

Υ.Γ.
Μέχρι να ανεβάσω την αναθεώρηση 150...να και ένα ωραίο γραφικό:

move 6000,6000
b=1 \\ 1 .. -1
every 30 {
      for n=1 to 2 step .05 {all()}
      if keypress(32) then exit
      for n=2-.05 to 1+.05 step .05 {all()}
      if keypress(32) then exit
}


sub all()
      local c=1000, c1=c*n, c2=c1/2
      refresh 5000
      cls
      for i=4000 to 1000 step 300 {
            width 3 { circle fill 8-4*b,i,800/c }
            step c2*b,c1*b : b-! : if b>0 then c-=150
      }
end sub