CLIP home page
Extensions of language features
new statement "switch" - select 1 from M node
switch (expr)
case const1 [,const2 [,const3] ... ]
// statemetns
case const11 [, .... ]
// statements
otherwise
end
create new command "do switch","endswich" via "do case","endcase"
create new operation ":=@", reference assign:
a:="a"
b:=@a
? a,b // "a","a"
b:="b"
? a,b // "b","b"
b:=@NIL // remove reference
For an easy work with MAP and objects, the following cycle has been made:
(a detailed description of MAP and objects is given below)
FOR value IN map_var
? value
NEXT
will look through all elements in map_var and put them into
value;
or
FOR key_value IN map_var KEYS
? key, map_var[key]
NEXT
will look through all elements in map_var, and the key value will indicate
the key of access to current elements of MAP or object.
Macro may consist of more complex expressions than in CA-CLIPPER, including recursive
calls of macros. Practically all lexemes, exept commands and
operators like for, while, etc., are processed more accurately.
Rational numbers with unlimited accuracy!
Currently, it is able to do only simple mathematical
operations -+/*^% on large numbers.
To realize these possibilities, it's necessary to write somewhere in program
set(_SET_RATIONAL,.t.)
or via the command described in clip.ch
set rational on|off
The compiler does not support large numbers as constants, that is,
when using expressions like
x:=123456789012345678901234567890,
the compiler will make an attempt to transform this into double,
and only coprocessor knows what the result will be :)
To actually use large constants, it's necessary to use VAL()
function
x:=val("123456789012345678901234567890")
It's possible as follows:
x:=val("1234.567890")
x:=val("1/3")
STR(val,len,dec) function now supports len, dec parameters of any
value.
For example:
? str(val("7/3"),1000,990)
Also, RSTR(val) function is added, and this gives a string in the
form of
"numerator/denominator", i.e. this string can be put into
val(),
and at the same time there will be no accuracy loss during
transforming!
? rstr(val("7/3")+val("5/6")) // ---->>> "19/6"
Hash code is the number more than 1 000 000 000, as a result of hashing
a string to a number by using bit operations.
For strings of less than 20 characters, the probability of coincidence of
hash codes is approximately 1/1000000. For longer strings, the probability
is reduced.
The compiler accepts hexadecimal constants in the form of 0x20, 0x30.
Association arrays (AA) - to understand these, read about OO model.
For instance, an ordinary array may be written as follows
declare m[5]
m[1]=11; m[2]=12; ....
To get access to elements, a consecutive numbers set is used, and it is
limited with the array size. Inserting a new element becomes a problem,
and it results in time losses. Opposite to ordinary arrays, elements of
association arrays are identified by strings, for example:
m=map()
m:asdf=11; m:qwer=12
? valtype(m) // 'O' //object
? len(m) // 2
? m:qwer // 12
Actually, elements of association array are identified by a hash code
of string calculated during compile-time. The compiler calculates hash
codes of strings enclosed in "`" characters.
For example:
? m:qwer==m[`qwer`] // .t.
During run-time, hash code can be calculated ashashstr("QWER")
? m:qwer==m[hashstr("QWER")] // .t.
Pay attention to QWER which is written in capital letters, because
the compiler does not distinguishes letter cases.
It's possible to get a list of indexes in the associate array via
mapkeys(m) which returns the array with hash codes being in m array
mm=mapkeys(m)
(instead of mapkeys() function, a special cycle can be used - its
description is given above)
? len(mm) // 2
for i to len(mm)
? mm[i] //will return something like 1233345677, 124321423
next
Also, the associate array is characterized by a very fast access to
elements, as a necessary element is actually searched in a hash table.
And instead of ascan(mm,`QWER`), it's better to use
`QWER` $ m // -> .t.
OO model.
Firstly, some words about CA-Clipper built-in OO model.
Its OO is based on usual array, and any call like
obj:attribute or obj:method()
results in the situation when in obj array there is searching of an
element whose first element coincides with attribute or
method,
name, and such search is executed lineary and is practically analogues to
ascan(obj,{|x|x[1]=="attribut"}) function, which greatly
reduces
the efficiency of OO model of "pure" CA-Clipper. This, of course, is
rather a
simplified explanation, but the sense is still that as described.
We believe, now it's clear for what purpose association arrays were made.
OO model based on association arrays is faster by an order!
At the same time, there's no need in expressions like
obj:=tclass(class_name):new()
and in tclass class itself, which raises OO model efficiency by
several
times.
How could you make your own class? It's very simple:
function MyClassNew()
obj:=map() // empty object
clone(MyClass2New(),obj) // adoption of MyClass2 structure
clone(MyClass3New(),obj) // adoption of MyClass3 structure
// if there are coinciding attributes or
// methods, elements of the last class
// become main.
obj:attribute1:=0
obj:attribute2:=date()
obj:method1:=@func1() // method1 becomes a function reference
obj:method2:=@func2() // these functions must be defined in
// prg file
// if methods have been addopted from other classes,
// they will be reassigned to indicated classes
return obj // returning a ready object
static function func1
::attribute1++
retun NIL
static function func2(self)
self:attribute1--
retun self
Also, we'd like to add two simple rules:
- 1. The attribute is created when something, including NIL, is
assigned to it.
- 2. At any moment, in run-time,the method can assign or reassign
any function announced in this mudule as static function, or can
adopt
this function from another object, as a usual assignment of values.
myObj1:method1 := myObj2:methodX
In what way can objects be used? As in CA-Clipper, or even more simply.
obj:=MyClassNew()
obj:metod1()
? obj:attribute1
In an object, destroy() method can be announced, but it isn't quite
destructor, which is usual in languages of the third generation.
There is local myObj:=myclassNew() variable, and this is just an
object. Upon leaving the function body, this variable, along with all its
data, is destroyed.
For example, this myObj has attribute
myObj:hFile:=fopen(trali_vali).
When destroying myObj, it's necessary to close hfile, but
the
compiler doesn't know this; the compiler (rather a virtual machine) only
knows that in hFile there's a number and will destroy the number
only,
but the file will remain open!
Just for this purpose destroy is created, and it'll called (if
it exists ) before destroying myObj variable.
static function my_destroy()
fclose(::hFile)
return
Control of change attributes.
If it's necessary to control changes of object attributes, make modify
method and set mapmodify(map_obj, .t. ), modify method will
be called, and only then the attribute value will be changed.
New value of attribute changet to return value of method modify()
Recovering/reviving objects.
CLIP is able to store the data of any type to MEMO fields, including
objects. But there is no way to store object methods (methods can be changed).
Recovering is made with steps below: data are decoded; if data are of
'object' type and object have CLASSNAME attribute then called function
_recover_&(var:CLASSNAME)(var). This function must assign this object methods.
This feature can be used to send object as string via e-mail or TCP :)
Here is an example of using this feature:
x:=asdfNew() /* Constructor */
? "x:m1",x:m1() /* See wheter it works */
? "x:m2",x:m2()
y:=var2str(x) /* object -> string */
/* or field->memo_field:=x */
? "y=",y
z:=str2var(y) /* string -> object, _recover_asdf() is called automatically */
/* or z:=field->memo_field */
? "z=",z
? "z:m1",z:m1() /* see wheter it works now */
? "z:m2",z:m2()
?
return
function asdfNew()
local o:=map()
o:classname := "ASDF"
o:a1 := "asdf"
o:a2 := "qwer"
_recover_asdf(o)
return o
function _recover_asdf(o)
o:m1 :=@ asdf_1()
o:m2 :=@ asdf_2()
? "recovering"
return o
static function asdf_1
? "asdf_1",::a1
return ::a1
static function asdf_2
? "asdf_2",::a2
return ::a1
Due to such OO model and compiling fast code via the translation into
C-program, there appears a possibility to write TBrowse and Get
standard classes in Clipper itself!
At the same time, the
efficiency of these classes is not worse than those written in pure C
in CA-Clipper.
CLIP home page
© Uri Khnykin, uri@itk.ru, 2001