среда, 29 июля 2015 г.

Briefly. Wonder of words redefining

Original in Russian: http://programmingmindstream.blogspot.ru/2015/07/blog-post_28.html 

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:

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:
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:

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:
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:

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

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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:
// Decorators

USES
 axiom:DocEditorWindow
;

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

4 комментария:

  1. А людям то - нравится.. Плюсы ставят...

    @Ingword а что там в G+? Опять ругают поди?

    ОтветитьУдалить
  2. It seems to me that people like it.

    It's pity that I don't know English to discuss this matter.

    https://plus.google.com/u/0/113567376800896602748/posts/Lppb28z3oaD


    Stefan Glienke29 июля 2015 г.+2
    1
    2


    I thought about extending the Delphi language by preprocessing as well. And we even had such things already (like DLangExtensions). Getting something like that running is not the issue.

    What's an issue though unfortunately is getting such code work inside the IDE. Nothing will work: no code completion nor refactoring (or completely messing up the code), nor proper tooltips or code navigation.
    Перевести

    Lars Fosdal29 июля 2015 г.+3
    4
    3


    preprocessors are more trouble than they're worth. doubly so if not actually supported.
    Перевести

    David MillingtonВчера в 13:50+1
    0
    1


    It's a sign of how much language development we as a community want, though. Perhaps we can get some of these improvements if we ask loudly enough?
    Перевести

    Johan BontesВчера в 23:02


    1
    Ответить

    +Stefan Glienke
    The refactoring we can get working using DelphiAST. Ditto for code completion. That still leaves the huge issue of debugging though. I wonder if it's possible to manipulate the MAP file.

    Unfortunatly by that time you've almost rebuilt the IDE.

    ОтветитьУдалить