Wiki

Clone wiki

MindStream / Articles in English / Briefly. Wonder of words redefining

Original in Russian

Briefly. I’ve made a wonderful thing – words redefining.

It allows Duck-Typing of a kind, though based on static type-checking, if possible.

Let us have:

#!delphi 
UNIT TObjectA // - defines a unit for TObjectA

USES
 axiom:TObjectA // - uses TObjectA axiomatics
;

EXPORTS
 axiom:TObjectA // - exports axiomatics of TObjectA to units that use it

INTEGER FUNCTION A
 TObjectA IN anObj // - object of TObjectA type
 ...
 Result := anObj SomeCodeA // - calls SomeCodeA method on anObj instance
; // A

...

UNIT TObjectB // - defines a unit for TObjectB

USES
 axiom:TObjectB // - uses of TObjectB axiomatics
;

EXPORTS
 axiom:TObjectB // - exports axiomatics of TObjectB to units that use it

INTEGER FUNCTION B
 TObjectA IN anObj // - object of TObjectB type
 ...
 Result := anObj SomeCodeB // - calls SomeCodeB на экземпляре anObj
; // A

Function A works with object of TObjectA type.
Function B works with object of TObjectB type.

Therefore, we can write as follows:

#!delphi 
USES
 TObjectA // - uses axiomatic of TObjectA and axiom:TObjectA
 TObjectB // - uses axiomatic of TObjectB and axiom:TObjectB
;

REDEFINE
 : A
   OBJECT IN anObj // - abstract object
   if ( anObj Is TObjectB ) then
   // - object of TObjectB type
    ( anObj B ) // - calls method B
   else
    ( anObj inherited ) // - calls the "MAIN" method of TObjectA::A
 ; // A

Thus, we can call in this way:

#!delphi 
TObjectA VAR x1
TObjectB VAR x2
...
x1 A // - calling of TObjectA::A method
x2 A // - calling of TObjectB::B method

We can also write symmetrically:

#!delphi 
USES
 TObjectA // - uses axiomatic of TObjectA and axiom:TObjectA
 TObjectB // - uses axiomatic of TObjectB and axiom:TObjectB
;

REDEFINE
 : B
   OBJECT IN anObj // - abstract object
   if ( anObj Is TObjectA ) then
   // - object of TObjectA type
    ( anObj A ) // - calls method B
   else
    ( anObj inherited ) // - calls the "MAIN" method of TObjectB::B
 ; // B

In this case, we can write:

#!delphi 
TObjectA VAR x1
TObjectB VAR x2
TObjectA VAR x3
TObjectB VAR x4
...
x1 B // - calling of TObjectA::A method
x2 B // - calling of TObjectB::B method
x3 B // - calling of TObjectA::A method
x4 B // - calling of TObjectB::B method

The examples given are in Run-Time.

However, setting the IMMEDIATE attribute to the words redefined and CompileValue instead of direct calls results in statistic overriding which depends on the parameters types and it is compilable.

Why do we need it?

We need it in order to adapt the object model for those people who are not eager to know details about specific object model.

For example, it can be used by testers.

For them TEdit, TvgEdit and TsomeOtherEdit look as like as peas in a pod.

There are also other people who understand the system in terms of GUI and there are other “generic objects” that are not classified similarly to the project classification.

The issue relates to the primitive types like INTEGER and STRING or interfaces as well.

Quite understandable is the fact that this “mapping” can be done in different ways in various “specific axiomatics”. It is not viewed by the testers similarly to the way other people see it.

It depends on the set of used dictionaries.

Moreover, mapping differs for various system layers.

Even more so since the layers of the system are separated on the principle: “we can only see our neighbours at a lower or a peer layer”.

It is obvious that REDEFINE controls “generic signatures” for covariation.

Notice that REDEFINE is not OVERRIDE.

REDEFINE is not integrated inside the classes but keeps “on the side” for “outside users”.

It is like a helper or categories in Objective-C.

Let me remind you that each abstraction layer can have different REDEFINE.

These people aim to develop a pre-processing program - Link. Why can't an interface have class methods? (most of the links are in Russian)

I quote:

"Yes, I get that, I guess I was stuck in the mindset of the Java default method and the static method. This is sort of a mix between the two.
The default methods are way cool.
Interface helpers and interface operator overloading would go a long way towards achieving these goals.
(Then there's virtual methods for records, method inheritance for records, allowing multiple class helpers in scope, allowing
inheritance for record helpers).

I'm temped to write a pre-processor to add these things myself (borrow some syntax from oxygene or SMS and transparantly alter the sourcecode before compilation)."

Too bad, I am not able to get my opinion out to these guys which is they should work with models and “script extensions” instead of dealing with “pre-processors”. They are compilable at least into a “threaded code”.

I would also advise to integrate “diferent axiomatics transformations” at a higher level compared to the “target language code”.

P.S. It is clear that using these “tricks” can result in an “extraordinary messed” code, but i do not focus on people who love to “shoot off their own legs”.

You can shoot off your legs using Delphi or C++ or Haskel as well.

Not to mention Python and the slots...

It is important to understand what you do and be reluctant to “shoot”.

It is also obvious that all REDEFINES are found considering all USES and EXPORTS - Briefly. I exported the dictionaries.

If it is not possible to define the word PRECISELY (you can not choose one), the error message is popped up.

In this case we classify it as UNIT :: WORD.

It is totally equal to namespace in C++.

Oops..

Real life example:

Briefly. I made axiomatic description partly on Delphi, partly on scripts

#!delphi 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Library "ScriptEngine$VT"
// Unit: "vtComboBoxWordsPack.rc.script"
// Resource scripts (.rc.script)
// Generated from UML model, root element: ScriptKeywordsPack::Class Shared Delphi::ScriptEngine$VT::vtComboBoxWords::vtComboBoxWordsPack
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//#UC START# *54EC8C7C011Eimpl*

// Decorators of words that work with combo

USES
 axiom:ComboBox
 axiom:ComboTree
;

REDEFINITION
 : pop:ComboBox:DropDown
  OBJECT IN aCombo
  if ( aCombo Is class::TvtComboTree ) then
   ( aCombo pop:ComboTree:DropDown )
  else
   ( aCombo inherited )
 ; // pop:ComboBox:DropDown

REDEFINITION
 : pop:ComboBox:GetItemIndex
  OBJECT IN aCombo
  if ( aCombo Is class::TvtComboTree ) then
   ( aCombo pop:ComboTree:GetItemIndex )
  else
   ( aCombo inherited )
 ; // pop:ComboBox:DropDown

REDEFINITION
 : pop:ComboBox:IndexOf
  OBJECT IN aCombo
  if ( aCombo Is class::TvtComboTree ) then
   ( aCombo pop:ComboTree:IndexOf )
  else
   ( aCombo inherited )
 ; // pop:ComboBox:DropDown

REDEFINITION
 : pop:ComboBox:SaveItems
  OBJECT IN aCombo
  if ( aCombo Is class::TvtComboTree ) then
   ( aCombo pop:ComboTree:SaveItems )
  else
   ( aCombo inherited )
 ; // pop:ComboBox:SelectItem

REDEFINITION
 : pop:ComboBox:SelectItem
  OBJECT IN aCombo
  if ( aCombo Is class::TvtComboTree ) then
   ( aCombo pop:ComboTree:SelectItem )
  else
   ( aCombo inherited )
 ; // pop:ComboBox:SelectItem

REDEFINITION
 : pop:ComboBox:SetItemIndex
  OBJECT IN aCombo
  if ( aCombo Is class::TvtComboTree ) then
   ( aCombo pop:ComboTree:SetItemIndex )
  else
   ( aCombo inherited )
 ; // pop:ComboBox:SetItemIndex

//#UC END# *54EC8C7C011Eimpl*

And some other example:

#!delphi 
// Decorators

USES
 axiom:DocEditorWindow
;

 : IsNeedSaveDocument
  OBJECT IN aWnd
  if ( aWnd Is class::TDocEditorWindow ) then
   ( aWnd DocEditorWindow:IsNeedSaveDocument )
  else 
   ( false )
 ; // pop:ComboBox:DropDown

Updated