Κυριακή, 21 Ιανουαρίου 2018

Αναθεώρηση 40 (Έκδοση 9.0)

Δυο αλλαγές έγιναν σε αυτή την αναθεώρηση:

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

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


Πέμπτη, 18 Ιανουαρίου 2018

Αναθεώρηση 39 (Έκδοση 9.0)

Αλλαγές-Βελτιώσεις:
1) Βελτίωση στο αναδυόμενου μενού επιλογών στον διορθωτή και στο στοιχείο ελέγχου Κείμενο (EditBox). Σε περίπτωση που ανοίγουμε το μενού στην κάτω ή και στην δεξιά πλευρά της οθόνης, τότε έρχεται πιο μέσα το μενού για να φαίνεται (δούλευε ο κώδικας αλλά είχε ένα λάθος και δεν έρχονταν αρκετά πιο μέσα το μενού).

2) Τα μενού στις φόρμες χρήστη κλείνουν αν επιλέξουμε μια άλλη εφαρμογή/εικονίδιο στην επιφάνεια εργασίας, με το ποντίκι ή με το ALT+TAB (πριν έκλειναν μόνο αν επιλέγαμε κάτι άλλο από τις φόρμες της εφαρμογής αλλά όχι από αλλαγή εφαρμογής). Επίσης και το αναδυόμενο μενού επιλογών, λειτουργεί έτσι, καθώς και δικές μας φόρμες που τις ανοίγουμε σαν αναδυόμενο μενού, δηλαδή με έξοδο αν χάσει την εστίαση. Παραμένει να μην κλείνει η λίστα επιλογών που βγαίνει με το Μενού (υπάρχει λόγος), στην κονσόλα, αν αλλάξουμε εφαρμογή, ενώ το ίδιο συμβαίνει και στην φόρμα Ρυθμίσεις.
Δικές μας φόρμες μπορούμε να ανοίγουμε ως "modal" (γίνονταν) αλλά τώρα μπορούμε να ορίσουμε το πώς θα συμπεριφέρεται το σύστημα σε περίπτωση που χαθεί η εστίαση από τη φόρμα, βάζοντας Αληθές ή Ψευδές σε δυο ιδιότητες της φόρμας, το "IamPopUp" και το "PopUpMenuVal". Το πρώτο με Αληθές και το δεύτερο με Ψευδές κλείνει η φόρμα μόνο αν επιλέξουμε κάτι άλλο από την εφαρμογή μας. Με το δεύτερο αληθές τότε κλείνει η φόρμα και όταν επιλέξουμε μια άλλη εφαρμογή.
(Στην Μ2000 οι φόρμες "κλείνουν" χωρίς να "διαγραφούν", μέχρι να το κάνουμε μέσω κώδικα, με την Όρισε, να ορίσουμε το όνομα της φόρμας να είναι Τίποτα, ή να αφήσουμε να γίνει αυτόματα με το τερματισμό του τμήματος που δημιούργησε τη φόρμα).

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

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


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


Αν έχουμε νήματα στο ίδιο τμήμα με τις συναρτήσεις εξυπηρέτησης, δεν έχουμε πρόβλημα "σύγκρουσης", επειδή τα γεγονότα "μπαίνουν" σφήνα σε οποιοδήποτε κώδικα, εκτελούνται, και μετά ο κώδικας συνεχίζει. Και τα νήματα δουλεύουν με εξωτερικό γεγονός, έναν χρονιστή του User32 (βιβλιοθήκη ρουτινών συστήματος), με τις SetTimer και KillTimer. Και τα νήματα, και οι συναρτήσεις εξυπηρέτησης τρέχουν σε δικά τους αντικείμενα εκτέλεσης, αλλά "βλέπουν" τις μεταβλητές του τμήματος (σαν να είναι κώδικας στο τμήμα) εκείνου στο οποίο τα μεν νήματα δημιουργήθηκαν, και για τις συναρτήσεις εξυπηρέτησης εκεί όπου τα αντικείμενα του γραφικού περιβάλλοντος δημιουργήθηκαν (είναι ουσιαστικά μεταβλητές του τμήματος). Στα νήματα δημιουργούμε στατικές μεταβλητές (για όσο το νήμα υπάρχει), και χρησιμοποιούμε τον ιδιωτικό σωρό τιμών, για να κρατάμε κατάσταση, ή μέσω αυτών να χρησιμοποιούμε αντικείμενα του τμήματος (στα νήματα αν δημιουργήσουμε κάτι, μένει στο τμήμα. Στις συναρτήσεις εξυπηρέτησης μπορούμε να δημιουργήσουμε μεταβλητές με την εντολή Τοπικό ή Τοπική ή Τοπικές, ώστε να "σκιάσουν" τυχόν τοπικές του τμήματος με το ίδιο όνομα, ή τοπική άλλου γεγονότος που ακόμα δεν ικανοποιήθηκε πλήρως. Όπως και να έχει το πράγμα, εκτελείται κώδικας από ένα σημείο! Οπότε πρώτα θα τερματίσει η πιο πρόσφατη συνάρτηση εξυπηρέτησης, μετά η αμέσως προηγούμενη, μετά τα νήματα, και τέλος ο κώδικας, του τμήματος, Μπορεί ένα νήμα να έχει "μπλοκαριστεί", για παράδειγμα να ζητάει εισαγωγή αριθμού. Τα νήματα "θυμούνται" το επίπεδο που εξάγουν γράμματα και γραφικά. Κάθε φόρμα έχει και αυτή Επίπεδο για γραφικά και κείμενο όπως η κονσόλα. Οι εντολές εισαγωγής δεν λειτουργούν στις φόρμες χρήστη. Εκεί για εισαγωγή χρησιμοποιούμε τα στοιχεία ελέχγου. Η κονσόλα έχει επιπλέον 32 επίπεδα (Χρησιμοποιούνται και ως "παίκτες" για παιχνίδια), καθώς και άλλα δυο, ένα το Περιθώριο πίσω από την οθόνη (το βασικό επίπεδο), και ένα μη φανερό, τη σελίδα του επιλεγμένου εκτυπωτή.

Στη Μ2000 εκτός από τα γεγονότα που παράγονται από το γραφικό περιβάλλον έχουμε άλλα δυο είδη, το αντικείμενο Γεγονός και τον ορισμό αντικειμένων COM με γεγονότα. Το αντικείμενο γεγονός που το φτιάχνουμε ως λίστα συναρτήσεων (μπορούν να είναι και συναρτήσεις αντικειμένων), ώστε να στέλνουμε με μια εντολή Κάλεσε Γεγονός σε ένα γεγονός τιμές (και με αναφορά αν θέλουμε) χωρίς να μας νοιάζει αν θα εξυπηρετηθούν, με το "γέμισμα" με συναρτήσεις να γίνεται με έλεγχο, με προσθήκη και με αφαίρεση καθώς και με αδρανοποίηση του αντικειμένουν όταν χρειαστεί (να μην λειτουργεί χωρίς να αφαιρέσουμε τις συναρτήσεις). Τέλος και σε εξωτερικά αντικείμενα τύπου COM, μπορούμε να χειριστούμε γεγονότα. Πχ μπορούμε να ξεκινήσουμε τον επεξεργαστή κειμένου Word και να παίρνουμε αντικείμενα με έλεγχο γεγονότων κατ΄απαίτηση. Οι συναρτήσεις εξυπηρέτησης για COM αντικείμενα έχουν το όνομα της μεταβλητής που δείχνει στο αντικείμενο, μετά ακολουθεί κάτω παύλα και μετά το όνομα του γεγονότος.  Οφείλουμε να έχουμε με μια Διάβασε Νέο (νέο ώστε αν ήδη υπάρχει το όνομα της μεταβλητής να βγει μια φορά ακόμα, και μέχρι να τερματίσει το γεγονός). Στην Μ2000 οι μεταβλητές (εκτός από τις στατικές) μπορούν να ορίζονται ξανά, σκιάζοντας τις υπάρχουσες, και διαγράφονται με τον ανάποδο τρόπο από αυτόν που ορίστηκαν, με το πέρας του τμήματος/συνάρτησης/ρουτίνας/ μπλοκ προσωρινών ορισμών, που τα όρισε. Οι στατικές μεταβληρές (χωρίς ονόματα με παρενθέσεις, απλές μεταβλητές, και δείκτες σε αντικείμενα) ανήκουν στο αντικείμενο εκτέλεσης και έχουν δικό τους κατάλογο με συνάρτηση κατακερματισμού. Ενώ οι μεταβλητές ανήκουν σε ένα γενικό "κατάλογο" που λειτουργεί με συνάρτηση κατακερματισμού. Τις μεταβλητές μπορούμε να τις περάσουμε με αναφορά, επειδή ανήκουν σε αυτήν την γενική λίστα. Μια μεταβλητή που είναι αναφορά άλλης έχει στην ουσία μια δική της θέση στο κατάλογο, αλλά έχει ένα δείκτη στο ίδιο στοιχείο που δείχνει η "Αρχική". Η διαφορά σε κάθε αναφορά είναι ότι υπάρχει μια σημαία που λέει "είμαι αναφορά". Μια αναφορά δεν μπορεί να πάρει νέα αναφορά. Και στη διαγραφή μεταβλητών, το σύστημα χρησιμοποιεί τις σημαίες για να μην "μηδενίσει" την μνήμη τους (που στην ουσία είναι αυτή της αρχικής, αναφερόμενης τιμής)



Δευτέρα, 15 Ιανουαρίου 2018

Example of using Class and SuperClass in M2000

From http://nilhcem.com/swift-is-like-kotlin/ I get the idea to make a same example as those for Subclass, in Kotlin and in Swift.

In first example we make two classes (functions which return a Group object). These are globals by default (and local if we define a class in a group/class). The second class make a group using first as the base. We get one group only. No reference exist from first to second. This done by merging using This<=NameShape(name$), in constructor. Also in constructor we replace simpleDescription, using a new Group, with same module name (modules are functions which not used in expressions, and also has the idiom of using parent stack value, and return this at exit, so modules can read not only the arguments we pass but all stack of values, and can pass back results if we want, in any number and kind, it is in caller responsibility to take these from stack of values). A class constructor is a module because when we call the function, first make the group as we define it, and then call constructor (if exist) passing only the stack of values. Functions always called in expressions with a new stack of values, and at return stack is desroyed, and any remain value dropped too. So we can make class without constractor.

This class has no constructor. We can pass values to a and b reading stack of values.
Class Look {
      a=number, b=number
}
N=Look(1,2)
Print N.a, N.b


A module with same name as the class name, inside class definition can be used as constructor, and has an idiom, after exit of module anything we make stays in class function (parent of module).
So in this example every change to This (the group which return from class function) in module Square exist after the exit of module and the expanded group returned from function.


Example 1


Class NameShape {
      name$, numberOfSides
      Module simpleDescription {
            Print format$("A shape with {0} sides.", .numberOfSides)
      }
Class:
      Module NameShape ( .name$) {}
}
Class Square {
      sideLength
      Function area {=.sideLength^2}
Class:
      Module Square (.sideLength, name$) {
           This<=NameShape(name$)
           Group Any {
                  Module simpleDescription {
                        Print format$("A square with sides of length {0}.", .sideLength)
                  }            
           }
           This<=Any
      }
}
testobj=Square(5.2, "square")
Print testobj.area()
testobj.SimpleDescription



The second example use a SuperClass, and we make a Square class which use this superclass. All objects from same superclass (not just same blueprint, but same instance) use Superclass to store/read unique values, or default values. A SuperClass is not a function. Intepreter make a Group with no members and put a reference to a closed group, the actual superclass. Any merging with a superclass put a reference to the actual superclass.
Because groups are not reference types, there is no way to have reference to each other, and superclass can't reference to other superclass (we just change reference if we assign to it another souperclass), like a chain of references. When all groups deleted which hold alive superclass then superclass deleted too. There are no deconstructors in M2000. So if we have to use one we have to explicity use one, a module or function to "prepare" any state change.

Example 2


\\ In M2000 we can't stack SuperClasses. Every group can have one or no supercalss. Inner groups may have different superclass, thus it is possible to have a group with more than one superclass, using as holders, inner groups.

\\ Groups are values, but SuperClass is referenced to group, so we can make a number of groups with same reference to a Superclass.

\\ Also note that a SuperClass defintion is Group Defintion, not a Class definition. So has no constructor.

\\ A Class is a function which return a group, and before returned, call the constructor passing any argument, passing in the call

\\ In M2000 calling a user function can be done with any number and kind of argument, because interpreter didn't check, and put anything to a private stack of values. The callee function can read arguments, to variable or in expressions just popping from stack of values, in any line of code, not only as first line. In this context can be raise error, if we read something not in stack, not same type or in empty stack. We can check before we read, and we can use optinal readings, so an empty stack is "optional". We can call with ? as parameter to say "use default" if we read an optional value

SuperClass NameShape {
unique:
      counter
public:
      name$="point", numberOfSides
      Module IncCounter {
            For SuperClass {
                  .counter++
            }     
      }
      Function Counter {
            For SuperClass {
                  =.counter
            }
      }
      Function DefaultName$ {
            For SuperClass {
                  =.name$
            }
      }
      Function simpleDescription$ {
            \\ get a copy of This, in Me
            Me=This
            Read ? Me ' merge argument if exist
            \\ so without argument we get the intial values
            =format$("A shape with {0} sides.", me.numberOfSides)
      }
}
Class Square {
      sideLength
      Function area {=.sideLength^2}
      Function Super.SimpleDescription$ {
            \\ we can use any name, and any dots, but here we place Super.
            For SuperClass {
                  =.SimpleDescription$(This)
            }
      }
Class:
      \\ (This, .sideLength, .name$) change to Read This, .sideLength, .name$
      \\ This is the current group so reading a defined group is a merging function
      \\ becuase we pass a Superclass, we make this group to get a reference to superclass
      Module Square (This, .sideLength, .name$) {
           .IncCounter
           .numberOfSides<= 4
           Group Any {
                  Function simpleDescription$ {
                        =format$("A square with sides of length {0}.", .sideLength)
                  }            
           }
           This<=Any
      }
}
MyNameShape=Lambda NameShape -> {
      M=NameShape
      M.IncCounter
      Read ? M.name$
      =M
}
\\ we can use a lambda function with a closure as a SuperClass
\\ and also for increment counter
test0=MyNameShape("My Point")
\\ we can use superclass as is
test1=NameShape
\\ but we have to adjust counter
test1.IncCounter
Print test1.SimpleDescription$()
Print test1.SimpleDescription$(?) \\ ? = use optional
Print test1.name$ 'point
testobj=Square(NameShape, 5.2, "square")
Print testobj.SimpleDescription$()
Print "area=";testobj.area()
Print testobj.Super.SimpleDescription$()
Print "NameShape name is ";testobj.name$
Print test1.SimpleDescription$(testobj) \\ now we pass another object to test1.
Print test1.DefaultName$()
Print Valid(@test1 as test0) \\ -1  : has same superclass
Print Valid(@testobj as test0) \\ -1 : has same superclass

Group ChangeDefaultName$ {
      Value {} \\ return "", because group has $ in name
      Set {
             For SuperClass {
                  Read .name$
             }
      }
}
\\ A group with $ in name return a string, and has a second name to access members without $.
\\ We can link a superclass after the Group definition
\\ Because we have a Set function, we use Let, which do this: Push NameShape : Read ChangeDefaultName
\\ reading a Group and merging to Group.
Let ChangeDefaultName=NameShape
ChangeDefaultName$="a new point"
\\ here we use second name without $
\\ Because this is an error for intepreter ChangeDefaultName$.DefaultName$()
Print ChangeDefaultName.DefaultName$()
Print test1.DefaultName$()
\\ $. used for a string before a name as a weak reference
a$="ChangeDefaultName"
Print eval$(a$.SimpleDescription$())
\\ or
a$=Weak$(ChangeDefaultName)
Print eval$(a$.SimpleDescription$())
a$=Weak$(ChangeDefaultName$) ' now a$ has $ inside
a$. = "another point"
Print ChangeDefaultName.DefaultName$() \\ another point
\\ change in any object made from same superclass
Print testobj.DefaultName$() \\ another point
Print test1.DefaultName$() \\ another point
Print test1.Name$ \\ point
Print test1.Counter() \\ 3 objects

Σάββατο, 13 Ιανουαρίου 2018

Αναθεώρηση 38 (Έκδοση 9.0) και νέο Range Object με SubRanges

Στην αναθεώρηση αυτή βρήκα (φτιάχνοντας το Range Object) ένα λάθος στην Compare() όπου υπήρχε περίπτωση να δώσουμε αρνητικό αριθμό και το μηδέν και να πάρουμε ότι ο αρνητικός είναι μεγαλύτερος! Φτιάχτηκε!

Παρακάτω είναι το νέο Range Object το οποίο δουλεύει με SubRanges, δηλαδή ορίζουμε υποπεριοχές, με συνάρτηση που δείχνει πως πάμε από την αρχή ως το τέλος κάθε περιοχής.

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

Κλάση Περιοχή {
Ιδιωτικό:
      Πίνακας ΥπόΠερ1()
      από$, έως$, πρώτο=Αληθές
      απόαριθμό, σεαριθμό, υποπεριοχή=0
      τύπος_περιοχής=0
      Συνάρτηση Έρευνα (κ$) {
             αντίγραφο1=Αυτό
             αντίγραφο1.Μηδένισε
             Ενώ αντίγραφο1 {
                  Αν κ$=αντίγραφο1.Αξία$ Τότε =Αληθές : Έξοδος
            }
      }
      Συνάρτηση ΈρευναΑριθμού (κ) {
             αντίγραφο1=Αυτό
             αντίγραφο1.Μηδένισε
             Ενώ αντίγραφο1 {
                  Αν κ=αντίγραφο1.αξ Τότε =Αληθές : Έξοδος
            }
      }
      ΕπόμενοΒήμα$=Λάμδα$ ->{Λάθος 500}
      ΕπόμενοΒήμαΑριθμ=Λάμδα ->{Λάθος 500}
Δημόσιο:
      Συνάρτηση Έχει {
                        Αν .τύπος_περιοχής=1 Τότε {
                        Διάβασε τι$
                        Διάβασε ? ΣυνάρτησηΧρήστη
                        Αν ΣυνάρτησηΧρήστη Τότε =.Έρευνα(τι$) : Έξοδος
                        υποπεριοχή=1
                        Επανέλαβε {
                              Στοκ .ΥποΠερ1(υποπεριοχή) σε από$, έως$
                              Αν τι$<>"" Τότε {
                                 Αν από$<=έως$ Τότε {
                                           ν=τι$>=από$ Και τι$<=έως$
                                    } Αλλιώς {
                                          ν=τι$>=έως$ Και τι$<=από$
                                    }
                              }
                              υποπεριοχή+=4
                        } Μέχρι υποπεριοχή>=Μήκος(.ΥποΠερ1()) Ή ν
                        =ν
                  } Αλλιώς {
                        Διάβασε τι
                        Διάβασε ? ΣυνάρτησηΧρήστη
                        Αν ΣυνάρτησηΧρήστη Τότε =.ΈρευναΑριθμού(τι) : Έξοδος
                        υποπεριοχή=1
                        Επανέλαβε {
                              Στοκ .ΥποΠερ1(υποπεριοχή) σε απόαριθμό, σεαριθμό ' these are locals too                        
                              Αν απόαριθμό<=σεαριθμό Τότε {
                                    ν=τι>=απόαριθμό Και τι<=σεαριθμό
                              } Αλλιώς {
                                    ν=τι>=σεαριθμό Και τι<=απόαριθμό
                              }
                        υποπεριοχή+=4
                        } Μέχρι υποπεριοχή>=Μήκος(.ΥποΠερ1()) Ή ν
                        =ν
                  }
      }
      Ιδιότητα Αξία$ { Αξία }
      Ιδιότητα Αξ { Αξία }
      Τμήμα Πήδα (κ){
            κ=Απολ(κ)
            Αν κ Αλλιώς Έξοδος
            Ένωσε Αυτό στο μ1
            Ενώ κ {
                  κ--
                  Αν μ1 Αλλιώς Έξοδος
            }
      }
      Τμήμα Μηδένισε {
            .υποπεριοχή<=0
            Αν Μήκος(.ΥποΠερ1())>1 Τότε {
                  Στοκ .ΥποΠερ1(.υποπεριοχή) σε .τύπος_περιοχής
                  Επίλεξε Με .τύπος_περιοχής
                  Με 1
                        {
                              Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .από$, .έως$, .ΕπόμενοΒήμα$
                              .[Αξία]$<=.από$
                        }
                  Αλλιώς
                        {
                              Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                              .[Αξ]<=.απόαριθμό
                        }
                  Τέλος Επιλογής
            }       
            .πρώτο<=Αληθές
      }
      Αξία {
            ν=Ψευδές
            Αν .τύπος_περιοχής=1 Τότε {
                             Δες {
                                    μ$=.ΕπόμενοΒήμα$(.[Αξία]$)
                                    Αν Λάθος Τότε Έξοδος
                                    Αν .πρώτο Τότε .πρώτο~ : =Αληθές : Έξοδος
                                    Αν Απολ(Σύγκρινε(μ$, .έως$)+Σύγκρινε(.από$, .έως$))=0 Τότε ν~ : Έξοδος
                                    .[Αξία]$<=μ$
                                    =Αληθές
                                   }
            } Αλλιώς {
           
                       Δες {
                             μ=.ΕπόμενοΒήμαΑριθμ(.[Αξ])
                              Αν Λάθος Τότε Έξοδος
                              Αν .πρώτο Τότε .πρώτο~ : =Αληθές : Έξοδος
                              Αν Απολ(Σύγκρινε(μ, .σεαριθμό)+Σύγκρινε(.απόαριθμό, .σεαριθμό))=0 Τότε ν~ : Έξοδος
                              .[Αξ]<=μ
                              =Αληθές
                        }                  
            }
            Αν ν Αλλιώς Έξοδος
            .υποπεριοχή+=4
            Αν .υποπεριοχή>=Μήκος(.ΥποΠερ1()) Τότε Έξοδος
            Στοκ .ΥποΠερ1(.υποπεριοχή) σε .τύπος_περιοχής
            Επίλεξε Με .τύπος_περιοχής
            Με 1
                  {
                        Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .από$, .έως$, .ΕπόμενοΒήμα$
                        .[Αξία]$<=.από$
                  }
            Αλλιώς
                  {
                        Στοκ .ΥποΠερ1(.υποπεριοχή+1) σε .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                         .[Αξ]<=.απόαριθμό
                  }
            Τέλος Επιλογής
            .πρώτο<=Ψευδές
            =Αληθές
      }
      Κλάση:
      Τμήμα Περιοχή {
            Ενώ Όχι Κενό {
                   Αν Ταύτιση("SS") Και Όχι .τύπος_περιοχής=2 Τότε {
                        .τύπος_περιοχής<=1
                        Διάβασε .από$, .έως$
                        Αν Ταύτιση("F") Τότε Διάβασε .ΕπόμενοΒήμα$
                        .[Αξία]$<=.από$
                  } Αλλιώς.Αν Ταύτιση("NN") Και Όχι .τύπος_περιοχής=1 Τότε {
                       Διάβασε .απόαριθμό, .σεαριθμό
                       .τύπος_περιοχής<=2
                       Αν Όχι Ταύτιση("F") Τότε {
                             .ΕπόμενοΒήμαΑριθμ<=Αν(.απόαριθμό<=.σεαριθμό -> (Λάμδα (χ) ->χ+1), (Λάμδα (χ) ->χ-1))
                        } Αλλιώς{
                                    Διάβασε .ΕπόμενοΒήμαΑριθμ
                        }
                        .[Αξ]<=.απόαριθμό
                 } Αλλιώς Λάθος "Δεν υποστηρίζονται οι τύποι στο σωρό:"+Φάκελος$()
                  Αν .τύπος_περιοχής<>0 Τότε {
                        που=Μήκος(.ΥποΠερ1())
                        Πίνακας Βάση 0, .ΥποΠερ1(που+4)
                        Επίλεξε Με .τύπος_περιοχής
                        Με 1
                              Στοκ .ΥποΠερ1(που) από .τύπος_περιοχής, .από$, .έως$, .ΕπόμενοΒήμα$
                        Αλλιώς
                              Στοκ .ΥποΠερ1(που) από .τύπος_περιοχής, .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                        Τέλος Επιλογής
                  }
            }
            Αν Μήκος(.ΥποΠερ1())>1 Τότε {
                  .τύπος_περιοχής<=.ΥποΠερ1(0)
                  Επίλεξε Με .τύπος_περιοχής
                  Με 1
                        {
                              Στοκ .ΥποΠερ1(1) σε .από$, .έως$, .ΕπόμενοΒήμα$
                              .[Αξία]$<=.από$
                        }
                  Αλλιώς
                        {
                              Στοκ .ΥποΠερ1(1) σε .απόαριθμό, .σεαριθμό, .ΕπόμενοΒήμαΑριθμ
                              .[Αξ]<=.απόαριθμό
                        }
                  Τέλος Επιλογής
            }
      }
}
ΕπόμενοςΧαρακτήρας$=Λάμδα$ (χ$) -> ΧαρΚωδ$(ΧαρΚωδ(χ$)+1)
ΠροηγούμενοςΧαρακτήρας$=Λάμδα$ (χ$) -> ΧαρΚωδ$(ΧαρΚωδ(χ$)-1)
μ=Περιοχή("A", "Z", ΕπόμενοςΧαρακτήρας$, "z", "a", ΠροηγούμενοςΧαρακτήρας$)
Τύπωσε Μ.Αξία$
Τύπωσε Μ.Έχει("A"), Μ.Έχει("z", Αληθές)
Ενώ μ {
      Τύπωσε μ.Αξία$;
}
Τύπωσε  "",,       \\ σπάει το ; και βάζει άλλη γραμμή
μ.Μηδένισε
Ενώ μ {
      Τύπωσε μ.Αξία$;
}
Τύπωσε  "",,       \\ σπάει το ; και βάζει άλλη γραμμή
μ1=Περιοχή(20, 1, 2, 20)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Τύπωσε Μ1.Έχει(500), Μ1.Έχει(15)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Στη μ1=Περιοχή(30, 20, 50, 60, 90, 100)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Στη μ1=Περιοχή(30, 20, Λάμδα (α)->α-2, 10,1)
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
      μ1.Πήδα 3
}
Τύπωσε
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Για μ1 {
      .Μηδένισε
      .Πήδα 2
}
Ενώ μ1 {
      Τύπωσε μ1.Αξ,
}
Τύπωσε
Κατάσταση κ=10,40,50,70,1000
Σετ1=Περιοχή( 0, Μήκος(κ)-1, Μήκος(κ)-2, 0)
Σετ2=Περιοχή(1, Μήκος(κ)-2, Μήκος(κ)-1, 1)
Ενώ Σετ1 {
      Τύπωσε κ(Σετ1.αξ!),
      Σετ1.Πήδα 1
}
Τύπωσε
\\  10 50 1000 50 10
Ενώ Σετ2 {
      Τύπωσε κ(Σετ2.αξ!),
      Σετ2.Πήδα 1 ' Πήδα
}
Τύπωσε
\\  40, 70, 70, 40

Μετρητής=Περιοχή("100", "110", Λάμδα$ (α$)->Γραφή$(Τιμή(α$)+2,"000"), "108", "100", Λάμδα$ (α$)->Γραφή$(Τιμή(α$)-2,"000"))
Τύπωσε Μετρητής.Έχει("108"), Μετρητής.Έχει("109", Αληθές), Μετρητής.Έχει("104", Αληθές) \\ Αληθές Ψευδές Αληθές
Ενώ Μετρητής {
      Τύπωσε Μετρητής.Αξία$,
}
Τύπωσε




\\ Multi Range object version 1
\\ Need revision 38, version 9.0 and up
\\ We can make a range with subranges.
\\ Constructor: Range( value_From, value_to [, lambda function] [,value_From, value_to [, lambda function]])
\\      For srtings we have to supply lambda function, for numbers we can skip lambda function and place number or close parenthesis.
\\      value types numbers or strings, lambda function must be the same type also
\\      lambda function produce the next item
\\  Properties
\\      Value$  : used if we have a range of strings
\\      Val : used if we have a range of numbers
\\ Function
\\      Has(string or number [, True]) : return True if in any sub range, object has value without check lambda function,
\\      if optional second argument is True then scan all values using lambda function. This is slow but accurate
\\ Method
\\      Reset
\\            reset val or value$ to match the first item of first subrange
\\      Skip number
\\            skip a number of items, and maybe change to new item, can change subrange too, or set state to false
\\            skip can used before using Value, see below, or in a while loop using Value.
\\ Value
\\      We use value of Range, value of object, as a state flag, and this call lambda for next item
\\            state False means object go out of range. Use Reset to begin again. Use Skip to skip some items.
\\            We use While RangeObj { } to walk through all items in all subranges

Class Range {
Private:
       \\ this is an array for store subranges, in each 4 items
       \\ we use Stock command to store a list of variables, and to read a list of variables too.
       \\ Arrays using Stock can used with any type. Here we store numbers, strings, lambda functions.
       \\ Stock statement has final form from revision 37, version 9.0
      Dim link1()
      from$, to$, begin=True
      fromnum, tonum, subrange=0
      option=0
      Function Inspect (k$) {
             copy1=This
             copy1.reset
             While copy1 {
                  if k$=copy1.value$ then =True : exit
            }
      }
      Function InspectNum (k) {
             copy1=This
             copy1.reset
             While copy1 {
                  if k=copy1.val then =True : exit
            }
      }
      NextStep$=Lambda$ ->{Error 500}
      NextStepNum=Lambda ->{Error 500}
Public:
      Function Has {
                        if .option = 1 Then {
                        Read what$
                        Read ? UseFunc ' optional
                        If UseFunc then =.Inspect(what$) : exit
                        subrange=1 ' this is local
                        Repeat {
                              Stock .Link1(subrange) out from$, to$ ' these are locals too
                              If what$<>"" Then {
                                 if from$<=to$ Then {
                                           v=what$>=from$ and what$<=to$
                                    } else {
                                          v=what$>=to$ and what$<=from$
                                    }
                              }
                              subrange+=4
                        } until subrange>=len(.Link1()) or v
                        =v
                  } Else {
                        Read what
                        Read ? UseFunc ' optional
                        If UseFunc then =.InspectNum(what) : exit
                        subrange=1
                        Repeat {
                              Stock .Link1(subrange) out fromnum, tonum ' these are locals too                        
                              If fromnum<=tonum then {
                                    v=what>=fromnum and what<=tonum
                              } else {
                                    v=what>=tonum and what<=fromnum
                              }
                        subrange+=4
                        } until subrange>=len(.Link1()) or v
                        =v
                  }
      }
      Property Value$ { Value }
      Property Val { Value }
      Module Skip (k){
            k=abs(k)
            if k Else Exit
            Link This to M1
            While k {
                  k--
                  If M1 Else Exit
            }
      }
      Module Reset {
            .subrange<=0
            If Len(.Link1())>1 then {
                  Stock .Link1(.subrange) out .option
                  Select Case .option
                  Case 1
                        {
                              Stock .Link1(.subrange+1) out .from$, .to$, .NextStep$
                              .[Value]$<=.from$
                        }
                  Else
                        {
                              Stock .Link1(.subrange+1) out .fromnum, .tonum, .NextStepNum
                              .[Val]<=.fromnum
                        }
                  End Select
            }       
            .begin<=True
      }
      Value {
            v=False
            If .option=1 Then {
                             Try {
                                    m$=.NextStep$(.[Value]$)
                                    if Error Then Exit
                                    if .begin Then .begin~ : =True : Exit
                                    If abs(compare(m$, .to$)+compare(.from$, .to$))=0 Then v~ : Exit
                                    .[Value]$<=m$
                                    =True
                                   }
            } Else {
                       Try {
                              m=.NextStepNum(.[Val])
                              if Error Then Exit
                              if .begin Then .begin~ : =True : Exit
                              If abs(compare(m, .tonum)+compare(.fromnum, .tonum))=0 Then v~ : Exit
                              .[Val]<=m
                              =True
                        }                  
            }
            if v Else Exit
            .subrange+=4
            if .subrange>=len(.Link1()) then exit
            Stock .Link1(.subrange) out .option
            Select Case .option
            Case 1
                  {
                        Stock .Link1(.subrange+1) out .from$, .to$, .NextStep$
                        .[value]$<=.from$
                  }
            Else
                  {
                        Stock .Link1(.subrange+1) out .fromnum, .tonum, .NextStepNum
                         .[val]<=.fromnum
                  }
            End Select
            .begin<=false
            =true
      }
      class:
      Module Range {
            While Not Empty {
                   If match("SS") and not .option=2 Then {
                        .option<=1
                        Read .from$, .to$
                        If match("F") Then Read .NextStep$
                        .[Value]$<=.from$
                  } Else.if match("NN") and not .option=1 Then {
                       Read .fromnum, .tonum
                       .option<=2
                       If Not match("F") Then {
                             .NextStepNum<=if(.fromnum<=.tonum -> (lambda (x) ->x+1), (lambda (x) ->x-1))
                        } Else{
                                    Read .NextStepNum
                        }
                        .[Val]<=.fromnum
                 } Else Error "not supported stack types:"+Envelope$()
                  if .option<>0 then {
                        where=len(.Link1())
                        Dim Base 0, .Link1(where+4)
                        Select Case .option
                        Case 1
                              Stock .Link1(where) in .option, .from$, .to$, .NextStep$
                        Else
                              Stock .Link1(where) in .option, .fromnum, .tonum, .NextStepNum
                        End Select
                  }
            }
            If Len(.Link1())>1 then {
                  .option<=.Link1(0)
                  Select Case .option
                  Case 1
                        {
                              Stock .Link1(1) out .from$, .to$, .NextStep$
                              .[Value]$<=.from$
                        }
                  Else
                        {
                              Stock .Link1(1) out .fromnum, .tonum, .NextStepNum
                              .[Val]<=.fromnum
                        }
                  End Select
            }
      }
}
NextChar$=lambda$ (x$) -> Chrcode$(Chrcode(x$)+1)
PrevChar$=lambda$ (x$) -> Chrcode$(Chrcode(x$)-1)
M=Range("A", "Z", NextChar$, "z", "a", PrevChar$)
Print M.Value$
Print M.Has("K"), M.Has("a", true)
While M {
      Print M.Value$;
}
Print  "",,       \\ break ; set next line using columns
M.Reset
While M {
      Print M.Value$;
}
Print  "",,       \\ break ; set next line using columns
M1=Range(20, 1, 2, 20)
While M1 {
      Print M1.val,
}
Print
Print M1.Has(500), M1.Has(15)
While M1 {
      Print M1.val,
}
Print
\\ using Let because M1 is a property now, and only LET can change it.
\\ Let a=b is same as Push b : Read a
let M1=Range(30, 20, 50, 60, 90, 100)
While M1 {
      Print M1.val,
}
Print
let M1=Range(30, 20, lambda (a)->a-2, 10,1)
While M1 {
      Print M1.val,
      M1.Skip 3
}
Print
\\ M1 is false now
While M1 {
      Print M1.val,
}
For M1 {
      .Reset
      .Skip 2 ' start from 3rd     
}
While M1 {
      Print M1.val,
}
Print
Inventory K=10,40,50,70,1000
Set1=Range( 0, Len(K)-1, Len(K)-2, 0)
Set2=Range(1, Len(K)-2, Len(K)-1, 1)
While Set1 {
      Print K(Set1.val!),   \\ using ! we pass index - from 0- not key
      Set1.Skip 1
}
Print
\\ we get 10 50 1000 50 10
While Set2 {
      Print K(Set2.val!),
      Set2.Skip 1 ' skip
}
Print
\\ we get 40, 70, 70, 40
\\ a lambda can be put in parenthesis, but not a lambda$.
Counter=Range("100", "110", lambda$ (a$)->Str$(val(a$)+2,"000"), "108", "100", lambda$ (a$)->Str$(val(a$)-2,"000"))
\\ using optional second argument as True (default false) we walk through all range using lambda function
Print Counter.Has("108"), Counter.Has("109", True), Counter.Has("104", True) \\ True false True
While Counter {
      Print Counter.Value$,
}
Print