语言的自由度

自由度这个概念在不同领域有不同的定义,我们借鉴数学中构成一个空间的维数来表达其自由度的做法,在此指的是:解决同一个问题彼此不相关的设计方法学数量。

例如,解决一个比如商品打折的问题,如何设计顺序、提取函数,具体的思路可能有很多,但是这可能都是从面向过程(OP)的角度,同样解决这个问题,如果另一门语言还支持面向对象(OO)的设计方法,那么我们认为后者的自由度要多一些,因为OO提供了几乎完全从另一个角度解决问题的能力。

既然自由度可以借鉴“维数”的定义,我们来尝试分析一下计算机语言的“维数”,在此之前,我们有必要简单分析一下语言是怎样一步一步变得复杂的。

本文关注的重点是命令式风格的计算机语言。

第一步,出现了结构体(数据结构)、常量、变量、算符、顺序、分支、循环等这些体现“命令”的基本方面;

第二步,例程的出现,包括函数、过程等;

第三步,宏的出现,包括宏、模板、泛型;

第四步,对客观世界在结构化上抽象能力出现,包括OO等;

第五步,元编程能力的出现,如注释、反射等等;

从计算机语言历史来看,以上步骤不一定按照时间顺序展开,我们更关注的是语言能力提升带来的意义。其中,第二步的完成,标志着结构化程序设计方法的出现,对大型软件工程提供了较好的支持,第三步是对第二步的进一步抽象,第四步所代表的意义更加重大,其中非常重要的一点,意味着终于可以支持实现“层次化”,可以实现将“内核”与“外围”做分离,将相对稳定与潜在变化的部分分开,也就是说,编码所表达的内容不再只能扁平化,终于进化出了“阶级”。

从本质上来讲,以上演进反映了语言自身抽象能力的不断提升。

这里非常有意思的一个现象是,抽象化的不断提升,会使得语言的维度提升至某个分数维——抽象的本质是在空间上提供了某种自相似的递归映射,从而体现出“分形”的结构形式,分形结构表现出在原有空间中增加了分数维,但是得到一个新的整数维是困难的,即比如1维可以提升至1.5维,但是无法到达2维。

所以,目前绝大部分计算机高级语言的维度是1.X。

但是第五步,意味着语言开始真正走向一个更高的维度。

事实上,实现元编程有多种方式,从语言本身来讲,可以分为两类:增强型API与新的语法实现,前者的代表是反射,后者的代表为Annotation。

我们来看一个例子:

public class TestCase{
@Before
public void setUp() throws Exception{}
@After
public void tearDown() throws Exception{}
@Test
public void add() {}
}

上面是Java语言中使用Annotation类型定义了一个单元测试的三个阶段,在这里:
@Before、@After、@Test用“变量”定义了“变量”,同时定义了执行的顺序,这里是“对编码再进行编码”的过程,是元编程的一种典型的实现。

我们当然也可以通过增强型API(反射或者用设计约束(比如摸版方法))来解决,但是无论哪一种,都不如Annotation的方式要简单直接明了。

根本的原因,在于增强型API的实现方式与原有代码这两个表达逻辑的维度存在过多的“相关性”,即1.X维的,但Annotation的方式在相关性上大大减少,两个维度更加解耦,所以后者的自由度更高。

如下JS基于Mocha的单元测试代码:

describe('测试过程1', function() {
it('1+1', function() {
expect(fn_add(1, 1)).to.be.equal(2);
});
});

我们期望如下编程风格:

'@test(step=测试过程1,name=1+1,expect=2';
var step0 = function(){
return fn_add(1, 1);
}

JS实现基于注释的元编程

我们尝试将Annotation的机制引入JS,如下:

'@Log(level=info,dateFormat=YYYY-MM-DD HH:mm)’;
var logInfo = function(_msg){
console.log(_msg);
}

复杂的场景,考虑多个注释的相关性:

'@Start';
var serverStart = function(){} '@Rule(fileType=.(html|htm))';
var proHtml = function(_req,_res){} '@Rule(fileType=.(jpg|gif|webp))';
var proPic = function(_req,_res){} '@Finish';
var serverFinish = function(){}

At-js框架

基于以上想法,我们实现了At-js框架并开源,At-js的实现思路非常简单,在Node.js端,通过覆盖运行时JS文件加载机制实现对Annotation类型的识别判断并对原生文件进行Enhance处理,为性能考虑,At-js采用了正则扫描而非AST的方式。

At-js使用方法包括:定义注释与使用注释。

定义注释:

require('at-js').define('helloworld',{//annotation's name
scope: 'var', build: function () {//the scope of it's effected
return "return function(_msg) {console.log('[helloworld]'+_msg);};"//the real script
}
})

使用注释:

'@helloworld';
var sayHello = function(){} sayHello('here')

运行效果:

[Helloworld]here

以下代码描述了一个单元测试过程(https://github.com/CheMingjun...):

'@test.start';
var start = function () {
ds = {};
} '@test.step(timeout=2000)';
var test0 = function* () {
ds.test0 = 'finish';
var rtn = yield (function(){
return function(_next){
setTimeout(function(){
_next(null,3);
},2000)
}
})();
assert.equal(rtn,3);
} '@test.step';
var test1 = function () {
ds.test1 = 'finish';
return ds;
} '@test.finish';
var fh = function () {
ds = null;
}

At-js支持Var级及File不同级别的注释定义,上例属于File级别复杂的注释定义,两者的API如下:

Var型注释定义:

    {
scope:'var',
build:function(_ctx, _argAry){
//_ctx
{
filePath,//应该该注释的文件位置
name,//注释名称
desc,//注释中的变量表(key-value)
refName,//被注释的变量名称
refType//被注释的变量类型(undefined|function|generator|object)
}
//_aryAry 被注释变量签名中的参数列表 return //返回该变量被替换之后的代码
}
}

File型注释定义:

    {
return {
which: {//针对改组annotation中的每一项做处理
'test.start': function (_ctx, _argAry) {
//_ctx 与 _argAry 同上定义
//处理逻辑
}
}, script: function () {
return //返回该文件追加的代码
}
}
}

在实际生产过程中,如下一套注释实现了ORM:

    '@dao.column';
var id; '@dao.column(name=name)';
var name; '@dao.column(name=status)';
var status; '@dao.column(name=creator_id)';
var creatorId; '@dao.column(name=creator_name)';
var creatorName; '@dao.column(name=gmt_create)';
var createTime = function (_time) {
var mm = require('moment');
return mm(_time).format("YYYY-MM-DD HH:mm:ss");
} '@dao.column(name=gmt_update)';
var updateTime = function (_time) {
var mm = require('moment');
return mm(_time).format("YYYY-MM-DD HH:mm:ss");
} '@dao.column(name=type)';
var type;

总结

本文给出了语言自由度的简单定义,并在此基础上论述了在语言发展过程中呈现的不同复杂性,并探讨了元编程是如何从根本上增加语言的自由度的。在第二部分,我们尝试在JS语言基础上增加原生的元编程能力并介绍了该思路的实现:At-js框架。

Javascript元编程之Annotation的更多相关文章

  1. javascript 元编程之 method_missing

    javascript 元编程之 method_missing 引言 要说元编程 ruby 中技巧太多了,今天来写的这个技术也来自于 ruby 中的灵感. method_missing 这个在 ruby ...

  2. Javascript异步编程之setTimeout与setInterval详解分析(一)

    Javascript异步编程之setTimeout与setInterval 在谈到异步编程时,本人最主要会从以下三个方面来总结异步编程(注意:特别解释:是总结,本人也是菜鸟,所以总结不好的,请各位大牛 ...

  3. 【转】Javascript异步编程之setTimeout与setInterval

    Javascript异步编程之setTimeout与setInterval 转自:http://www.tuicool.com/articles/Ebueua 在谈到异步编程时,本人最主要会从以下三个 ...

  4. JavaScript模块化编程之AMD - requireJS基础使用

    JavaScript模块化编程之AMD requireJS基础使用 标签(空格分隔): JavaScript 参考文章 AMD规范 AMD是"Asynchronous Module Defi ...

  5. JavaScript模块化编程之require.js与sea.js

    为什么要模块化:当今,网站以不再是一个简单的页面,JavaScript也不再是做一些简单的脚本验证,随着WEB.20时代到来,前端工程师面临的必将是越来越庞大的JavaScript代码,越来越复杂的内 ...

  6. 我也来谈javascript高级编程之:javascript函数编译过程

    前言 题目有点大,其实也就是手痒...跟大家来扯一下javascript编译过程. 那么到底什么是“编译”呢 这个...本人文笔太差,我还是直接举例子吧. 相信玩过js童鞋应该都看过下面这样一个面试题 ...

  7. Javascript模块化编程之Why

    说到模块化编程,大家比较容易想到Java, C++等语言,感觉这事和Javascript沾不上一丁点边.虽说Javascript看上去好像同Java有莫大的关系,但那也只是一厢情愿,不过是挂羊头卖狗肉 ...

  8. JavaScript模块化编程之AMD

    简单的说一下AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义".它采用异步方式加载模块,模块的加载不影响它 ...

  9. Javascript模块化编程之CommonJS,AMD,CMD,UMD模块加载规范详解

    JavaSript模块化 在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发?     模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问 题进行系 ...

随机推荐

  1. 华为鸿蒙系统pk安卓系统

    Harmony OS Vs Android Comparison It isn’t based on Linux kernel The key difference between HarmonyOS ...

  2. topological space

    \(\underline{Def:}\)A topology space \(\mathcal{X}=(\underline{X},\eth_{x})\)consists of a set \(\un ...

  3. 分类算法之KNN分类

    1.介绍 KNN是k nearest neighbor 的简称,即k最邻近,就是找k个最近的实例投票决定新实例的类标.KNN是一种基于实例的学习算法,它不同于贝叶斯.决策树等算法,KNN不需要训练,当 ...

  4. java成神之路

    一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://i ...

  5. 用Excel做数据分析常用函数(数据清理、关联匹配……)

    本文总结在使用Excel进行数据分析时,最常用的功能和函数. Excel的功能和函数非常多,用进废退,除了学习基本的函数和功能,最重要的是遇到问题可以快速的搜索并解决. 首先Excel可以处理的数据量 ...

  6. 100)PHP,文件上传总代码整理

    首先是我的目录关系: 然后我的html表单代码: <html> <head> <title>Form</title> <meta http-equ ...

  7. python库之——sklearn

    机器学习库sklearn 官方documentation(资料)中分为不同的部分: 其中我们主要讲User Guide(机器学习算法理论介绍).API(程序实现方法): 一.User Guide ht ...

  8. [Windows] Windows API 串口通信

    Windows 中通过Windows API 进行串口通信主要有以下步骤: 打开串口 配置串口 读写串口 关闭串口 打开串口 关键API: CreateFile Windows 中进行设备的操作,第一 ...

  9. SCI|EI|ISTP|万方|istic|NSTL|CASTD|CNKI|nlc|ethesys|CALIS|CETD|proquest|NDLTD|中国科学院学位论文检索系统|学位论文

    BD AC D 三大检索指的是:SCI(科学引文索引 ).EI(工程索引 ).ISTP(科技会议录索引 ) 即Science Citation Index.Engineering Index.Conf ...

  10. Windows 10操作系统针对不同环境下的安装方法

    一.电脑系统能正常运行 1.解压win10镜像文件 到电脑的非系统分区,运行setup安装文件 2.点击setup应用程序,准备安装 3.准备安装 4.等待安装过程结束,重启即可. 二.光盘安装 1. ...