您的位置:首页 > 移动开发 > WebAPP

作者自述CSE语言设计思想(六)----基于HTML5跨越NativeApp与WebApp的一种途径

2011-12-30 22:48 288 查看
今天的主题是:用CSE仿真JavaScript语言

多范式语言

CSE是一门多范式编程语言,尽管在官方文档中CSE只宣称是基于函数式编程(FuntionalProgramming)的语言,并未宣称它是多范式语言,但从实际表现来看,它确实是一门不打折扣的多范式语言。

《CSE功能手册》中介绍了用CSE映射C、C++,CSE在支持基于过程、基于面向对象方面是完整的,CSE本身是脚本语言,与Python、Ruby类似,它的内核基于纯正的函数式架构,所以也可拓展用纯正函数式风格进行编程,前面我们有过介绍了:

作者自述CSE语言设计思想:用CSE模拟LISP语言(上)

作者自述CSE语言设计思想:用CSE模拟LISP语言(中)

作者自述CSE语言设计思想:用CSE模拟LISP语言(下)

在多范式方面,还有一门语言值得一提:Falcon(官方主页:www.falconpl.org/),中文介绍请参考维基百科中的词条(http://zh.wikipedia.org/wiki/Falcon编程语言)。Falcon宣称支持六种编程范式(见Falcon官方首页):

Ø procedural,过程式

Ø object oriented,面向对象

Ø prototype oriented,基于原型

Ø functional,函数式

Ø tabular,表格化

Ø messageoriented,面向消息

对Falcon多些了解后,我有一个挥之不去的感觉,Falcon为语言而语言了。创造一门语言要着眼于它能解决什么问题,Objective-C够土吧?但它解决了MAC、iPhone、iPad上高效率程序的开发问题,傻儿八唧并不影响它广泛流行。所谓表格化(还有面向消息),与函数式、面向过程、面向对象根本不在同一层面上,面向过程语言也可以构造消息驱动机制呀。把多范式作为一门语言的主要卖点去宣传,说明作者的思维方式还没进化。

同行相轻了?见谅。干同样技术活,忍不住多说几句。拿Falcon类比是要引出今天的话题,如何让CSE也具备Prototype Oriented(基于原型)的编程能力,JavaScript是基于原型编程的一个典范,我们要做的是,如何用CSE脚本仿真JavaScript语言风格。

模拟JS的意义

CSE是脚本语言,JavaScript也是脚本语言,用脚本语言模拟脚本语言,吃饱了撑着吗?

前面我强调:一门编程语言要强化它的应用特质,拿CSE仿真JS,不要只看到脚本语言仿真脚本语言,因为仿真的价值不在于CSE能实现原型编程,而是它可以仿真作为WEB终端开发事实标准的JavaScript的能力。“实现原型编程”是没多少价值的,基于函数式的语言都容易做到,但模拟WEB事实标准的开发形式却是高价值的。

进一步阐述我的思路,当前CSE聚焦于提供一种“用脚本化方式”快速开发“经编译、能高效运行”的程序,即,让开发者同时享受脚本语言与编译语言的优势,为实现这个目标我们耗用了七年。后面,我们还同样消耗若干年为CSE赋予更高使命:融合WebApp开发与NativeApp开发,或者说,让WebApp开发不要有那么多缺陷,也让NativeApp发行不再受限,当这个使命放在Html5注定流行的大背景下,它变得高大起来,你信吗?至少我是信的。

还没理解上面这段话的,请往下看,已理解了的,也请往下看。用CSE仿真JS是个契子,它会引伸出更多有趣的东西。

一个前提

用CSE脚本语言模拟JS,主要服务于软件开发阶段,release发布时应将CSE脚本译成JS,或译成C/C++。否则,如果发布仍用CSE脚本,用脚本仿真脚本,真是吃饱撑着了。

这种做法至少为WebApp解决两个难题,其一,性能问题,谁都愿用Html5开发跨平台游戏,但JS支持大型网游存在性能瓶颈。其二,安全问题,基于JavaScript与HTML5网页的程序,客户端代码很难保密,谁都不希望自己辛辛苦苦开发的东西,一发布就被别人盗用。

但脚本语言与C/C++编译语言存在鸿沟,前者是弱类型系统,后者是强类型系统,消除两者鸿沟,我们需作出一些限制,让弱类型系统模拟强类型系统的行为,就像当前CSE-CPP语言集,用脚本做开发、做调试,最后能翻译为强类型系统的代码。

类型系统

JS的类型比较简单,number、string、boolean、object,再就是null了,用CSE的int、wint、float可以模拟JS的number,CSE的string模拟JS的string,CSE的TBool模拟JS的bool,剩下只有object要费点事,后面专门介绍。

创建变量与变量读写:

iValue as 3;
print(iValue);
sName as "example";
print(sName);


这几行译成JS:

var iValue = 3;
print(iValue);
var sName = "example";
print(sName);


一个变量不应用作多个类型,如下代码尽管CSE能正确执行,译成JS也正确。

iValue as 3;
print(iValue);
iValue as "example";
print(iValue);


但译成C/C++会有问题。使用命名前缀,如上面iValue、sName,可有效避免误用。

控制语句与函数定义

CSE的if、else、while、for、try..catch、break、continue、return等语句,可以直译到JS代码。swith..case不支持,使用switch的场合均可用if..else替代,另外,JS的with也不支持,因为C/C++没有与之对应的语法。

CSE的lambda函数定义足以仿真JavaScript的函数。比如:

test as lambda: i,j,
return i + j;
end;

test2 as lambda: declare(i,j = 1),
return i + j;
end;


等效于JS中:

function test(i,j)
{ return i + j; }

test2 = function(i)
{
j = arguments.length == 1? 1:arguments[1];
return i + j;
}


用JSON风格创建object

JavaScript创建object典型方式如下:

var classmate = { name:"Wayne" };
print("name is " + classmate.name);
classmate.age = 18;

classmate.info = function() {
print("name:" + this.name);
}
classmate.info();


我们用CSE中interface风格的class模拟这种object,如下:

class JsonClass: end as AInterface;

class JsonClass:
declare #dict as TEntryArray*;

func JsonClass(me):
ppDict as TEntryArray** = &me as TEntryArray**;
*ppDict = new TEntryArray();
end;

func `~JsonClass`(me):
ppDict as TEntryArray** = &me asTEntryArray**;
delete *ppDict;
*ppDict = NULL;
end;

func `#1:`: ## get attribute
declare(me,attr);
if "#dict" == attr:
return *(&me as TEntryArray**);
end else:
pDict as *(&me asTEntryArray**);
ret as pDict->get(attr.toId());
if CseNull == ret:
throw(EAttrError,"attribute(%s) inexistent" % [attr]);
end else return ret;
end;
end;

func `#1;`: ## set attribute
declare(me,attr,value);
if "#dict" == attr:
throw(EAttrError,"attribute(#dict) is readonly");
end else:
pDict as *(&me asTEntryArray**);
pDict->set(attr.toId(),value);
return value;
end;
end;
end;


在CSE中创建与使用object如下:

classmate as JsonClass();
classmate.name = "Wayne";
classmate.age = 18;
classmate.info = lambda:
print("name:" + classmate.name);
end;


给一个object随时增加成员变量(如上面classmate.age),或成员函数(如上面classmate.info)我们做到了。这里我们用CSE模拟JS还存在几个缺陷:

1. 没有用“{}”表达object的初始内容

2. 为object定义函数时,没像JS那样用this来虚指

这两点在本文后都会解决。我们先解决上述JS中JSON表达方式存在的一个问题,赋给classmate.info的函数一次定义后专供classmate对象使用,并未共享给其它object。如果我们创建另一个名为classmate2的变理,也用“classmate2.info = function()....”再赋一次值,太繁琐了。改用JS的prototype可解决这个问题,比如:

function Person(name)
{ this.name = name; }

Person.prototype.info = function()
{ print("name:" + this.name); }

var classmate1 = new Person("Wayne");
var classmate2 = new Person("George");
classmate1.info();  // output is: name:Wayne
classmate2.info();  // output is: name:George


接着优化,让JS的类型声明独立出来,就像C++的class类声明,让JS中的object通过class类创建出来,即,上面“new Person()”看起来有点像C++的类实例创建,但Person是个函数。改成如下代码:

var Person = {
__init__: function(name)
{ this.name = name; }

info: function()
{ print("name:" +this.name); }
};

function New(aClass,aParams)
{
function New_()
{ if (aClass.__init__) aClass.__init__.apply(this,aParams);}

New_.prototype = aClass;
return new New_();
}

var classmate1 = New(Person,["Wayne"]);
var classmate2 = New(Person,["George"]);
classmate1.info();
classmate2.info();


这里__init__相当于C++中的构造函数,上面Person定义是不是很像C++的class类声明了?New函数有点奥妙在其中,我们定义New_是为了转接待创建类的原型,为什么要这样转接留给大家自己琢磨。

让JS像C++那样定义类继承关系

继续对JS描述方式做优化,逐步让它长得像C++,我们才好动手用CSE描述它。

function New(aClass,aParams)
{
function New_()
{ if (aClass.__init__)aClass.__init__.apply(this,aParams); }

New_.prototype = aClass;
return new New_();
}

function klass(aBaseClass, aClassDefine)
{
function klass_()
{
for(var member in aClassDefine)
this[member] = aClassDefine[member];
}

klass_.prototype = aBaseClass;
return new klass_();
};

var Person = {
__init__: function(name)
{ this.name = name; }

info: function()
{ print("name:" +this.name); }
};

var Student = klass(Person, {
__init__: function(name,No)
{   Person.__init__.call(this,name);
this.No = No;
}

info2: function()
{ print("name:" + this.name+ ",No:" + this.No.toString()); }
});

var classmate1 = New(Person,["Wayne"]);
var classmate2 = New(Student,["George",11]);
classmate1.info();
classmate2.info();
classmate2.info2();


klass函数用来组织派生类的内容定义,实际就是将基类与新定义的派生类进行内容合并。上面我们用“Student = klass(Person,{ ... } )”的形式指明基类(Person),在花括号内定义派生类新增的函数,最后得到派生类Student。

经过前面改造,我们让JS代码长得很像C++了,如果大家还有别的更好方案,不妨告诉我一下。

用CSE模拟JS的类定义

把上面代码改用CSE表达,New与klass函数是公共基础函数,我们先不管。

Person as klass(TObject, {
__init__: lambda: name,
me.name = name;
end;

info: lambda:
print("name:" + me.name);
end;
});

Student as klass(Person, {
__init__: lambda: name,No,
INIT_CLASS(Person,name);
me.No = No;
end;

info2: lambda:
print("name:"+ me.name + ",No:" + me.No.toString());
end;
});

classmate1 as New(Person,["Wayne"]);
classmate2 as New(Student,["George",11]);
classmate1.info();
classmate2.info();
classmate2.info2();


让TObject成为所有仿真JavaScript实体的基类,一些通用的函数,如类型比较要在这个类中定义,这样,我们新定义的Person类要从TObject继承,Student类要从Person继承。

对比前面CSE代码与JS代码,不难看出这两者之间具备一一对应的直译关系,用CSE模拟JS不再困难。至于New与klass函数在CSE中如何实现,限于篇幅,本文不展开介绍,事实上,目前正在开发的CSE-SUPER语言未必就用上面举例的klass与New的方式定义类及创建对象(用CSE脚本还有更简洁的表达方式),本文用来论证语法表达形式兼容C++、CSE、JavaScript的可能性,就这样举例了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐