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

Έκδοση 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