Friday, October 18, 2013

Zen Style: Semantics Oriented, Contextual Programming

The title of this blog is suggestive.
Like a monk in Zen temple, a programmer should not work hard for low level thing, but just try hard to identify the essence of the problem, then the rest will follow magically with no effort.

Declarative programming style is something common to this style. we don't care some procedural steps, which are very low level, but just concentrate on the relationship.
But declarative style itself are still not powerful enough. We must be able to extend the declarative constraint enforcing mechanism in the programming. It is sort of reflective approach, the goal of this approach is to create autonomous intelligent program driven by knowledge and semantics, context, rules etc. Essentially the output is not cumming just from the written code, but the as a synthesis of machine intelligence and the directive programming which will be short in size.

Normally such kind of programming were not easy. But these days, reflection library can be used to assist such programming style. Annotation is actually very under evaluated naming, but it has big potential. we can change ordinarily programming behavior outside of written code using such annotation information and specific library using reflection.

The code I developed for GUI is such an example.
Essentially the goal of the approach is to support declarative GUI development.
Some structural/layout related coding are defined with no procedural codes.

And procedural code which are associated with how the GUI will respond to user input etc are cleanly separated from these GUI code.

In normal program, we cannot change the timing of setting some property values etc, but using reflection library, it can implicitly set these values based on annotation, field type, context class type etc.
So we may think of this as semantics driven program, or contextual program. We can improve programming productivity by delegating certain annoying patterns to such library.
This is quite close to changing our language itself. So that is the essence of reflectivity.

These things could have been done in Java, but Java's generics were poor at runtime compared to Dart, Dart has more potential utilizing generic's type information. This is important difference. Java could not know itself at runtime, but Dart can. One interesting example was the CouchDB json parser which will use provided applied generic type information to determine sub json's type information as posted before.
Another reason may come from just the basic verboseness of Java language. There are so many restrictions, like anonymous class, even something can be done better, in the faces of such a bloated code, the gain would have reduced a lot.
That would have been discouraging some effort. AOP activities were something to be mentioned, but I have never seen such AOP application for GUI library in Java.
The cascading syntax is very small syntactic addition, but it has a big potential to eliminate all html  based development. Also many future, higher order functional make code very short.
Only in such an environment, these new approach will shine.

Here is a new revised version of sample code I posted before.
in the first part of code are dedicated to GUI presentation. Also the idea of this approach is to assist component style web development which combine the behavioral logic in the component, so such sub components are also declared as final field property with annotations.
From this annotation information and the declaring class, ie, CRUDView as subclass of Component class, when the object is instantiated, the super class Component will start analysing the annotation
 through reflection library, and setting corresponding property in the subcomponents(like label value in the annotation).

class CRUDView extends Component {
  static const String CRUD = "g_cud_view";
  DivElement _content;
  DivElement _actions;

  @UI_Table()
  final Table<Expense> table = new Table<Expense>();
  
  @UI_Form()
  final Form<Expense> form = new Form<Expense>();
 
  @UI_Button(label: "Load")
  final ButtonComp loadButtom = new ButtonComp();
  
  @UI_Button(label: "New")
  final ButtonComp newButtom = new ButtonComp();
  
  @UI_Button(label: "Save")
  final ButtonComp saveButtom = new ButtonComp();
  
  @UI_Button(label: "Delete")
  final ButtonComp deleteButtom = new ButtonComp();
  
  Element _updateElement(Element elm) => 
      elm
      ..classes.add("section")
      ..nodes.add(new Element.html("<header class='section'>${table.modelType} Table</header>"))
      ..nodes.add(_content = new Element.tag("div")
        ..classes.add("g_crud_view_table")
        ..nodes.add(table.element))
      ..nodes.add(_actions = new Element.tag("div")
        ..id = "actions"
        ..classes.add("section")
        ..nodes.add(loadButtom.element)
        ..nodes.add(newButtom.element)
        ..nodes.add(saveButtom.element)
        ..nodes.add(deleteButtom.element))
      ..nodes.add(form.element)
      ..nodes.add(new Element.html("<footer class='section' id='footer'></footer>"));
 
This part defines more behavioral aspect of program.It defines how application respond to the user input etc. these are nothing to do with GUI. We may still reduce direct association of the action with each GUI components if we introduce Monitored fields as I have done in namebudge application.

  // this should be injected by AOP approach from out side..
  ICouchDbClientDAO<Expense> dao = new CouchDbClientDAO<Expense>(Expense, sampleJsonMapper);
  
  CRUDView() {
    this.classes.add(CRUD);
    Type _Expense = Expense;
    table
      ..modelType = _Expense
      ..formatFunctionMap[ExpenseType] = ExpenseTypeComp.format;
    
    form
      ..modelType = _Expense
      ..inputFactoryCache.specialInputCompMap[ExpenseType] = ExpenseTypeComp.inputCompFactory
      ..inputFactoryCache.adhocCompMap['detail'] = 'textarea'; // should be moved to annottaion!
    
    loadButtom.onClick((_) {
      dao.fetchAll().then((List<Expense> es){
        table.load(es);
        //print('loaded data from db; ${es}');
      });
    });
    
    newButtom.onClick((_) {
      Expense e = form.create();
      _changeButtonState(true, false, true);
      //print('new in db');
    });
    
    saveButtom.onClick((_) {
      if (form.e != null) {
        Expense e = form.save();
        if (e == null) {
          //print('form is empty, click New, or select arow before Save.');
          return;
        }
        // this part is tricky..
        // since e is fill from InputText, when it is empty text, it will assign "" instead of null..
        if (e.id == "") e.id = null;
        if (e.rev == "") e.rev = null;
        ((e.id == null)?dao.insert(e):dao.update(e)).then((Expense e0){
          e.id = e0.id;
          e.rev = e0.rev;
          table.addOrUpdate(e);
          _changeButtonState(false, true, true);
          //print('updated in db e0: ${sampleJsonMapper.toJson(e0)}, e: ${sampleJsonMapper.toJson(e)}');
        });
      }
    });
    
    deleteButtom.onClick((_) {
      Expense e = form.e;
      if (e != null) {
        dao.delete(e).then((ok){
          if (ok) {
            form.delete();
            table.delete(e);
            _changeButtonState(false, true, true);
            //print('deleted in db');
          }
        });
      }
    });
    _changeButtonState(false, true, true);
    
    table.row_listeners.add((ev, row){
      Expense e = row.e;
      form.load(e);
      _changeButtonState(false, false, false);
    });
  }
  
  void _changeButtonState(bool new_disable, bool save_disable, bool delete_disable) {
    newButtom.node.disabled = new_disable;
    saveButtom.node.disabled = save_disable;
    deleteButtom.node.disabled = delete_disable; 
  }
  
  Element createElement() => addSubComponents0(newElem("div"));
  
  Element update() => addSubComponents0(initElem());
      
  Element addSubComponents0(Element elm) => addListeners(_updateElement(elm));
}

This is one application of annotation and reflection, the other application I introduced was Monitor. Monitor is useful to separate GUI interaction and actual semantics.It may be considered as more efficient version of Event driven code.
Monitor is achieving similar goal as Observable does in Ploymer, but it is general purpose class, which may be used for OR mapped entity classes to support lazy loading etc.

Anyway, I will need to describe them in more detail later.

No comments:

Post a Comment