A new revision uploaded see github.
There are two different aspects for types: Those types on variables, and those types on parameters. You may thing that a parameter is like a variable. Indeed a parameter is a variable, but these, parameter and variable, have something not common, the type. A variable declared somewhere in the program and maybe passed as an argument for a function, module, or a subroutine, by default using the By Value pass. So the parameter of a function, module or subroutine, get the value of the argument, but what about the type?
A parameter get the value from a stack of values. An argument written to the stack of values, we can say the current stack. The argument get the value from an expression (this is the By Value pass), so passing only a variable is like passing the result of an expression with only a variable. For M2000 there are two major expressions: Numeric and Alphanumeric (String Expression). Boolean expressions consider Numeric (0 for false non zero for true).
For a function parameter, interpreter see the name of the parameter, and if ends to $, then expect to find string value in stack else an error raised. So according to major types, numeric and string we have a first check, before checking the value.
For a function a(x,y) we can't pass strings as arguments. Although we can do this a="11234.5" and the interpreter do that a=Val("11234.5"), and pass the value 11234.5 to a, we can't pass the "11345.5" where we expect to get a numeric value.
How many numeric types used in M2000?
We can use integer, long, simple, double, currency, decimal and boolean (exist as type, and that type returns a comparison)
How we can force a type for a variable?
By default 1 is a double literal number, is same like 1.0. A statement like A=10 when A not defined as local previous in the module, make A as double type and this can't change with assigning an new value. So A=10& give to A a double type 10 and not the long type 10&, if A has type double.
We can use Def statement to define types for variables before the first assignment.
Def integer K=100, L=4
make K and L integer type (16bit) with values 100% and 4% (% used for integer literal numbers). M2000 check overflow for variables and return error.
If the Def find K or L isn't new names (in local scope) then an error raised. Def defines variables always local and not exist before as local. We can't use Def to shadowing variables.
We can use this form also:
Def K as integer=100, L as integer=4
In a subroutine we can't use Def because we want something else for shadowing a local variable with a new one with same name.
Local K=100%, L=4%
or
Local K as integer=100, L as integer=4
Every time we use Local from above a new set of K and L shadowing any K and L (if any K and L exist before as local variables, or global variables too). So when we call a subroutine, we have same scope as the caller, but we can use Local variables, and at the exit from routine any variable we define erased, so any K or L which we shadow are available to the caller. Local also define local arrays too
We don't use Local in the main body of a Module or Function (except for simple functions which are like subroutines, with the code written at the end of module's code), because these define a new NameSpace, and any new variable/definition by default is Local. We can use Global to make at some point a global variable or array, and the life for that is the same as for local variables.
Parameter Types
Lets see the program bellow. Function A need two arguments, and the parameter list has two, the x and z, one of them is Long type (32 bit) and the other is Integer (16 bit). So what we get; It depends. Here we pass 2 and 3 (double type) which convert to long and integer, and then we have the return value as the multiplication of those two. We read the type from the variable M. The M variable is new variable so the type for it is the type of the return value from function, and here is Long (long*Integer return long or error). The second try, we pass a big value 300000 which can't fit to Integer and we get Overflow error.
Function Alfa(x as long, z as integer) {
=x*z
}
M=Alfa(2, 3)
Print type$(M)="Long"
try ok {
M=Alfa(2, 300000)
}
Print Error$=" Overflow in function ALFA()"
Now we change the example. We remove the types from the function signature and we make a SayType module. We want that module, because we use M only for the call, and at the end of module's run the M erased, so next time can be another type. So We pass to Alfa() numeric literals. The first two have double type, the next two have Currency type, and the last two have Decimal type.
Use 2~, 3~ for single type (4byte float).
Module SayType (M) {
Print type$(M)
Print M
}
Function Alfa(x, z) {
=x*z
}
SayType Alfa(2, 3)
SayType Alfa(2, 300000)
SayType Alfa(2#, 3#)
SayType Alfa(2#, 300000#)
SayType Alfa(2@, 3@)
SayType Alfa(2@, 300000@)
Hexadecimal values are two types: 0xFFFF (65535) and 0xFFFFFFFF (4294967295) are currency type (map to unsigned), 0xFFFF% is Integer signed (-1) and 0xFFFFFFFFF& is long signed (-1). So there is no type unsigned long, but we can use a double, or decimal or a currency type. The Binary.And() and other functions return Currency type but they work on 32bit unsinged long. The Binary.add() has no overflow, the overflow bit just not used,
So now we know that using types make functions to have problems with overflow. This isn't bad if we know what to do. Because the M2000 Environment (Interpreter plus internal objects) written for education and playing by programming for kids and pupils, using only the major types Numeric and String we can make the life easier.
There are three type of identifiers for variables. like A for numeric (and pointers to objects), like A$ for strings and some kind of objects (including Document), and like A% for numeric with integer value (we may have a double type under the hood, but the value is always integer). This third major type is like numeric but there is a rounding process like the school rounding method, at the half integer value. All of these prints True.
A%=2.6
Print A%=3
A%=1.6
Print A%=2
A%=-1.6
Print A%=-2
A%=-2.6
Print A%=-3
If we use A=A/(A*2), we get 1 not 0.5
for i=1 to 10And now we check these two programs which give different results:
A%=i: A%/=i*2: Print A%=1
next
A%=100
Do
Print A%,
A%/=2
When A%>1
Print A%
A=100&
Do
Print A,
A/=2
When A>1
Print A
There is one problem with DIM statement. This statement can define arrays and can redim arrays (change the definition for an identifier for array which exist). If we have a global array say A(10) from 0 to 9, and we have a module with the statement DIM A(100) we change the global array. To prevent this if we know about the global array, or we want the module to included in a library, we use the DIM NEW A(100) which make always a new local identifier (shadowing any other local or global with the same name. If we have to redim the local we use DIM A(50), the A() is the local one. If we want to redim the global one we use SET DIM A() where the SET change for that line the Namespace to global namespace so A() is the global array. Statement GLOBAL A(50) always make a new identifier for global namespace, and LOCAL A(50) make a new identifier for local namespace. Global and Local can't redim arrays.
If the global A() exist and we have a parameter A() there will be no problem, because the READ statement (this used for reading from stack of values) always use the current namespace to create new identifiers, so the Read A() in a function or in a module make a new local array A().
global a(10)=1000
Print len(a())=10
Module beta {
// we change the global one
let a()=(1,2,3,4)
Print len(a())=4
}
beta
Print len(a())=4
dim a(100)=1
Module beta2(a()) {
// a() is local
Print len(a())=7
let a()=(1,2,3,4)
Print len(a())=4
}
beta2 (1,2,3,4,5,6,7)
Print len(a())=100
Module beta3 {
// a() is local
Push a() // this a() is global
read a() // this a() is local
dim a(4) // redim to 4 items
Print len(a())=4
}
beta3
Print len(a())=100
You can skip the next paragraph, which contain things about array names, pointer interfaces, passing by reference arrays, variables and array items.
class alfa {
private:
k=100
value (n){
=.k*n
}
set {
read .k
}
}
dim a(10)=alfa()
Print a(3)(3)=300
a(3)=20
Print a(3)(3)=60
m=group(a(3))
Print m(3)
z=pointer(a(3))
Print eval(z, 3)=60
a(3)=1000
Print eval(z, 3)=3000
z=pointer(m)
Print eval(z, 3)=60
Dim L(10)
L(0)=lambda x=0 ->{
x++
=x
}
L(1)=L(0)
L(2)=L(1)
Print L(1)()=1, L(1)()=2
L(3)=L(1)
Print L(2)()=1, L(3)()=3, L(1)()=3
L(1)=L(0)
Print L(1)()=1, L(1)()=2
m=L(0)
Dim L(10)=m()
Print L() ' print 1 2 3 4 5 6 7 8 9 10
Dim L(10)<<m()
Print L() ' print 2 3 4 5 6 7 8 9 10 11
Print m()=12
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.