作者自述CSE语言设计思想(七)----CSE-Super语言设计思路(上)

来源:互联网 发布:淘宝商城女装新款冬装 编辑:程序博客网 时间:2024/05/05 17:17

本文从设计角度剖析CSE-Super语言的定位及几项关键特性的设计思路。如果您第一次听说CSE-Super语言,不妨先阅读前一篇博文《CSE-Super语言概貌》。

 

 

CSE-Super语言设计定位

CSE-Super是一种定位于拉通原生应用(Native App)与Web应用(Web App)这两类程序设计的新一代编程语言。

Super是“超越”的意思,无论NativeApp走向WebApp,还是WebApp走向NativeApp都需实现很大跨越,我们用Super来命名,希望它将Native程序开发与Web程序开发真正融合起来,实现超越。

Super还有“超级”的含义,我们也希望它成为超级棒的编程工具。在设计了CSE-C、CSE-C++、CSE-C#语言集后,我们顺理成章、驾轻就熟的设计了这门语言,它集“简单”与“高效”于一身,是CSE技术体系中首推的语言集。

Super的首字母(大写S)是CSE-Super语言的幸运符,你能看到这门语言中不少定义以S开头,如SInt、SFloat、SStr等,选择器也以一个大写的S字母来表示。

 

 

选择器及“以物件为中心”的编程

选择器(Selector)是实体(Entity)的集合,实体是Super语言编程中,从应用角度去看的基本元素,比如一款游戏程序中的一只小鸟、一座房屋、一个英雄等,是大家可理解、可想像的“物件”。在多数编程语言中,这些物件用一个个变量去表示(是否为可想像的物件是应用层面考虑的东西),但在Super语言中,物件是由系统参与管理的一种实体。

按理说,应用层面的东西不应设计成语言的核心要素,Super语言这么做,主要为了简化软件设计,让编程能更好的围绕可理解、可想象的物体来展开,比如下面代码创建“石头”实体:

super Stone:  D2: D2(),  Canvas: Canvas(),  color: SColor(),end;stone as Stone();stone.D2.setRect(SRect.c(100,100,50,50));stone.D2.setSceneLevel(0,0);

首先定义数据类型Stone,然后用这个数据类型创建“一块石头”,最后两条语句给这块石头的属性赋值。这种基于变量的编程风格是所有编程语言中最常见的,CSE-Super当然也支持这么写,如果我们把思考问题的习惯改成“以物件为中心”,代码可能写成这样:

superStone:  color: SColor(),end;S.e("D2,Canvas,Stone")  .each( super(me):    me.D2.setRect(SRect.c(100,100,50,50));    me.D2.setSceneLevel(0,0);  end);

“以物件为中心”的设计,既从应用角度思考问题,石头是看得见、摸得着的东西,围绕它想问题很自然,同时,它也从设计角度看问题,与“如何编码实现”挂钩,如上,重用已有定义(D2与Canvas)是这种思路, “S.e("D2,Canvas,Stone")”用来创建一个实体,重用已有的D2(表达二维空间)与Canvas(画布)定义,增加Stone专有定义,这就确定了我们新物件的架子。随后围绕这个新物件,展开一系列操作,比如我们再增加若干语句:

superStone:  color: SColor(),end;for i in range(20):  S.e("D2,Canvas,Stone")    .bind("remove",super(me):      me.D2.setVisible(0);    end)        .each( super(me):      me.Canvas.bindImage(stoneImage);      me.D2.setRect(SRect.c(100,100,50,50))        .setSceneLevel(0,0);    end)        .each( super(me):      me.Stone.color = SColor.c(255,50 + i,0);      ## wait to do: fill stone color      ## ...    end)  ;end;

上面代码用来创建20块颜色渐变的石头,由于“S.e()”调用返回Entity实体,其后Entity.bind()语句可以连写,bind调用仍返回当前实体自身,所以,其后Entity.each语句仍可以接着连写,不必非得借助变量指明被操作主体。就像我们平时说话,“我吃早饭,然后坐车、上班”,很自然,如果非得这么说,“我吃早饭,我然后坐车,我然后上班”,别扭死了。

选择器(Selector)用于从已创建的实体中,选择符合条件的集合,针对这些集合可进行批量操作,比如:

S("Stone").exit();S("D2,Canvas").D2.setVisible(true);S("D2 | Canvas").exit();

这3条语句分别是:选择所有含有Stone定义的实体、选择同时定义了D2与Canvas的所有实体、选择定义了D2或Canvas的所有实体,然后进行批量操作(属性读写或类方法调用)。

用实体与选择器来组织编程对象,体现了Super语言贴近终端应用的特点,另外,动态创建的实体被缓存,还优雅的解决了闭包函数容易导致的内存泄露问题,后文有论述。

 

 

表达风格

CSE-Super除了具备CSE脚本的常见表达风格外,它还比较“紧凑”,如前面介绍连写方式在Super语言中大量使用,读写属性常用函数调用的形式,比如用“D2.visible()”查看visible属性是true还是false,用“D2.setVisible(isVisible)”设置该属性,设置属性的函数调用返回值都是组件自身,所以连续设属性可以连写,显得比较紧凑,比如:

me.D2.setRect(SRect.c(100,100,50,50))   .setSceneLevel(0,0)   .setVisible(0);

紧凑风格还体现在用Super语言容易将上下文相关的变量及函数过程定义放在一起,与javascript类似,基于原型、闭包等若干特性支持了这种风格,不赘述。

轻便”是Super语言另一种风格,在面向对象方面它与JavaScript非常接近,利用prototype轻便的组织对象化数据,比如:

super MyClass:  iValue_: 5,  rect: SRect(),   test@0: super(me):    print("in test()");  end,  globalName@0: "example",end;
上面定义MyClass类,SRect是用来表达矩形的class类(定义x、y、width、height属性),iValue_与rect是两个类成员,test是类方法,globalName是静态类成员。我们用“@0”后缀区分某个符号注册为类成员,还是注册到prototype中。

“<<<”操作可以给类对象的多个属性赋值,如:

obj as MyClass();obj <<< super:  iValue_: 10,  rect: super:    x:0, y:0, width:20, height: 20,  end,end;
这种表达方式与JavaScript的JSON风格近似。

Super语言不支持多态性,它要求用“明确、直接”的方式调用函数,这也形成Super语言的一种编程风格。比如下面3个函数定义:

SRect.moveTo(topLeftas SPoint):SRect;SRect.moveXY(left as SInt, top as SInt):SRect;SRect.moveBy(detaX as SInt, detaY as SInt):SRect;
若换成C++编程,大家倾向于把前两个(moveTo与moveXY)改用多态函数,都命名为move函数。这两种风格各有优劣,多态函数貌似减轻编程负担,其实C++编程中,大家调用“SRect.move”时,仍会想着它与哪几个多态函数相关,实际会调用其中哪一个,编程负担仍在。Super语言强调以直接、明确的方式定义函数,函数接口明确、无歧义,C++的const修饰、传值或传引用、operator Type操作符重载等机制都加重了产生语法歧义的机率,Super语言避开这些容易导致歧义的因素。当它成为一贯风格,编码体验其实还是不错的。

 

 

强制类型转换

类型转换保证了C/C++语言的灵活性,但也是一处乱源。Super语言支持类型转换,但对它有所控制,其一,消除指针的概念,这也是脚本语言通用做法,脚本语言自动管理实体的生存周期,指针方式过于灵活,会破坏引用计次的管理机制。

其二,Super语言以更明确的方式描述类型转换,它只支持“类型调用”这一种表达方式,比如:

buff as SBuff();buff.push(SRect.c(0,0,20,20));buff.push(SRect.c(20,20,20,20));rect as SRect(buff[0]);assert(rect.x == 0 && rect.y == 0);rect = SRect(buff[1]);assert(rect.x == 20 && rect.y == 20);
一个用户自定义数据类型(与C++中的struct/class概念对应),不带参数调用是创建类实例,带一个参数时含义固定为“强制类型转换”。如上面代码中,“buff[0]”的数据类型是SObject,把它转化成SRect类型就用“SRect(buff[0])”。

Super语言中除SInt、SWint、SFloat、SStr等几种基本类型的强制转换可以是“值”变换(比如SInt("35")会把字串转成int值),其它都是“引用”变换,把指定数据从一种类型看作另一类型,数据内容不发生变化,变换前后是同一份数据。Super语言的强制类型转换,属非Copy风格(none-copy style),很明确,不像C++,受构造函数与operator操作重载影响,Copy或不Copy没那么明确,编程时要经常查手册。Super语言中Copy风格的转换要明确定义专用函数,函数名指出是什么转换,比如:

SRect.copy():SRect;SRect.center():SPoint;

类型调用在C++中是构造调用的含义,创建一个类对象使用此方式,Super语言中,不带参数的类型调用是构造调用(即创建一个新对象),带一个参数是强制类型转换,如果带若干参数创建类对象,要用静态类方法,如:

SRect.c(0,0,20,20)

函数名“c”是“create”缩写,因为很常用,我们用缩写效率更高些。这个函数译为C++,原型为:

static _SRect _SRect::c(const SInt& x, constSInt& y,                       const SInt&width, const SInt& height);
这也是一种明确的语言风格,当你有多种对象构建方式时,就用函数名指出各个方式,如“SRect.createByXXX”、“SRect.createFromXXX”等形式。

介绍到这儿,我们不难看出Super语言有个设计原则:人使用工具,而非被工具奴役。大家埋怨C语言,是因为它没有面向对象特性,反感C++,是因为它太过复杂,如孟岩所说,“如果你真的是用C++,那理论必须得强。因为它有个毛病,很难完美降级,如果你不太懂,用着用着就可能给系统埋雷”。用C++继而被它拖累,看来是不得已的事,Super语言提倡简单,拒绝复杂,远离花哨,学习CSE-Super,两三个月就能成为高手,但用C++,没有三年、五年,请不要轻易说自己是编程高手。

 

(未完,待续)

 


原创粉丝点击