Παρασκευή 15 Ιανουαρίου 2016

Εμπλουτισμός Αντικειμένων Ι (Μ2000)


Στη Μ2000 τα αντικείμενα λέγονται ομάδες και μπορούν να έχουν μεταβλητές, συναρτήσεις, τμήματα, πίνακες, και άλλες ομάδες. Αυτό που δεν έχουν άμεσα είναι μεταβλητές κλάσης. Επειδή μια κλάση είναι μια συνάρτηση που επιστρέφει μια ομάδα δεν έχει να κάνει με κάποια λίστα καταγραφής. Η κάθε ομάδα που φτιάχνουμε έχει τη δική της λίστα με το τι περιέχει.
Μάλιστα μια ομάδα με όνομα έχει κάθε στοιχείο της ως μεταβλητή του τμήματος, κυριολεκτικά. Με την εντολή Λίστα θα δούμε όλα τα στοιχεία με πρόθεμα το όνομα της ομάδας, και ένα στοιχείο ξέχωρο το αντικείμενο με το όνομα. Αυτό κρατάει μια λίστα που χρειάζεται για να περνάμε με αναφορά ή με αντιγραφή την ομάδα σε συναρτήσεις/τμήματα/σωρό.
Σε μια ομάδα με όνομα δεν μπορούμε να διαγράψουμε στοιχεία!Με το που φτιάχνονται τα στοιχεία μπαίνουν στην λίστα του τμήματος. Μπορούμε να χρησιμοποιήσουμε το Για ΌνομαΟμάδας { } ώστε να ανοίξουμε ένα μπλοκ για προσωρινές αλλαγές στη λίστα στοιχείων του τμήματος, που σημαίνει ότι μπορούμε πρόσκαιρα να έχουμε μεταβλητές στην ομάδα, αλλά εδώ δεν θα επεκταθούμε σε αυτό. Θα δούμε δηλαδή μια πιο κανονική προσέγγιση. Αυτό που σίγουρα θα έχουμε δει και σε άλλες αναρτήσεις σε αυτό το blog είναι ότι μπορούμε να προσθέτουμε στοιχεία, ή και να αλλάζουμε διαστάσεις στους πίνακες, ή και να αλλάζουμε ορισμούς στα τμήματα και στις συναρτήσεις.
Επιπλέον έχουμε δει και ότι το "=" μεταξύ δυο ομάδων (έστω Α και Β είναι ομάδες) όπως το Α=Β δεν θα κάνει το Α ίσο με το Β αλλά θα βάλει τα στοιχεία του Β στο Α και όσα έχουν ίδιο όνομα θα αλλάξουν. Που σημαίνει ότι κάνουμε ένωση.
Εδώ πρέπει να ξεχωρίσουμε την περίπτωση που έχουμε κλειστές ομάδες. Σε στοιχεία πίνακα μπορούμε να έχουμε μόνο κλειστές ομάδες. Λέγονται κλειστές γιατί δεν "ανιχνεύονται", δεν έχουν τα στοιχεία τους στη λίστα στοιχείων του τμήματος που βρίσκονται (είναι πραγματικά encapsulated). Στις κλειστές ομάδες και όσο είναι κλειστές γίνεται αντικατάσταση, Δηλαδή χάνεται το παλιό και στη θέση του μπαίνει το νέο. Δεν υπάρχουν ενεργές αναφορές στα αντικείμενα της Μ2000. Οι αναφορές υπάρχουν εκεί που εκτελείται κώδικας. Αντίθετα μπορούμε να κρατάμε ισχνές αναφορές. Δηλαδή μισές αναφορές, οι οποίες ενδέχεται να μην δείχνουν σε υπάρχον στοιχείο. Εδώ δεν έχουμε θέμα με διευθύνσεις. Οι ισχνές αναφορές έχουν ονόματα, οπότε η χρήση τους είναι θέμα του προγραμματιστή.
Σύντομη περιγραφή με τη χρήση (δείτε πως η Α$ μπορεί να αλλάζει, να δείχνει κάτι άλλο)
Χρησιμοποιούνται οι Weak$() που φτιάχνει το δείκτη, η Eval() για αριθμητικές παραστάσεις (Από αλφαριθμητικό). η Eval$() για αλφαριθμητικές παραστάσεις με δείκτες - και χωρίς- η Function() καθώς και αυτή που δεν φαίνεται η Function$() για συναρτήσεις που γυρνάνε αλφαριθμητικά.
Ο διερμηνευτής βρίσκει ότι κάτι έχει δείκτη από το ζευγάρι αυτό $. (δεν υπάρχει περίπτωση κάπου αλλού να έχουμε το δολάριο και την τελεία μαζί). Μόνο στην Eval όταν το αποτέλεσμα είναι αλφαριθμητικό - ενώ ζητάμε αριθμό υπολογίζεται για δείκτης.
Πρόσθεσα  και παράδειγμα με τα Array() και Array$() για πίνακες και ισχνές αναφορές.

k=10
A$=Weak$(k)
A$.+=20
Print Eval(A$.) ' 30
Print Eval(A$) ' we can exclude right dot
B$="George"
A$=Weak$(B$)
Print Eval$(A$.) \\ look the dot right
Print Eval$(A$) \\ now we get the pointer (not the value from pointer)
A$.="Hello"
Print Eval$(A$.) \\ Hello
Print B$ \\ Hello
Group Alfa {
      X=10
      Function X2 { =.X**2+Number}
      Module XX {Print "ok", .X }
}
A$=Weak$(Alfa)
A$.X++
Print Eval(A$.X) ' 11
Print Function(A$.X2,20) ' 141
A$.XX ' print: ok             11


Dim A(10,3)=20, B$(4)="ok"
A$=Weak$(A())
Print Array(A$, 3,2) ' 20
A$=Weak$(B$())
Print Array$(A$, 3) 'ok


Πάνω λοιπόν στις ισχνές αναφορές δουλεύει και το παρακάτω παράδειγμα. Εδώ σκοπός μας είναι να βάλουμε σε μια ομάδα εκ των υστέρων  (υπάρχει δηλαδή η ομάδα) σύνδεση με μια γενική (Global), μια τοπική αριθμητική και μια τοπική αλφαριθμητική, όπου όλες θα φαίνονται μέσα σε όλες τις ομάδες που θα φτιάξουμε με την αρχική. Για να πετύχουμε περισσότερα έχουμε φτιάξει μια συνάρτηση την Pass3group η οποία παίρνει το όνομα που θα θέλαμε να έχει μια μεταβλητή που την περνάμε με ισχνή αναφορά (και με πέρασμα &kl$ περνάμε ισχνή αναφορά. Σημασία έχει αν από την πλευρά της συνάρτησης η Διάβασε διαβάζει αλφαριθμητικό ή διαβάζει αναφορά με &. Αν κάνει το δεύτερο τότε φτιάχνει κανονική αναφορά, εμείς εδώ κάνουμε το πρώτο, διαβάζουμε αλφαριθμητικό, άρα την ισχνή αναφορά. (δες την μεταβλητή var$).
Αφού φτιάξουμε τις τρεις μεταβλητές, δούμε πως τις αλλάζουμε, πως τις διαβάζουμε, μετά αντιγράφουμε σε μια επώνυμη ομάδα και μετά σε μια κλειστή σε πίνακα. Επίσης περνάμε τον πίνακα με αναφορά σε ένα τμήμα και βλέπουμε ότι λειτουργούν όλα καλά!
Όμως όλο σχεδόν το παράδειγμα έγινε σε ένα CheckAll για να δούμε την επιστροφή του πίνακα ομάδων που κάνουμε με την Βάλε (Push) στο σωρό τιμών. Με το που επιστρέφουμε από το τμήμα (το είχαμε καλέσει με Call ή Κάλεσε αλλά δεν χρειάζονταν ιδιαίτερα, θα μπορούσαμε να το παραλείψουμε), διαβάζουμε από το σωρό τον πίνακα (σε ένα στοιχείο του σωρού ήταν όλος ο πίνακας). Τώρα δοκιμάζουμε τα Exist...για να δούμε αν τι έχουμε (μόνο βέβαια την γενική MyVar)


Global myvar=100
Module CheckAll {
      \\ This function construct variables with weak reference to globals or locals
      \\ And return a group for union
      \\ Make the variable as a string contains weak reference
      \\ We make GetVar() function, SetVar module and ExistVar() function
      Function Pass2group {
            Read name$, var$
            if Right$(var$,1)="$" then {
                  name$=Filter$(name$,"$")
                  template$={
                  glob{0}$="{1}"
                  Function Get{0}$ %%=Eval$(.glob{0}$.)||
                  Module Set{0} %%.glob{0}$.<=Letter$ ||
                  Function Exist{0} %% =Valid(Eval$(.glob{0}$.)="")||
                  }
            } else {
                  template$={
                  glob{0}$="{1}"
                  Function Get{0} %%=Eval(.glob{0}$)||
                  Module Set{0} %%.glob{0}$.<=Number||
                  Function Exist{0} %% =Valid(Eval(.glob{0}$))||
                  }
            }
            template$=format$(template$,name$, var$)
            template$=replace$("%%","{",template$)
            template$=replace$("||","}",template$)
            group aa type template$
            =aa
      }
      Group AA {
            M=10
      }
      \\ we add a global
      AA=Pass2group("X", Weak$(myvar))
      Print AA.GetX()
      AA.SetX 123
      Print AA.GetX()
      alfa=1000
      \\ we add a local
      AA=Pass2group("Y", Weak$(alfa))
      Print AA.GetY()
      kl$="Ok"
      \\ we add a local string
      AA=Pass2group("K$", Weak$(kl$))
      Print AA.GetK$()
      AA.SetK "Hello There"
      Print AA.GetK$()
      Dim Alfa(10)=AA
      Print Alfa(2).GetK$()
      Alfa(5).SetK "Change it"  ' change to Alfa(5) also change for all
      Print Alfa(2).GetK$()
      Module CheckMe {
            Read &All()
            For All(4) {
                  Print .GetX(), .GetY(), .GetK$()
                  .SetY 500 ' we set alfa in module
            }
            Print All(9).ExistY() ' -1
      }
      CheckMe &Alfa()
      Print alfa ' 500
      Push Alfa() \\ export array from module
}
Call CheckAll
Read AA()
Print AA(2).ExistY() ' 0 no not now
Print AA(3).M ' Only M exist and...
Print AA(4).ExistX() ' X as global  MyVar
Print AA(4).GetX()


Πέμπτη 14 Ιανουαρίου 2016

Παράδειγμα Πίνακα ως Vector (και αναθ. 138)

Έγινε η Αναθεώρηση 138 με μια μικρή διόρθωση στο χρωματισμό κώδικα.

Πίνακας ως Vector (Πίνακας με στοιχεία με  διαφορετικούς τύπους)
Παρακάτω είναι ένα πρόγραμμα όπου χρησιμοποιούμε έναν πίνακα για να βάλουμε αριθμούς, αλφαριθμητικά, ομάδες (κάτι ως Vector σε άλλες γλώσσες). Λογικά μπορούμε να βάλουμε σε πίνακα ότι ομάδα θέλουμε (αντικείμενο της Μ2000). Αλλά δεν είναι αναγκαίο όλα τα στοιχεία να είναι ομάδες.
Πως γίνεται λοιπόν να βάλουμε σε έναν πίνακα έστω Α() με 10 στοιχεία αλφαριθμητικά; Πώς γίνεται σε έναν πίνακα Α$() να βάλουμε αριθμούς και ομάδες (ενώ γράφονται σε πίνακες αριθμών).

Ξεχνάμε για λίγο τα αντικείμενα (ομάδες). Με την Ένωσε δίνουμε με αναφορά τον πίνακα του Α() στο Α$(), ας τον λέμε βοηθό. Στην ουσία ο πίνακας υπάρχει μια φορά, αλλά ο βοηθός Α$() διαβάζει αλφαριθμητικά...ή ότι έχει ο Α() ως αλφαριθμητικό. Μπορούμε να βάλουμε αλφαριθμητικά στον Α() χωρίς την ανάγκη του βοηθού Α$() . Αυτό γίνεται με το ":="
Σε ένα πίνακα μπορούμε να δίνουμε πολλαπλές τιμές με το "=" αλλά στο ίδιο είδος, το ":="
Η εντολή Α(0)="άλφα βήτα", 2000, "Κάτι άλλο" θα δώσει λάθος, επειδή περιμένει ο διερμηνευτής αριθμητική παράσταση.


Πίνακας Α(10)
Ένωσε Α() στο Α$()
Α(0):="άλφα βήτα", 2000, "Κάτι άλλο"
Τύπωσε Α$(0), Α(1), Α$(2)



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

Η ομάδα Άλφα  έχει ουσιαστικά "εγκαταστήσει" τα Α.χ,  Α.ψ και Α.ζ και στην Μ2000 δεν σβήνονται από το "σκοπό" εδώ το τμήμα, αν ο σκοπός δεν παρέλθει (όταν δηλαδή τερματίσει το τμήμα).  Αλλά στο πίνακα Α και στο στοιχείο 4 δηλαδή στο Α(4) έχουμε ένα ανώνυμο τμήμα (δεν έχει εγκατασταθεί κάπου, βρίσκεται κλειστό στο στοιχείο). Μπορούμε να το σβήσουμε με μια κίνηση! Βάζοντας ένα άλλο αριθμό ή μια άλλη ομάδα! Στο παράδειγμα παίρνουμε ένα αντίγραφο στο Α(5) και σβήνουμε το Α(4) με μια τιμή 0. Ελέγχουμε το τύπο του Α(4), είναι Double και ελέγχουμε αν υπάρχει στοιχείο ζ στο Α(4) με την Έγκυρο(), και μας δίνει 0 (ψευδές), δεν υπάρχει.
Αυξάνουμε την τιμή του ζ στο Α(5) και αντιγράφουμε το Α(5) στο Α(4).

Ουσιαστικά η Μ2000 δεν έχει δείκτες σε αντικείμενα, ούτε μετράει τις αναφορές σε αυτά! Δεν χρειάζεται! Αυτό που έχει είναι πίνακες που τους χειρίζεται ως εικονική μνήμη. Η Στοκ δουλεύει και για πολυδιάστατους πίνακες και τους χειρίζεται ως μονοδιάστατους. Κερδίζουμε με τη χρήση της γιατί στις αντιγραφές στοιχείων υπολογίζεται αυτόματα το επόμενο στοιχείο βάσει του "επιπλέον", του offset.
Στο τρίτο μέρος του παραδείγματος, κάνουμε αλλαγή μεγέθους στο πίνακα Α() διατηρώντας τα στοιχεία που είχε. Η αλλαγή έγινε και για το Α$() (ουσιαστικά και τα δυο δείχνουν τον ίδιο πίνακα).
Εδώ λοιπόν κάνω αντιγραφή από βάση 0 σε βάση 10 για 6 στοιχεία (από 0 έως και 5 στο 10 έως και 15). Η Στοκ μπορεί να αντιγράψει κατά ένα στοιχείο πάνω ή κάτω (όχι εκτός ορίων), με τρόπο ώστε να μη χάσει στοιχεία. Στοκ Α(0) για 6, Α(1)  και μετά στο Για βάλτε Για ι=5 έωςθα έχουμε το ίδιο αποτέλεσμα! Η δεύτερη Στοκ με το Σε  βάζει τιμές σε μεταβλητές. Οπότε αν θέλουμε δεν χρησιμοποιούμε την Ένωσε Α() στο Α$() αν και δεν έχει κόστος και βοηθάει αν θέλουμε να διαβάζουμε με μια Για { }.
Εδώ έχω χρησιμοποιήσει την Ομάδα Άλφα με απευθείας ορισμό ομάδας: Διαφορετικά θα έκανα:
Κλάση Αλφα_ { χ=10, ψ, ζ=3}
Αλφα=Αλφα_()
Τύπωσε Αλφα.ζ

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



Ομάδα Αλφα { χ=10, ψ, ζ=3}
Πίνακας Α(10)
Ένωσε Α() στο Α$()
Στοκ Α(0) από "άλφα βήτα", 2000, "Κάτι άλλο", Αλφα.χ, Αλφα
Άλφα.ζ=1000
Τύπωσε Α$(0), Α(1), Α$(2), Α(3), Α(4).ζ


Τύπωσε Τύπος$(Α(4)) ' Group
Α(5)=Α(4) ' αντιγραφή
Α(4)=0 ' σβήσαμε το αντικείμεο από το Α(4)
Τύπωσε Τύπος$(Α(4)), Έγκυρο(Α(4).ζ) ' Double   0
Α(5).ζ++
Α(4)=Α(5)
Τύπωσε Α(4).ζ ' τυπώνει 4


Α(4).ψ=1000
Πίνακας Α(30)
Στοκ Α(0) για 6, Α(10)
Στοκ Α(10) σε Α1$, Α2, Α3$, Α4
Τύπωσε Α1$, Α2, Α3$, Α4
Για ι=14 έως 15 {
      Για Α(ι) {
            Τύπωσε .χ,,
      }
}




Στο 2ο μέρος έχω ένα μικρό θέμα με το πώς ένα αντικείμενο γνωρίζουμε ότι είναι μοναδικό!
Αφού κάνουμε αντιγραφές στα αντικείμενα, τότε πως ξέρουμε αν υπάρχει πρωτότυπο;
Αυτό το λύνει η τοπική στη κλάση! Μάλιστα καλούμε ένα τμήμα και περνάμε με αναφορά το αντικείμενο και μας δείχνει άμεσα ποιο είναι γνήσιο!

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

Όταν κάνουμε αντιγραφές δημιουργούμε ουσιαστικά ένα κλειστό αντικείμενο, και η τιμή της α1 δεν δίνεται από την τρέχουσα αλλά από εκείνη που καταγράφηκε την πρώτη φορά που ορίστηκε.
Έχω δώσει και μια λύση πως γίνεται να φαίνεται έγκυρο ένα αντικείμενο, αλλά δείτε όμως ότι πρέπει να πάρουμε την τιμή του Α.α1 δεν γίνεται διαφορετικά! Στο τμήμα Δοκίμασέ_με η κάτι.α1 δεν υπάρχει και για τις τρεις περιπτώσεις. Αυτό συμβαίνει γιατί δεν υπάρχει στη λίστα των μεταβλητών που περνούν με αναφορά. Η συνάρτηση ΔεςΜε() βλέπει τις μεταβλητές γιατί όταν τρέχει σαν Κάτι.ΔεςΜε() αλλάζει όνομα χώρου και πάει σε αυτό του αντικειμένου. Αυτό συμβαίνει γιατί κατά τη δημιουργία αναφορών στα τμήματα και συναρτήσεις ενός αντικειμένου δίνονται όλες οι πληροφορίες. Να γιατί δεν μπορούμε να δώσουμε ως αναφορά στοιχείο πίνακα αν δεν το ανοίξουμε πρώτα.


Κλάση Α_ {
      Τοπική α1=0 ' αρχική τιμή
      χ=1234, ψ
      Συνάρτηση ΔεςΜε {
            Αν Έγκυρο(.α1) τότε {
                  =.α1
            } Αλλιώς {
                  =0
            }
      }
}
\\ φτιάχνω το Α
Α=Α_()
\\ Δίνω στη τοπική α1 μια τιμή
Α.α1=Τυχαίος(1,10000)
Τύπωσε Α.ΔεςΜε()
\\ Αντιγράφω το Α στο Β
Β=Α
\\ Δεν έχει αντιγραφεί η "τοπική"
Τύπωσε Β.ΔεςΜε()
\\ Β.α1 = Α.α1  'έτσι το κάνουμε να φαίνεται γνήσιο
Τύπωσε Β.ΔεςΜε()
Πίνακας Α(1)
Α(0)=Α
\\ Αντιγράφω το Α ως κλειστό αντικείμενο στο Α(0)
\\ Δεν έχει αντιγραφει η "τοπική"
Τύπωσε Α(0).ΔεςΜε()


Τμήμα Δοκίμασέ_με {
      Διάβασε &κάτι
      Τύπωσε κάτι.χ, κάτι.ΔεςΜε(), Έγκυρο(κάτι.α1)
}
Δοκίμασέ_με \\ οκ είναι γνήσιο
Δοκίμασέ_με \\ 0 δεν είναι γνήσιο
Για Α(0) {
      \\ .α1=Α.α1    ' έτσι το κάνουμε να φαίνεται γνήσιο
       Δοκίμασέ_με &Αυτό \\ δεν είναι γνήσιο
}


Αναθεώρηση 137 - Περάσματα Συναρτήσεων

Βελτίωση στη ταχύτητα.
Δείτε το παρακάτω παράδειγμα. Περνάω μια συνάρτηση με τρεις τρόπους σε ένα τμήμα Η συνάρτηση ανήκει σε μια κλάση και από αυτή έχω φτιάξει μια ανώνυμη ομάδα (αντικείμενο). Το For A(0)  { } μπλοκ ανοίγει την  ομάδα.
Καλώ το πρώτο τμήμα, το Check και περνάω την GG() συνάρτηση. Στο Check καλώ τη συνάρτηση με το 100, και τυπώνεται το αποτέλεσμα .Α*100 δηλαδή το 100. Κάνω την Α 20, και αυτή αλλάζει στην ανοικτή ομάδα...έξω από το τμήμα!

Καλώ το δεύτερο τμήμα, το Check1 αλλά εδώ έχω κάνει το εξής. Έχω συνδέσει το This (την ανοικτή ομάδα) σε ένα όνομα...το Β. Τώρα μπορώ να φτιάξω μια οκνηρή αποτίμηση. Δηλαδή το B.GG(BB*100) δεν εκτελείται άμεσα αλλά φτιάχνει μια ανώνυμη συνάρτηση και εκτελείται εκεί που θα παραδοθεί (όσες φορές θέλουμε). Αυτήν περνάω στην Check1 και εκεί εκτελείται και μας δίνει το 20000 και επίσης αυξάνει το Α σε 30. Δείτε όμως ότι η ΒΒ είναι μεταβλητή του τμήματος απ΄όπου καλέσαμε το Check1. Στην ουσία η συνάρτηση που δίνουμε είναι τμήμα του τμήματος που κάλεσε το Check1.

Καλώ το τρίτο τμήμα, το Check2 και εδώ δίνω μια συνάρτηση μόνο την &.GG() χωρίς να δώσω τιμές αλλά με παραγωγή αλφαριθμητικού. To Check2 διαβάζει το αλφαριθμητικό και το χρησιμοποιεί στην Function() με παράμετρο το 50.

Ξανά καλώ το Check με το Lazy$(&.GG()) το οποίο είναι ίδιο με αυτό &.GG() και τα δυο δηλαδή δίνουν το ίδιο πράγμα, ένα αλφαριθμητικό που θα γίνει συνάρτηση.


Αν το δει κανείς το θέμα αυτό...δίνουμε συνάρτηση σε ένα τμήμα και αυτό μπορεί να τη καλέσει όσες φορές θέλει, και να αλλάζει κάτι εκεί από όπου πήραμε τη συνάρτηση.

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

Η συνάρτηση ModulePart είναι τμήμα του τμήματος το οποίο το περνάμε στο Check1. Εκεί εκτελείται μεταφέροντας το περιβάλλον του αρχικού τμήματος. Δείτε πως καλούμε την Check1 και πάλι την καλούμε μέσα από την ModulePart.
Αν αφαιρέσουμε το Function ModulePart { } και την εντολή μετά, και αφήσουμε το περιεχόμενο τότε θα έχουμε ακριβώς το ίδιο αποτέλεσμα!



Class AAA {
      A=10
      FUNCTION GG {
            Read num
            Print .A*num
            .A+=10
      }
}
Module Check {
      Read &B()
      Call B(100)
}
Module Check1 {
      Read A$
      AA=Function(A$)
}
Module Check2 {
      Read A$
      AA=Function(A$, 50)
}


dim a(1)
a(0)=AAA()
BB=10


Function ModulePart {
      For a(0) {
            Check &.GG() ' 1000
            Link This to B \\ we give a temporary name to A(0)
            Check1 Lazy$(B.GG(BB*100)) ' 20000
            Check2 Lazy$(&.GG()) ' 1500
            Check Lazy$(&.GG()) ' 4000
      }
}
Check1 Lazy$(&.ModulePart())

Print a(0).A ' 50

Τετάρτη 13 Ιανουαρίου 2016

Ισότητα για αντικείμενα (Μ2000)

Στις νέες εκδόσεις και ειδικότερα στην 10 υπάρχει ο τελεστής είναι που μας λέει αν δυο αναγνωριστικά δείχνουν το ίδιο αντικείμενο. Επίσης υπάρχει ο τελεστής είναι τύπος  που παίρνει δεξιά τον όνομα του τύπου ενός αντικειμένου (βασικού τύπου Ομάδα) και αριστερά μια ομάδα και μας λέει αν είναι ή όχι αυτός ο τύπος:
Κενός=(,)
Α=(1,2,3,4)
Β=Α
Τύπωσε Α είναι Β, Α είναι Κενός ' Αληθές Ψευδές
Α=Κενός
Τύπωσε Α είναι Β, Α είναι Κενός ' Ψευδές Αληθές


Κλάση Αλφα {
Χ=1, Ψ=1
}
Γ=Αλφα()
Τύπωσε Γ είναι τύπος Αλφα ' Αληθές
Κλάση Βήτα ως Αλφα {
Τμήμα ΧΨ {
Τύπωσε ,
}
}
Δ=Βήτα()
Τύπωσε Δ είναι τύπος Βήτα ' Αληθές
Τύπωσε Δ είναι τύπος Αλφα ' Αληθές
Τύπωσε Γ είναι τύπος Βήτα ' Ψευδές
Δες {
Τύπωσε Γ είναι Α
}
Αν Λάθος Τότε Τύπωσε Λάθος$
Ζ->Γ
Τύπωσε Ζ είναι Γ ' Αληθές
Ζ->Δ
Τύπωσε Ζ είναι Γ ' Ψευδές
Τύπωσε Δ είναι Γ
Μ=Δ
Τύπωσε Δ είναι Μ ' Ψευδές

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



Στη Μ2000 δεν έχουμε συνάρτηση η μέθοδο που να μας δηλώνει αν δυο αντικείμενα είναι ίδια.
Μπορούμε να δούμε αν έχουν ίδιες τιμές, με δική μας συνάρτηση.

Εδώ είναι ένα πρόγραμμα στα αγγλικά που κάνει αυτό το πράγμα. Επίσης δείχνει και μερικά άλλα πράγματα! Για την εξαγωγή έχω γράψει ένα βοηθητικό τμήμα που γυρνάει σε $(7) δηλαδή δεξιά στοίχιση με αναλογική γραφή.

\\ We use a small module for printing
Module PrintBool {
      \\ read any from stack
      \\ numbers  0 or -1 are dispalyed as False or True
      \\ All are right justify in column
     While Not Empty {
            If IsNum then {
                  Print $(7),str$(Number,";\T\r\u\e;\F\a\l\s\e;"),$(0)
            } Else Print $(7),Letter$,$(0)
     }
     Print
}
Class Alfa {
      A=10, B$, K
      Function AxK {
            Read .K
            =.A*.K
      }
}
\\ now we have a Alfa() class function
\\ so we can make a group X
X=Alfa()
\\ now we have a X with 3 parameters and a function
Flush \\ we empty the stack...to ensure that PrintBool take only what we give
PrintBool format$("X.AxK(10)={0}",X.AxK(10)) ' prints X.AxK(10)=100
\\ we can make a Group Y also
Group Y {
      A=10, B$, K
}
\\ In M2000 we don't have an equal operator for Groups
\\ Groups return 0 as value - and also pass a reference
\\ So we make these functions
Function Equal {
      Read A, B
      =A.A=B.A and A.B$=B.B$ and A.K=B.K
}
Function Equal2 {
      Read &A, &B
      =A.A=B.A and A.B$=B.B$ and A.K=B.K
}
KK=X=Y \\ KK is a copy of Y  -- So Don't used it
PrintBool Type$(KK) \\ also we can print labels
KK1=X=Y or true \\ KK1 is a double with value -1  -- also don't used
PrintBool Type$(KK1)
\\ we can't use an operatror for Equality
\\ We can use a user function and extract what we mean by equal
\\ Here Equal as for variables


\\ Because PrintBool read any number of parammeters is good to open a clear new stack
Stack New {
      PrintBool Equal(X,Y) \\ false
      Y.K=10
      PrintBool Equal(X,Y) \\ true  as for variables  - PASSING BY VALUE -COPY
      PrintBool Equal2(&X,&Y) \\ true  as for variables PASSING BY REFERENCE
      Y=X \\ we can make a union - so now Y has a function AxK()
      Print Y.AxK(20)
      Push 10=10 \\ look the effect of using stack, the next module read 4 parameters
      PrintBool Equal2(&X,&Y),3=3, 4>5
}


Πίνακες αντικειμένων με Πίνακες αντικειμένων

Μικρό πρόγραμμα (στα αγγλικά)  με κλάση Mem() που φτιάχνει πίνακες με κλάσεις. Στο παράδειγμα φτιάχνουμε πρώτα το Μ με την κλάση Mem() να περιέχει 100 στοιχεία από την κλάση D3. Μετά κάνουμε resize τον πίνακα της Μ βάζοντας επιπλέον 100 στοιχεία από την ίδια κλάση. Εκτελούμε και μια καταχώρηση ίδιας τιμής σε μια περιοχή στο πίνακα (με το τμήμα ResetRange )
Μετά φτιάχνουμε ένα αντικείμενο ΜΜ ως κλάση Mem() με 100 στοιχεία από κλάση Mem() με δέκα στοιχεία (δέκα έχουμε βάλει εξ ορισμού, δες το Ν=10)  από την κλάση D3. Κάνουμε διάφορες εργασίες όπως αντιγραφή, αλλαγή μεγέθους επιλεκτικά σε ένα από τα 100 στοιχεία,
Μετά βγάζουμε ένα αντίγραφο του ΜΜ στο ΚΚ. Μάλιστα του αφαιρούμε τα μισά στοιχεία (κρατάμε το κάτω μισό). Στην αντιγραφή του ΜΜ στο ΚΚ έχει γίνει αντιγραφή του κάθε στοιχείου του ΜΜ, και όλων των στοιχείων και πινάκων μέσα σε αυτό.
Θα μπορούσαμε να βγάλουμε ένα αντίγραφο του ΜΜ στο σωρό τιμών και να το "σηκώσουμε" σε ένα ΚΚ (μπορεί να γίνει και ως επιστροφή σε τμήμα που καλούμε)
Push MM
Read KK

Σε συνάρτηση μπορούμε να γράψουμ =ΜΜ και να γυρίσουμε το αντικείμενο
οπότε ένα ΚΚ=ΜιαΣυνάρτηση() θα δώσει το αντίγραφο του ΜΜ (ενώ το ΜΜ θα έχει διαγραφεί με το πέρας της ΜιαΣυνάρτηση )
Οι κλάσεις είναι στην ουσία συναρτήσεις που γυρίζουν αντικείμενα (ομάδες λέγονται στην Μ2000). Ένα τμήμα (Module) με το ίδιο όνομα με τη κλάση είναι ο κατασκευαστής, δηλαδή όταν καλούμε την Mem() αυτή περνάει τις όποιες παραμέτρους στο τμήμα Mem και στο τέλος δίνει ένα αντικείμενο για επιστροφή. Ακόμα και αν δεν έχουμε το τμήμα Mem, θα γυρίσει αντικείμενο. Ο κατασκευαστής είναι προαιρετικός. Δεν υπάρχει ειδικός αποδομητής (deconstructor).  Μπορεί κανείς να ορίσει μηδενικό μέγεθος πίνακα, άρα να τον σβήσει, κρατώντας το όνομα για χειρισμό μετά.

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

Στη Μ2000 δεν υπάρχει αναγνωριστικό ιδιαίτερης ομάδας, ή αντικειμένου. Αν θέλει κανείς κάτι τέτοιο μπορεί να κάνει κάτι μόνος του, δηλαδή να βάλει σε κάθε αντικείμενο μια συνάρτηση που να γυρνάει το τύπο ή μια μεταβλητή. Μόνο οι βασικοί τύποι αναγνωρίζονται στη Μ2000, όπως double (και το Α% που παίρνει ακέραια τιμή είναι double), string, group, long και document. (και COM αντικείμενα που δύναται να χειριστούμε, και δεν θα επεκταθώ, δείτε εδώ). Το Document δεν δίνει πίνακες, αλλά μπορεί να αλλάξει ένα στοιχείο σε πίνακα αλφαριθμητικών (ένα κάθε φορά). Το Long αλλάζει απλή μεταβλητή σε Long για να χρησιμοποιηθεί σε κλήσεις εξωτερικών ρουτινών (dll).




Class Mem {
      Dim d()
      MaxItem
      Module Mem {
            If Match("N") Then {Read N} Else N=10
            If Match("G") Then {Read G} Else Group G { Null }
            Dim .d(N+1)=G
            .MaxItem<=N
      }
      Module Resize {
            If Match("N") Then {Read N} Else N=10
            If Match("G") Then {Read G} Else Group G { Null }
            NewItems= N-.Maxitem
            Dim .d(N+1)
            If NewItems>0 Then Stock .d(.MaxItem +1) Sweep NewItems , G
            .MaxItem<=N
      }
      Module ResetRange {
            Read FromHere,ToThere, G
            stock .d(FromHere) Sweep ToThere-Fromhere+1, G
      }
}
Class D3 {
      x,y,z
      Module D3 {
            If Match("NNN") Then Read .x, .y, .z
      }
}
Mx=100
M=Mem(Mx,D3())
For I=0 to Mx : Gosub GetD3(I,10*I,20,30) : Next I
For M.d(50) {
      Print .x, .y, .z
}
Mx*=2
M.Resize Mx, D3()


Print Type$(M.d(150)) \\ Group  
For I=Mx div 2+1 to Mx: Gosub GetD3(I,10*I,20,30) : Next I
For M.d(150) {
      Print .x, .y, .z
}
M.ResetRange 0, 19, D3(10,20,30)
For M.d(15) {
      Print .x, .y, .z
}
MM=Mem(100,Mem(D3(10,20,30)))
Print MM.d(10).maxitem \10
\\ we have 100 Mem() with 10 items each
Print MM.d(10).d(2).z \ 30
MM.d(10).ResetRange 1, 10, D3(100,100,100)
Print MM.d(10).d(2).z \ 100
MM.d(4).Resize 20, D3(10,20,30)
Print MM.d(4).d(12).z
For MM.d(10), MM.d(0) {
       ..d() =.d() ' copy all elements
}
Print MM.d(0).d(2).z \ 100
For MM {
      .d(1)=.d(10) ' the same for all elements of group inside array item
}
Print MM.d(1).d(2).z \ 100
For MM {
      Swap .d(1),.d(3) ' Swap objects
}
Print MM.d(1).d(2).z \ 30  
Print MM.d(3).d(2).z \ 100
\******************************/
KK=MM ' this is a copy - KK has a copy of 100 objects with an array each, with an object of that array
KK.resize MM.Maxitem div 2
\*************************/
For MM {
      .d(1).d(2).z+=10
      .d(3).d(2).z+=10
      Print .d(1).d(2).z \ 40
      Print .d(3).d(2).z \ 110
}
For KK {
      Print .d(1).d(2).z \ 30  
      Print .d(3).d(2).z \ 100
      Print .maxitem \50
}
End
Sub GetD3(where, x,y,z)
      For M.d(where) {
            .x=x
            .y=y
            .z=z
      }
End Sub