Τετάρτη, 20 Φεβρουαρίου 2019

Revision 22 Version 9.7

This is the final revision for 9.7 version.

All updates for GUI elements done. Also minor bugs removed.

The help file update and include the # functions for arrays. The # functions call one another, if result is an array e.g if p is a pointer to array then we can perform a series of  functions like this p#Filter(...)#Map(...)#Fold(...)

When we exit from a module with an error and before we set Nothing to user forms, the forms was not unloaded, and all references to forms (from M2000 variables) lost. Now there is an automatic routine which unload the forms. So we can programming in M2000 editor and call modules without any problem, even if we have errors in program.

Calling a method for com objects prior use only passing by value, now we can pass by reference using & before the name of variable.

An example exist in info.gsb in the updated meditor.

Κυριακή, 17 Φεβρουαρίου 2019

Αναθεώρηση 20 Έκδοση 9.7

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

Ειδικά στο EditBox ή Κείμενο, προστέθηκε νέο γεγονός. Δεν αναφέρω κάτι περισσότερο, γιατί είναι πολύ τεχνικό. Στο info.gsb που παρέχεται με τον διερμηνευτή υπάρχει το meditor, ο διορθωτής για προγράμματα της Μ2000, σε μορφή παραθύρου, γραμμένος σε Μ2000. Τα επιπρόσθετα σε αυτήν την έκδοση του meditor είναι:
  • η ενσωμάτωση της βοήθειας (με χρήση SQL ερωτημάτων, στην βάση δεδομένων της βοήθειας της Μ2000). Από την ίδια βάση δουλεύει και το Βοήθεια ή Help. 
  • νέο μενού όπου επιλέγουμε αν θα τρέξουμε το πρόγραμμα με επίδειξη του κώδικα καθώς τρέχει (αυτό γίνεται με κλήση του προγράμματος που γράφουμε σε νέα παρουσία του διερμηνευτή, και σε αυτήν ανοίγει ο Έλεγχος, που δείχνει τις εντολές).
Ως προς το σύστημα παραθύρων:
Στις αναδυόμενες λίστες, όπως αυτή των μενού, έχει βγει η μετακίνηση με το ροδελάκι του ποντικιού και έχει αντικατασταθεί με άμεση μετακίνηση του δρομέα (που εμφανίζει την επιλογή) με την κίνηση του δείκτη του ποντικιού. Μπορούμε με κράτημα του αριστερού πλήκτρου του ποντικιού να μετακινούμε τις επιλογές (αν το μενού έχει περισσότερες από ένα αριθμό γραμμών, τότε δεν εμφανίζονται όλες οι επιλογές, αλλά μπορούμε με ολίσθηση των γραμμών να δούμε και τις άλλες εντολές). Η χρήση των μενού προγραμματιστικά δεν είναι δύσκολη, αλλά παρόλα αυτά απαιτεί δουλειά για να προγραμματίσει κανείς ένα καλό μενού. Δείτε πόσα πράγματα χρειάζονται. Για κάθε μενού πρέπει να ορίσουμε ένα αντικείμενο τύπου Combo ή Λίστα.Εισαγωγής. Αυτό το στοιχείο έχει τρεις βασικές παραλλαγές. Και οι τρεις εμφανίζουν ένα όνομα και δίπλα ένα τρίγωνο με την βάση από πάνω, που δηλώνει σαν βελάκι, ότι κάτι βγαίνει από κάτω! Η απλή λίστα εισαγωγής δείχνει μόνο το όνομα αυτό και όταν πατάμε σε αυτήν ανοίγει η λίστα για να επιλέξουμε. Αυτός ο τύπος γίνεται μενού επιλογής. Μπορούμε να καθορίσουμε το πλάτος της αναδυόμενης λίστας, αλλά το ύψος καθορίζεται αυτόματα. Βεβαίως το προς τα που θα ανοίξει η λίστα σχετίζεται με το που είναι το μενού (η επικεφαλίδα) σε σχέση με την οθόνη, ώστε πάντα η λίστα να είναι εντός οθόνης. Μπορεί δηλαδή η λίστα να βγει πάνω από την επικεφαλίδα.  Κατόπιν προγραμματίζουμε τις επιλογές του μενού. Μπορούμε να βάζουμε γραμμές διαχχωρισμού (δεν σταματάει σε αυτές ο δρομέας), να ορίζουμε αν η επιλογή είναι ενεργή ή όχι (βγαίνει με κόκκινο χρώμα η μη επιλογή), και επιπλέον μπορούμε να έχουμε δυο ακόμα ειδών επιλογές, τις λεγόμενες radiobutton, και τις τύπου checkbutton. Οι τύπου radiobutton δουλεύουν ως μια συνεχόμενη ομάδα όπου όμως μια από τα μέλη της μπορεί να "τσεκαριστεί" με ένα τετράγωνο αριστερά. Αντίθετα οι επιλογές τύπου checkbutton, είναι ανεξάρτητες και αυτές εμφανίζουν ένα τετράγωνο.

Αφού φτιάξουμε τις επιλογές, ορίζουμε σε ποια ομάδα μενού ανήκει το κάθε μενού. Η ομάδα χρειάζεται για όταν μετακινούμαστε στο μενού με τα βελάκια. Με τα βελάκια αριστερά και δεξιά αλλάζουμε μενού επιλογής, βάσει της ομάδας. Μπορούμε δηλαδή να έχουμε δυο ή περισσότερες ομάδες μενού επιλογών στην ίδια φόρμα. Η θέση τους δε μπορεί να είναι όπως θέλουμε, οριζόντια, η κάθετη ή διάσπαρτη! Για κάθε στοιχείο πρέπει να δώσουμε μια μέθοδο move που θα τα βάλει εκεί που θέλουμε. Ο καλύτερος τόπος για αυτή τη μέθοδο είναι στο γεγονός resize της φόρμας.

Τώρα ως προς το χειρισμό των μενού. Για να επιλέξουμε κάτι ή θα δώσουμε διπλό κλικ με ένα πλήκτρο του ποντικιού (και το δεξί πιάνει), ή θα σείρουμε την επιλογή στα δεξιά, ως σχεδόν να εξαφανιστεί και αφήνοντας την επιλογή είναι σαν να την επιλέξαμε. Αν δεν την αφήσουμε εκεί και την γυρίσουμε πίσω τότε δεν πιάνει σαν επιλογή μας.
Πριν ανοίξει το μενού και ενώ το έχουμε ζητήσει με πλήκτρο ή με το ποντίκι, στέλνει ένα γεγονός Open. Σε αυτό ρυθμίζουμε το ποια στοιχεία θα είναι ενεργά ή όχι, ή ποια checkbutton θα είναι τσεκαρισμένα ή όχι. Μπορούμε ακόμα και αν αλλάζουμε τα ονόματα! Δείτε όμως κάτι. Το συγκεκριμένο γεγονός δεν δίνει κάτι, πέρα ότι καλεί συγκεκριμένη συνάρτηση με το όνομα του στοιχείου και το επίθεμα .Open, Για να έχουμε πρόσβαση ή έλεγχο στις επιλογές πρέπει να δημιουργήσουμε πίνακες επιλογών, το οποίο είναι εύκολο, με την Με Στοιχείο, "όνομα ιδιότητας" ως Πίνακας1(). Δεν δίνουν όλες οι ιδιότητες πίνακες. Η βασική στα μενού λέγεται "label" και είναι η ετικέτα ή επικεφαλίδα του μενού. Οι πίνακες που μας ενδιαφέρουν (φαίνονται σαν πίνακες αλλά είναι ιδιότητες με μια παράμετρο), είναι των ιδιοτήτων "ListSelected" και "MenuEnabled". Η πρώτη έχει να κάνει με τα checkbutton, και η δεύτερη με όλα τα στοιχεία, όπου με 0 ή false τα απενεργοποιούμε.Κάθε επιλογή έχει ένα νούμερο, με την πρώτη να έχει το 0. Για κάθε στοιχείο μενού (που όπως είδαμε είναι λίστα εισαγωγής αναδυόμενη) έχουμε και το γεγονός dblClick() το οποίο δίνει τον αριθμό της επιλογής.

Εδώ πρέπει να ξεκαθαρίσω στον αναγνώστη ότι ενώ οι συναρτήσεις και τα τμήματα εξ ορισμού δεν βλέπουν τίποτα έξω από αυτές, εκτός των όποιων γενικών μεταβλητών και τμημάτων, οι συναρτήσεις γεγονότων είναι "ψεύτικες". Αφενός δεν μπαίνουν σε εκφράσεις (πράξεις). και αφετέρου το όνομα τους δεν είναι αυτό που βλέπουμε αλλά το όνομα του τμήματος ή της συνάρτησης όπου δημιουργήθηκαν. Με αυτόν τον τρόπο έχουμε πρόσβαση σε όλες τις μεταβλητές του τμήματος, καθώς και σε άλλες συναρτήσεις γεγονότων.  Ο τρόπος κλήσης διαφέρει, και για τα γεγονότα γίνεται με την Κάλεσε Τοπικά. Η λέξη τοπικά κάνει την παραλλαγή της κλήσης. Ότι ορίσουμε σε μια συνάρτηση εξυπηρέτησης γεγονότος, θα διαγραφεί. Επίσης όταν καλείται η συνάρτηση από το "παράθυρο" ξεκινάει με νέο σωρό τιμών. Η Κάλεσε εξ ορισμού μεταβιβάζει τον τρέχον σωρό τιμών του  καλούντος. Στη πρώτη  κλήση αυτό δεν έχει κέρδος, δηλαδή αν αφήσουμε δυο τιμές στο σωρό, αυτές θα διαγραφούν με την επιστροφή από την κλήση. Αν όμως καλέσουμε από άλλη συνάρτηση τη συγκεκριμένη, τότε θα μεταβιβαστεί και ο σωρός τιμών. Αυτό βολεύει όταν καλέσουμε μια άλλη συνάρτηση "τοπικά" και αφήσουμε τιμές στο σωρό τιμών (είναι ένας τρόπος να αποφύγουμε να δημιουργήσουμε μεταβλητή που θα πάρει την τιμή και μετά θα την περάσουμε ως έχει στην επόμενη κλήση).
Εδώ καλό είναι επίσης να ξεκαθαρίσουμε ότι η γλώσσα τρέχει πάνω σε ένα περιβάλλον γραμμένο σε Visual Basic 6, και ότι τα γεγονότα έχουν σχέση με αυτή, αν και είναι νέα δηλαδή δεν υπήρχαν τα στοιχεία ελέγχου και γράφτηκαν σε αυτήν. Τα ονόματα των γεγονότων είναι στα αγγλικά από επιλογή, γιατί δεν θα μπορούσαν να ήταν σε δυο γλώσσες (όπως είναι όλα τα αναγνωριστικά στα λεξιλόγια της Μ2000). Κάθε γεγονός πυροδοτεί μια συνάρτηση εξυπηρέτησης. Μπορούμε βέβαια τη μεταβλητή που δηλώνει το μενού να την έχουμε στα ελληνικά, αλλά στη συνάρτηση το όνομα θα είναι το ελληνικό του στοιχείου, μετά μια τελεία και όνομα του γεγονότος στα αγγλικά. Επιπλέον ως προς το πότε εκτελούνται έχει σημασία εδώ να πούμε ότι ενώ η γλώσσα είναι ενός νήματος εκτέλεσης, δηλαδή πάντα εκτελείται μόνο μια εντολή, η σειρά εκτέλεσης αλλάζει λόγω των γεγονότων. Μπορεί ένα γεγονός να έχει κολλήσει κάπου, πχ τραβάει ένα αρχείο από το δίσκο, αλλά αυτό δεν σημαίνει ότι άλλο γεγονός δεν θα εκτελεστεί. Στον meditor, έχει γραφτεί έτσι το πρόγραμμα ώστε να δίνει μήνυμα του πότε ξεκινάει το διάβασμα αρχείου και το πότε τελειώνει. Αν δε κλείσουμε την φόρμα, γίνεται σταμάτημα της φόρτωσης. Όσο δε φορτώνει το έγγραφο μπορούμε να μετακινούμε ή να αλλάζουμε το μέγεθος της φόρμας, που σημαίνει το τελευταίο ότι θα τρέξει κώδικας της Μ2000 για να ρυθμίσει το πώς θα εμφανίζονται τα στοιχεία ελέγχου. Αυτό μας κάνει να νομίζουμε ότι γίνονται παράλληλα εργασίες,αλλά στην ουσία κάθε γεγονός θα πάρει το χρόνο του για να εκτελεστεί. Επειδή ένα μενού που έχει σταλία μπορεί να ανοίξει και να καλέσουμε άλλη ή την ίδια εντολή, οι παράμετροι δεν διαβάζονται με την απλή Διάβασε αλλά με την Διάβασε Νέο, ώστε να φτιαχτούν σίγουρα νέες μεταβλητές. Πάντα το σύστημα τερματίζει το νεότερο προς το αρχαιότερο. Έτσι πάντα "καθαρίζουν" οι πιο πρόσφατες μεταβλητές.  Το σύστημα της Μ2000 έχει τις μεταβλητές σε μια γραμμή "χρόνου". Οι νεότερες διαγράφονται πρώτα. Σε άλλες γλώσσες αυτό γίνεται με το σωρό επιστροφής, return stack, αλλά εδώ ο σωρός επιστροφής είναι για το περιβάλλον της Μ2000, έτσι οι μεταβλητές που φτιάχνουμε πάνε σε μια ιδιόμορφη λίστα, που απλώνει στη λεγόμενη heap, σε όλη δηλαδή τη μνήμη. Αυτή η ιδιόμορφη λίστα κρατάει ονόματα και τιμές μαζί. Τα δε ονόματα έχουν προθέματα που τα διαφοροποιούν ως προς την θέαση. Ο αριθμός ονομάτων δεν ταυτίζεται πάντα με τον αριθμό τιμών/ Αυτό συμβαίνει γιατί κάποια ονόματα είναι "αναφορές" οπότε αναφέρονται σε τιμές που ήδη υπάρχουν άλλα ονόματα γι' αυτές. Τα γεγονότα του συστήματος παραθύρων χωρίζονται σε δυο ήδη, αυτά προς αναμονή, τα οποία δίνουν τιμές, και σε αυτά της άμεσης εξυπηρέτησης, τα οποία δίνουν με αναφορά τιμές. Πχ το γεγονός unload της φόρμας ζητάει να δώσουμε μηδέν ή μη μηδενική τιμή, με την τελευταία να σημαίνει, ακύρωση "αποφόρτωσης". Μπορούμε αν θέλουμε να μην "σηκώσουμε" τη αναφορά. Το σύστημα δεν το ενδιαφέρει το τι θα κάνουμε, η αλλαγή ή όχι της τιμής "εμάς" πονάει! Πχ αν έχουμε κάνει αλλαγές στο κείμενο στον διορθωτή meditor, και πατήσουμε το τετράγωνο που κλείνει τη φόρμα (θέλει διπλό κλικ, με ένα δεν πιάνει), τότε θα μας ρωτήσει αν θέλουμε να σώσουμε τις αλλαγές. Το κλείσιμο της φόρμας μπορεί να γίνει με alt+f4, από τη λίστα ελέγχου της φόρμας (δίπλα στο εικονίδιο, ένα μόνιμο μενού για χρήση και με το πληκτρολόγιο), με το τετράγωνο πάνω στην επικεφαλίδα της φόρμας (αντίθετα από το εικονίδιο), και μέσω του μενού File, με την επιλογή Quit. Όλες οι περιπτώσεις οδηγούν στον ίδιο κώδικα, που βλέπει αν πρέπει να ρωτήσει για να σώσει.

Παρακάτω είναι μια εικόνα από το σύστημα linux με τις δυο οθόνες, η δεύτερη είναι 32άρα τηλεόραση! Τρέχουν ταυτόχρονα τέσσερις παρουσίες του διερμηνευτή. Οι δυο δεξιά τρέχουν το info, από το οποίο ξεκίνησε το meditor, και αυτά έκλεισαν την κονσόλα (την ανοίγουν λίγο πλην τερματίσουν). Οι δυο αριστερά είναι τα προγράμματα που εκ κινήσαμε από τους διορθωτές. Το ένα από αυτά έχει ανοίξει ένα παράθυρο και περιστρέφει ένα 3D γραφικό. Δείτε επίσης στους διορθωτές. είναι ανοικτή η βοήθεια.




εδώ έχω ανοίξει ένα αρχείο 13.5Mbyte, με 575120 γραμμές (το πρόγραμμα ήταν ο παλιός meditor, δεν έχει το μενού Run!


Με το shift F2 ανοίγει φόρμα εισαγωγής για αναζήτηση προς τα πάνω (με shift F3 προς τα κάτω). Αν έχουμε επιλέξει μια λέξη τότε με τα F2 και F3 αναζητούμε χωρίς να βγει η φόρμα. Η λέξη καιρός είναι στην 240317 γραμμή (φαίνεται δίπλα στο μενού)


Παρακάτω είναι κώδικας της Μ2000, χρωματισμένος! Μπορούμε να ορίσουμε η εσοχή να είναι με tab ή με διαστήματα. Με F1 αλλάζουμε την εμφάνιση αναδίπλωση παραγράφου (με ή χωρίς).


Δείτε το νέο πρόγραμμα κατά την εγκατάσταση, ή απευθείας στο Github:
https://github.com/M2000Interpreter/Version9  στο info.gsb

Παρασκευή, 15 Φεβρουαρίου 2019

Revision 19, Version 97 Update (Gui Controls)

New from this revision:
1. Shift F9 in editor and in Editbox control toggle the editor mode from free line to center line (by default is the center line, which means we type in the center line, if there are enough  lines before the current one)
2. The directory/file dialog form now can take keys as we type and automatic find the file. If we move cursor then letters erased, also backspace erase letters too (we didn't saw letters but we saw the result, what we find)
3. Popup menu and the list of Combo control now move the cursor as we hover over it. Menus may have more lines, so we can hold the left mouse button to automatic scroll up or down (also there is a hidden vertical scroll bar, which get visible, at some state, so we can scroll using it, or we can use keys, like page up, page down, home and end).
4. Color, Font, File dialogs now use better the mouse wheel.


Δευτέρα, 11 Φεβρουαρίου 2019

Revision 16, Version 9.7

1. Refactoring for more speed.
2. Addition: Functions in Math object (hyperbolic trigonometric functions)
3. Identifiers from M2000 vocabulary can be used variables/functions, temporary in modules and functions.
4. Addition of modules (M2000 programs) in info.gsb file.
When we install the language, the info.gsb saved in program directory. We have to do this:

dir appdir$
load info

so now we can press F1 to save the file in M2000 user directory (we can open this directory in explorer using Win Dir$  where Dir$ is the current directory as string and Win is the shell statement of M2000)

This is the screen of m2000 console when we load info.gsb (there are commands which run automatic). Info.gsb has 7749 lines. The modules have names as the statement Modules ? return. Also in editor we can use F12 to display a list in a form, and we can click in any name and we get the code in that form.

We can open for edit the info.gsb without loading the modules, using the name in quotation marks (we press Esc to return and save the text, or Shift+F12 to abandon any change):
Edit "info.gsb"

The cyan border help for TV, so we have a safety area to display.





New modules are:


kb, a keyboard for playing music (run on Linux through Wine but with no sound, because utilize the Midi, and Wine has no sound banks to reproduce sound)



FL, a demonstration of rotating flowers. Moving the mouse they separate more, but pressing left mouse button all flowers follow the mouse. Right mouse for exit, with a nice effect of rotating zooming text.

tr

SH, demonstration: moving the console, and how we can get the desktop as an image.




TR, Three oscilloscopes, we can accelerate in any direction.



Σάββατο, 9 Φεβρουαρίου 2019

Revision 15 Version 9.7

Some last minute corrections. Also info.gsb has some added modules: Demo1 for simple 3d graphics in a user form (window), Json (using Lib3 module as library), BJ a black jack simulator, for 4 players.

Corrections:
Wine: From revision 15 was a fault in Esc key, so now is ok (this not happen when the same program, the M2000 interpreter run on a Windows OS).

Fix for For object {} so now old programs can run as expected.

To understand the next fix: When I change the Case in Select Case from executing one statement or a block of statements, to including many statements in one line (but not in block of statements), I gave to the method execution on group objects more than one statement. This was not bad, except for some special statements like restart and continue, which have to interpret at the level from we wish to get the effect of the statement. So the group method executed in a deeper level, and return without
allowing the execution of other statements, onto the deep level, but instead   (inside the functions of interpreter - interpreter is one top function calling other inside, and some of them may call interpreter again, and that is the meaning of the level).

Syntax color: Now anything is after Then and Else are as in a first line, so we get the proper color for operator =, which is white when we use it to assign a value, or yellow when used for comparisons.




Παρασκευή, 8 Φεβρουαρίου 2019

Αναθεώρηση 14, Έκδοση 9.7 Βελτιώσεις!

Σε αυτήν την αναθεώρηση βελτίωσα τη χρήση των Break και Ctrl+C. Επιπλέον το Esc σε ένα μπλοκ Δες {} ή Try {}  τώρα το σταματάει, μαζί με το κώδικα. Υπάρχει η εντολή ΔΙΑΦΥΓΗ ΟΧΙ ή ESCAPE OFF η οποία βγάζει εκτός το ESC.  Όταν τρέχουμε τον διερμηνευτή στην πιο γρήγορη ταχύτητα (ΓΡΗΓΟΡΑ ! ή FAST !, στη κονσόλα ή ΘΕΣΕ ΓΡΗΓΟΡΑ! ή SET FAST! σε πρόγραμμα), τότε δεν γίνονται αυτόματα ανανεώσεις της οθόνης. Παλαιότερα είχα συνδέσει την χρήση των CTRL+C και BREAK με την ανανέωση της οθόνης, αλλά τώρα το άλλαξα ώστε κάθε δευτερόλεπτο ο διερμηνευτής ελέγχει αν αυτά τα πλήκτρα είναι πατημένα, εκτός από την περίπτωση που εκτελεί κάποιο γεγονός (οπότε δεν το διακόπτουμε, αλλά αυτά είναι σύντομα) ή αν έχουμε φόρμες χρήστη. Επειδή στις φόρμες ισχύει το Alt F4 που κλείνει την φόρμα, δεν χρειάζεται άλλο τρόπο "κράτησης".

Μικρές βελτιώσεις στα νήματα, και επιπλέον βρήκα και ένα λάθος, στις λάμδα συναρτήσεις, όπου μια τιμή σε μια συνάρτηση της VB6 πέρναγε με αναφορά, ενώ ήταν από πίνακα, με συνέπεια σε αυτήν την συνάρτηση ο πίνακας να μην μπορούσε να αλλάξει μέγεθος (τον είχε κλειδώσει). Δεν το ήξερα και το βρήκα μέσω ενός παραδείγματος που έκανα με χρήση αναδρομής σε λάμδα συνάρτηση. Το παράδειγμα δεν ήταν σωστό και λογικά θα περίμενα να βγάλει Full Stack, δηλαδή ότι γέμισε ο σωρός επιστροφής Έχω φτιάξει το πρόγραμμα έτσι ώστε να μην πέφτει όταν γεμίζει ο σωρός επιστροφής, δηλαδή τον έχει μετρήσει στην αρχή της εκτέλεσης, και μετά ελέγχει το μέγεθός του, κάθε φορά που καλούμε ένα τμήμα ή μια συνάρτηση (επειδή αυτά είναι που τρώνε περισσότερο από το σωρό επιστροφής). Τελικά ως προς το πρόβλημα, λόγω του λάθους, αυτό που έπρεπε να βγει, ως ένδειξη λάθους δεν βγήκε! Αυτό σήμαινε ότι άλλο λάθος είχε προκύψει. Έτρεξα τον διερμηνευτή στο περιβάλλον της VB6, και το βρήκα! Το μεγαλύτερο πρόβλημα στο θέμα του λάθους, δεν είναι το πώς θα το λύσεις, αλλά το πότε μαθαίνεις για την ύπαρξή του. Άμα μάθεις λοιπόν για το λάθος, δεν αργείς να το διορθώσεις. Το πρόβλημα ήταν ότι όταν πέρναγα με αναφορά στοιχείο ενός πίνακα, δεν μπορούσα σε αυτόν τον πίνακα να αλλάξω μέγεθος. Στη Μ2000 μπορούμε να περνάμε με αναφορά στοιχείο πίνακα. Δείτε όμως πώς. Πρώτα η γλώσσα φτιάχνει μια πρόσκαιρη μεταβλητή, δίνει σε αυτήν την τιμή του στοιχείου του πίνακα, και μετά αυτή μεταφέρεται στο τμήμα που καλούμε. Στην επιστροφή από το τμήμα γίνεται η αντιγραφή από αυτή τη μεταβλητή στο στοιχείο του πίνακα...και εκεί μπορεί να βρεθεί λάθος αν ο πίνακας έχει λιγότερα στοιχεία, και δεν έχει θέση για αυτό που αρχικά πήραμε. H VB6 δίνει κατευθείαν την διεύθυνση του στοιχείου και κλειδώνει το πίνακα! Στην επιστροφή, τον ξεκλειδώνει!  Η λύση ήταν να αλλαχθεί ο τρόπος που πέρναγε η τιμή (αφού δεν με ενδιέφερε η αλλαγή της, δεν γίνονταν αλλαγή στη συνάρτηση που καλούσα), σε By Value, δηλαδή αντέγραφα τον αριθμό (από τον πίνακα) και έτσι η VB6 δεν τον κλείδωνε!

Τετάρτη, 6 Φεβρουαρίου 2019

Αναθεώρηση 13 Έκδοση 9.7

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

GROUP ALFA {
 GROUP BETA
 MODULE TEST_BETA {
  .BETA  =>  SAY "OK"
 }
}
CLASS BEING {
 MODULE SAY (A$) {
  PRINT A$
 }
}
Z=BEING()
\\ pointer show the names group (is a weak reference inside)
ALFA.BETA->Z
ALFA.TEST_BETA
\\ pointer show the float group (is a real pointer)
ALFA.BETA->(Z)
ALFA.TEST_BETA

Εκτός όμως από τα προβλήματα, σήμερα θα δείξω κάτι για την Λάμδα συνάρτηση:

Παρακάτω είναι ένα πρόγραμμα που δείχνει πώς η λάμδα συνάρτηση είναι τύπου τιμής και όχι αναφοράς, αλλά ως μέλος ομάδας (group) για την ομάδα είναι εσωτερικά τύπου αναφοράς (δηλαδή με δείκτη), που σημαίνει ότι αν αντιγράψουμε την Α στη Β και η Α έχει μια λάμδα συνάρτηση αυτή θα αντιγραφεί στο Β ως δείκτης, και έτσι τα οποιαδήποτε κλεισίματα (closures) θα είναι κοινά. Τα κλεισίματα (closures) στις λάμδα της Μ2000 είναι αντίγραφα την ώρα που δημιουργείται η λάμδα και παραμένουν εκεί και για τον κώδικα της λάμδα όταν τον καλούμε άμεσα αλλά και για την περίπτωση της αναδρομικής κλήσης, δηλαδή η λάμδα να καλέσει τον εαυτό της. Επειδή δεν μπορούμε να γνωρίζουμε το όνομα της συνάρτησης λάμδα (οι λάμδα είναι ανώνυμες ουσιαστικά), χρησιμοποιούμε το Λάμδα() ή το Λάμδα$() (lambda(), lambda$()) ως ονόματα για την κλήση αυτή. Τα ίδια ονόματα μπορούν να χρησιμοποιηθούν και σε απλές συναρτήσεις (επειδή και οι απλές έχουν τρόπο να μεταβιβαστούν με αναφορά, και έτσι πάλι χάνεται το αρχικό όνομα της συνάρτησης).


Μια μικρή εξήγηση του κώδικα. Πρώτα ορίζουμε την α ως την τιμή της lambda... (η λάμδα είναι ανώνυμη συνάρτηση και έτσι αυτό που πάει στην a είναι ένας δείκτης στην συνάρτηση, αυτό το λέμε αλλιώς ότι η a είναι αντικείμενο τύπου lambda.

Η λάμδα κατασκευάζεται με τέσσερα μέρη. Πρώτο μέρος είναι το αναγνωριστικό lambda (λάμδα) ή lambda$ (λάμδα$). Αυτό το μέρος λέει στον διερμηνευτή τι γυρίζει η λάμδα, από τα δυο: αριθμό ή αλφαριθμητικό. Μπορεί όμως να γυρίζει αντικείμενο, αλλά σημασία έχει το τι μπορεί να σταθεί αριστερά του ίσον. Εδώ έχουμε για αριθμούς και η μεταβλητή a μπορεί να δεχτεί αριθμούς άρα είμαστε εντάξει. Το δεύτερο μέρος είναι μια λίστα κλεισιμάτων. Η λίστα δεν έχει παρενθέσεις, και τα κλεισίματα μπορούν να έχουν ή να μην έχουν κάποια αρχική τιμή. Όταν δεν βάζουμε αρχική τιμή τότε πρώτα κοιτάει ο διερμηνευτής αν αυτό που έχουμε για κλείσιμο υπάρχει, αν ναι τότε το αντιγράφει, αν όχι το δημιουργεί με αρχικές τιμές. Δεν μπορούμε να περάσουμε πχ ένα πίνακα Α() χωρίς αυτός ήδη να υπάρχει. Μπορούμε όμως να περάσουμε αυτόματο πίνακα, πχ b=(1,2,3,4,5) θα κάνει το b ως κλείσιμο με δείκτη σε πίνακα πέντε στοιχείων. Μετά τα κλεισίματα  ακολουθεί μια λίστα παραμέτρων σε παρενθέσεις. Αυτό είναι προαιρετικό. Τόσο όσον αφορά το αν θέλουμε εισαγωγή παραμέτρων ως και σε όσον αφορά το πώς θα διαβάσουμε τις παραμέτρους.  Όταν έχουμε τη λίστα παραμέτρων τότε ο διερμηνευτής βάζει μια πρώτη γραμμή στο κώδικα ως Διάβασε και ότι ακολουθεί στη λίστα. Θα μπορούσαμε δηλαδή αντί να βάλουμε την λίστα με τις παραμέτρους πριν το βελάκι ->, να βάλουμε μια ή περισσότερες Διάβασε εντός του κώδικας. Ο κώδικας πάει μετά το βελάκι, ή ως μια παράσταση ή ως ένα μπλοκ με πολλές εντολές. Γενικά αν βάλουμε μια παράσταση ο διερμηνευτής φτιάχνει το μπλοκ και βάζει ένα = πριν την παράσταση. Οι συναρτήσεις στην Μ2000 επιστρέφουν τιμή με ένα = ως εντολή. Εδώ έχουμε μπλοκ και το = γυρνάει το χ. Μετά ακολουθεί η άνω και κάτω τελεία που δηλώνει ότι θα ακολουθήσει νέα εντολή και εκεί αυξάνουμε το χ κατά 2. Τα κλεισίματα στις Λάμδα στην Μ2000 μπορούν να αλλάξουν στις λάμδα, απλά η λάμδα δεν τα προσφέρει ως μέλη όπως κάνουν οι ομάδες. Τρίτο μέρος θεωρείται η λίστα παραμέτρων και τέταρτο μέρος ο κώδικας της συνάρτησης. Αν έχουμε ως παραμέτρους διαδοχικά πολλές λάμδα, τότε εκτός από την τελευταία τις άλλες τις βάζουμε σε παρενθέσεις (εκτός και όλα τα τέταρτα μέρη είναι μπλοκ). Αυτό συμβαίνει γιατί σε αυτήν την υλοποίηση της Μ2000 πριν την εκτέλεση μιας παράστασης ο διερμηνευτής με έναν γρήγορο τρόπο βγάζει συμπέρασμα αν είναι αλφαριθμητική ή αριθμητική η παράσταση που ακολουθεί για να καλέσει τις αντίστοιχες εσωτερικές δικές του συναρτήσεις.

Μετά ακολουθεί η δημιουργία ενός αντικειμένου χρήστη, η λεγόμενη ομάδα (Group). Εδώ  η ομάδα έχει όνομα G, και θα υπάρχει όσο το τμήμα που φτιάχτηκε συνεχίζει να εκτελείται. Σε αυτήν ορίζουμε μια ομάδα k με ένα μόνο αποτέλεσμα το 0 (δεν βάζουμε το =, θα το βάλει ο διερμηνευτής).
Μέλη στην ομάδα λέμε τις μεταβλητές και τους πίνακας. Η  λάμδα αφού έχει μεταβλητή είναι μέλος. Ουσιαστικά μέλη είναι και τα τμήματα (modules) και οι συναρτήσεις (functions) αλλά δεν τα λέμε μέλη, τα λέμε μεθόδους. Η λέξη ιδιότητα δηλώνει ένα είδος μέλους που λέγεται ιδιότητα, και είναι ουσιαστικά μια ομάδα που γυρνάει τιμή ή παίρνει τιμή ή κάνει και τα δύο, και μπορούμε να ελέγχουμε τι παίρνουμε και τι δίνουμε (σε άλλες γλώσσες αυτό θα ήταν ένα αντικείμενο με getters και setters).

Οπότε ξεκινάμε να δείξουμε ότι κάθε φορά που καλούμε την a() αυτή δίνει την τιμή του x και τον αυξάνει κατά 1. Μετά εισάγουμε στην G.k που είναι λάμδα την a. Ο διερμηνευτής βλέπει τις λάμδα ως πρώτους πολίτες (first citizen), που σημαίνει ότι λειτουργούν όπως οι μεταβλητές, παίρνουν και δίνουν αντίγραφο της τιμής τους. Εδώ το αντίγραφο θα είναι μαζί με τα αντίγραφα των κλεισιμάτων.

Επίσης φτιάχνουμε την ομάδα G1 ως αντίγραφο της G. Θα δούμε μετά γιατί το κάνουμε αυτό.

Για να δείξουμε ότι όντως έχουμε αντιγραφή του κλεισίματος x, αρκεί να τρέξουμε πρώτα την a() δυο φορές, ώστε να έχουμε τα 3 και 4 ως αποτέλεσμα και μετά να καλέσουμε στο G το τμήμα test_me το οποίο συγκρίνει μια τιμή που δίνουμε, τα 3 και 4 και αν συμπίπτει με την τιμή της λάμδα συνάρτησης k() (δείτε τη τελεία πριν το k στο κώδικα, λέει ότι το k είναι μέλος της ομάδας).

Μετά θέλουμε να δείξουνε ότι στην αντιγραφή ομάδας σε νέα ομάδα, η λάμδα ως μέλος θα αντιγραφεί ως δείκτης και όχι ως τιμή. Αρκεί να καλέσουμε την ίδια μέθοδο στο δεύτερο αντικείμενο, στο G1. Αν ήταν περασμένη με τιμή θα έπρεπε να ξεκινήσει η αρίθμηση από το 3 (αφού τότε εκεί ήταν η k του G. Όμως βλέπουμε ότι θα πάρουμε τιμές 4 και 5, άρα έχουμε αντιγραφή με δείκτη που δείχνει την ίδια λάμδα. Ο δείκτης είναι ένα αντικείμενο φορέας που περιέχει ένα δείκτη στην λάμδα. Αυτός ο φορέας είναι θεατός μόνο από τον διερμηνευτή. Αν τώρα βάλουμε πάλι στο k του G την τιμή του a, τότε θα δείξουμε ότι τα G και G1 δεν έχουν πια κοινή λάμδα! Αυτό πάλι είναι εύκολα κατανοητό εφόσον τρέξουμε την k του G που θα μας δώσει το 5 (αλλιώς θα μας έδινε το 7), και όντως η k του G1 δίνει 7. Επίσης βλέπουμε ότι η a δεν έχει αλλάξει και ότι αν καλέσουμε την συνάρτηση a() δυο φορές θα πάρουμε τα 5 και 4.



a=lambda x=1 ->{
 =x : x++
}
Group G {
 k=lambda ->0
 module test_me (n) {
  Print .k()=n
 }
}
Print a()=1, a()=2
\\ G.k get a copy of a
G.k=a
\\ G1.K get a reference of G.K
G1=G
Print a()=3, a()=4
G.test_me 3
G.test_me 4
\\ this shows that G1 get G.k by reference
G1.test_me 5
G1.test_me 6
\\ reloading G.k as a copy of a, so now G.k has a new pointer to a new copy of a
G.k=a
G.test_me 5
G1.test_me 7
Print a()=5, a()=6