脚本语言比较:CSE vs Python

 这篇文章是Tiger Dong今年3月份写的,较完整的比较了CSE与Python之间异同,转贴出来供大家参考。

CSE vs Python

Python是一门优秀的脚本语言,CSE无疑也是一门优秀语言,要不,本文不会将它们相提并论的作比较。

事实上,要准确比确两门语言的特性差异不是一件容易的事。因为,既然一门语言能够存在,就有她存在的理由,她总有一些特殊的应用定位。由于定位不同,导致语言比较很难在对等的层面上展开,有谁尝试比较汇编语言与C#的异同吗?----所以,本文尝试比较PythonCSE,首先因为这两门语言的应用范围与表现特征有较高的重合度,可比性有了,其次,从两者的发展渊源来看,CSE是新生语言,从Python继承较多的风格,当然也摈弃了不少东西,比较这两者,不难管窥现今语言的承递脉络与发展趋势。

CSE从推出第一个版本到现在还不到一年,打个比方,她还是一个婴儿,而Pyhton有数十年的发展历史,已经是个中年人了。两者在语言成熟度、应用广泛度、拥有资源丰富程度上,都存在很大差距,这是显而易见,不是我们比较的重点,本文更多的从核心语法语义上对比,也即重点比较两门语言的内涵,而非外延,新生语言的外延若假以时日,外部条件也具备了,总能很快抺平与他人差距的。而内涵相对稳定,如果核心语法有了很大改变,那可能演生出一门新语言,语言比较所假定的基础不存在了。

现在比较CSEPython就可能存在这个风险,还不是因为CSE尚处于快速发展中,更重要的是,CSE将适应语言发展变化当作她固有的一个特性,她好比是一部强大的进化机器,核心语法语义演化不只被认为可能,而且被认为是应该,或者说是必然。本人时隔3个月再次试用CSE新版本就大吃一惊,prop属性、yield产生式、测试脚本自动生成等令人惊异的特性好似一夜之间突然冒出来的。所以,本文不只比较CSEPython的语法差异(否则一两年后这篇文章就成垃圾了),也比较两者的行事风格、运作模式、商业定位等方面的异同,有赖于与CSE缔造者wayne chan多年朋友关系,本文获得一些独家内幕消息,希望能给大家提供一点帮助。

CSEPython的总体感观差异

CSE具备两面特性,她的第一面是脚本语言,另一面是编译语言,某种程度上说,前者是软语言,后者是硬语言,前者更富动态变化,或者说具备有机体特征,而后者是命令式架构,缺失一些变化,但具有更强的能力与更高的运行性能。拿wayne chan本人的话来说,他希望CSE是狮身人面像,在古埃及,狮身人面像被认为是智慧与权力的象权,CSE具备LISP语言特征,展现拥有人的智慧一面,同时还具备命令式语言特征,展现如狮子般敏捷与强大的另一面。

这种两面性是CSE区别于其它语言的本质特征,可以说,CSE相比于Python,多数差异都源于此,把握住这一点就能很好理解什么是CSE了。CSE人面已揭开面纱了,遗憾的是,狮身还无缘谋面,CSE编译器还没开发,我们无从揣测其特性。

CSE的脚本表述方式与Python比较接近,函数、类、模块的组织方式很类似,一些命名风格,如系统保留命名__init____del____str__等都是一致。两者的外在脚本表现较接近,但内在的体系架构却存在天壤之别,可以说,CSE相比Python,外在表述的创新远逊于其内核组织机制的创新,外部创新甚至有点归于平淡。另外,试用过CSE后不难感觉她的行事风格与Python还是有很大差别的。

比如,CSEGUI界面是与生俱来的,第一个CSE版本发布时,IDE(集成开发界面)就已经比较完整,CSE的扩展模块还很少,但单元测试框架、跨进程MVC布署框架却已具备了,CSEIDE还完整的支持单步调试功能。Python是另一种风格,先有命令行界面,集成IDE是后加的,而且其风格相对于内核比较另类,随正式版本发布的Python GUI(即IDLE)是用TCL/TK做的。这些差异,我们还不能简单的将之归结于初创者个人风格的差别,更多的,我们应理解为时代的差异,有人将前者称为Windows风格,使用风格倾向于终端用户,而后者称为Unix风格,使用风格倾向于开发者。毕竟时代变了,Python产生于上世纪80年代,那是UnixDos盛行的年代,CSE产生于21世纪初,是一个强调个性与客户体验的时代。

再如,CSE还专注于为软件研发过程提供配套服务,而不只是提供一个执行器,Python软件缺少这种工程化思路。CSE推出第一个版本就宣称支持第4代白盒测试方法(4GWMThe 4th Generate White-box-testing Methodology),CSE后续版本还将内嵌XML解析器,注意,不是简单扩展出一个能解析XML的模块,而是直接使用CSE内核封一门可解析XML的语言,本质上说,CSE语言也是CSE内核的一种实例化实现,有点类似于.NET平台,CLR是核心平台,C#VB.NET等是都是它的实例化实现。当CSE体系有了CSE执行器与XML执行器这两根支柱后,在IT工程服务方面必能大展身手,.Net号称是基于XML信息集成的系统,它的XML支持仍属外在扩展,当然这也没有太多坏处,只是某些内嵌紧耦合的应用无法支持,比方,CSE集成XML后,实际模糊了代码、文档、规格化数据三者之间的界限,无论对代码文档化,或文档代码化,还是UML表述及MDA转换支持,都是非常便利的。所以,仅此一点而论,CSE.NET具有更高的起点,.NET使用XML保证了静态集成性,而CSE除静态集成性,还拥有更多的动态(或在线)集成特性。

以上两点是本人初次接触CSE就有深刻体会的,除此之外,我们形而上的概括,CSEPython更加FPFunctional Programming),Python的语法分析与字节码机制中尚保留强烈的命令式语言特征,CSE语法分析及解释执行增加不少生命气息(这个提法较抽象,不要紧,下文还有叙述),操作符与命令字(或称保留字)都是在线可定义的,不是语法分析固定规定的。

由于这个原因,CSE语法表达显得非常灵活,当然,过于灵活不见得都是好事,一些不合规范的CSE脚本,解释器并不认为它是错的,这导致一些错误引入后不容易被发现。不合语法规则的脚本,许多时候CSE解释器只是忽略它,或者直接返回一个缺省值,并不报错。Python具备更多命令式风格,比较明确的限定哪些语句是合法的,哪些非法,能够检测的语法错误也就更多。比如下面2CSE语句:

raise EMyError, 'Here raise error.';
raise(EMyError, 'Here raise error.');

这两个语句都是合法的,第一条CSE把它看成两个表达式,等效于“raise(EMyError),'Here raise error.';”,第二条CSE能正确解析成raise调用,很显然,这两个语句的执行效果不同的。

CSE核心语法过于灵活,相比其它语言更容易误用,比如:

iValue = 0;
if iValue == nil:
  print('OK');
end;

>>> executing script...
ESyntaxError:Error at line 586, LNotator(if) not closed.

上述报错多少有点让人摸不到头脑,分析一下,错误发生在nil误用了,因为nil注册为变元操作,变元操作可以有如下书写格式:

>>> nil     # same to nil()
0
>>> nil()
0
>>> nil(0)  # careful, nil not same to 0, but "nil == 0" is true
0
>>> nil: 0; end;

0

因为变元操作可以写成以“:”开头、“end”结尾的语句块,所以前面报错是因为nil吃掉其后从“:”“end”的语句块,使得if语句无法正常结束。上面例子若按CSE推荐格式,应写成:

iValue = 0;
if nil(iValue):  # or, you can write "if nil == iValue:" as you like, but it is not same meaning
  print('OK');
end;

>>> executing script...
0

nil类似用法的还有dummy关键字。

CSEPython的核心语言要素差异

CSEPython一样,都是一门解释执行、动态交互、面向对象的编程语言,集合了模块化结构、异常处理、动态类型、高度抽象动态数据类型、类与类继承等特性。下面我们重点比较两者异性,相同之处只稍微提及,不展开说明。我们分如下五个方面展开叙述:

²        编码风格

²        数据类型

²        函数定义

²        类与模块

²        扩展接口

先讲编码风格,两者的指令风格、保留字设置比较近似,他们的注释风格完全相同,都以“#”作为注释起始标记。编码风格差异主要表现在以下几个方面:

1.         行缩进,Python采用行缩进风格,CSE无此要求

Python代码:

if isTrue:

  print 'OK'

else:

  print 'fail'

CSE代码:

if isTrue: print('OK'); end else print('fail');

换行符及每行缩进字符在Python是有语法含义的,在CSE中不具语法含义,换行符在Python中作为语句自然结束标记,CSE中各语句或表达式必须以逗号或分号分隔。两者均以作为语句块起始标记,但Python以行缩进指示语块何处结束,CSE必须明确用end关键字指示。

2.         前后缀风格

Python使用"_"前缀指示变量或函数是否私有,CSE除了使用前缀指示变量类型,还使用“_”后缀指示变量或函数是否私有。之所以要用前缀标识数据类型,是因为CSE要兼容解释执行与编译执行两种运行模式。

3.         构词法

PythonCSE均可用单引号或双引号构造字串,不同的是,Python使用单引号或双引号构造字串不可以跨行,CSE可以跨行。Python要构造跨行字串应使用longstring标记,即起止为连续3个单引号(或双引号)。

Python支持迭代方式构造List数据,比如:[i for i in range(5)]CSE不支持。

另外,CSE中的分号(;)与冒号(:)只是分隔符,语法含义与“,”等同。比如:Python构造字典数据“{key1:value1,key2:value2}”CSE也支持这种书写格式,另外还可以写成:“{key1,value1,key2,value2}”,再如:

tt = (1,2,3);
print(tt);

将上面两行CSE脚本的逗号与分号互换,写成如下样子也是可以的:

tt = (1;2;3), print(tt),

接下来我们看看CSEPython的数据类型差异,CSE中的intfloatstringbuffdict类型与python中相关数据类型一一对应,其中Python中的listCSE中改叫buff了,个人揣测:“l”前缀比较难看,容易与数字1弄混,CSE干脆改称listbuff,用“b”作前缀了。CSEPython主要数据类型差异如下:

1.         CSE放弃Python中的tuple类型,而增加了Tier类型

Python中的tuplebuff都能保存任意类型的数据,两者功能重复了,至少表面上如此(实际上tuplePython中还来表达immutable数据、函数调用参数等)。CSE认为tuple类型并非必须,而且,用户面对tuplelist,到底选择哪一个常有困扰,这个类型毫无悬念的被喀嚓掉了。

同时,Python中的string实际上是字符数组,list实际上是任意类型的数组,int数据最常用,却没有int数组,只能用list去构造。CSE认为这是不充分的,尤其在增加编译支持后,应尽量用int数组代替list数据,int数组直译为数据块,无论加快运行速度还是节约内存空间,都是很有益的,所以CSE语言新增设了Tier类型。

2.         CSEWideInt对应Pythonlong,但CSEWideInt宽度限定于int2倍,而Pythonlong是不限宽度的

3.         CSE新增了IDNotator数据类型

一个变量名或函数名在表达式中计算时,它是变量或函数,但它在描述一种指示体时,是ID类型,ID被计算1次就是变量或函数,或者这么认为,ID域名查找计算0次时的值,而变量或函数是域名查找计算1次的值。

CSE还使用Notator类型表达操作运算,比如“3+5”被描述成<+:3,5>“print(3+5)”被描述成:>,当“<+:3,5>”被计算0次时,它是Notator数据,而被计算1次时,就得到计算结果8了。

NotatorID反映了程序代码的静态特性,把常见的表达式也描述成一种数据,所CSE的表达式是可以自由传递的。Python也提供类似机制,CodeType就是这种运行代码的数据形式表达,不同的是,Python封装这种执行体数据仅让用户可以从中读取一些简单信息,并没有很好的抽象其组成要素并开放出去,即,PythonCodeType还不是完整意义上的可读写的数据类型。

有了IDNotator类型,CSE更象一个可以自我成长的有机体了。下面举一个例子,先定义TRemoteModule

uses:
  'duality.cse';

  'bases.cse';

  'rpc.cse';
end;


class TRemoteModule:

  sPeer_ := '';

  iWait_ := 5000; # 5 seconds

 

  func __init__(me,sPeer,iWait=5000):

    me.sPeer_ = sPeer;

    me.iWait_ = iWait;

  end;

 

  func __get__:

    declare(me,$var);

    if str($var)[-1] == '_':

      setRet(me.$var@1);

    end else setRet(rpc.evalEx(local.(bArg_[0]),[$var],

                                      me.iWait_,me.sPeer_));

  end;

 

  func __set__:

    declare(me,$var,value);

    setRet(value);

  

    if str($var)[-1] == '_':
      me.$var@1 = value;

    end else rpc.evalEx(local.(bArg_[0])=bArg_[1],[$var,value],

                                      me.iWait_,me.sPeer_);

  end;

end;

TRemoteModule用于将本机其它CSE进程映射为本程序的一个类对象。比如当前程注册RPC端口为CseWin,启动本机另一个进程,注册RPC端口为CseClient,假定CseClient程序已定义一个变量sValue,其值为“I am at CseClient.”,之后我们在当前CseWin程序中远读写CseClient中变量sValue

>>> CseClient = TRemoteModule('CseClient')

>>> CseClient.sValue

I am at CseClient.

>>> CseClient.sValue = 'Yes, I know.'

Yes, I know.

>>> CseClient.sValue  # the value should changed

Yes, I know.

这个例子中,读写对端变量的表达式很方便的透传到另一个程序执行了,而且,应用接口封装可以不留痕迹,就象读写远程变量就像操作本地的变量一样。

4.         CSE未支持unicode字串

准确来讲,CSE内核未支持针对unicode字串的相关操作。因为unicode直接面向应用,CSE仅将它理解为字串的特定应用,比如取字串长度调用函数“len(s)”,如果支持unicode或许应增加一个函数“uniStrLen(s)”,应该在扩展库中实现这些定义。Python则是另一思路,把unicode支持合到内核去了。基于相同理由,CSE也没象Python那样支持复数类型。

从中我们不难看出,CSEPython遵循了两种行事风格,CSE尽力维持精简的内核,把内核当成DNA,然后在外围将DNA组装成细胞,根据不同功能制造不同细胞,比方能运载氧气的红细脑,能抵御外敌的白细胞,具有记忆功能的脑细胞等,最后才组合各类细胞制造有机体。所以,CSE内核之上可以封装新语言,不只形成CSE,完全可以仿真CPython等语言。

Python内核处于更高一个层面,它已经是细胞了,库模块type.py记录了Python内嵌的数据类型,除了intfloatstringtuplelistdict等基本类型外,还有Unicode、函数、类、类实例、类方法、lambda对象、文件对象、产生式等30多种类型,这已经是种类齐全的细胞库了。

5.         Python用中括号([])操作字典,CSE用花括号({})操作字典,如:

Python字典操作:

>>> dd = {1:'One',2:'Two'}
>>> dd[2]

'One'

>>> dd[3] = 'Three'

CSE字典操作:

>>> dd = {1:'One',2:'Two'}

{1:'One',2:'Two'}

>>> dd{2}

One

>>> dd{3} = 'Three'

Three

>>> dd{4:'Unknow'}  # if key(4) not exist, return default value('Unknow')

Unknow

CSE的函数定义要比Python复杂,因为CSE函数还同时承担Iter迭代功能,Python的迭代器是后期版本追加的,如果算上迭代功能,CSE函数定义附加的规则与Python相当。这两者都支持缺省参数与变长参数,他们主要差别如下:

1.         调用CSE固定格式函数时,可用“:=”赋值指示函数返回,Python无类似功能

该功能可心让代码书写更加紧凑,比如:

s = 'Coverage:%s, rate:%d';

strJoin(s,',Test passed.');  # return new string length

print(s % ['LICC',95]);

可以改写为:

print(strJoin(s := 'Coverage:%s, rate:%d',',Test passed.') % ['LICC',95]);

2.         Python支持Documentation StringsCSE无此功能

PythonDocumentation Strings常用于函数接口提示,如:

def my_function():

    """Do nothing, but document it."""

    pass

 

>>> print my_function.__doc__

Do nothing, but document it.

3.         CSEIterScript函数可以传递表达式的原始数据,Python无此功能

比如:

func showVar:

 

  declare($var);

  print($var, ":", $var @ -1);

end;

 

>>> iValue = 55;

55

>>> showVar(iValue)

iValue : 55

4.         产生式定义

CSEPython的产生式都按无堆栈计算方式实现,两者都以yieldreturn指定产生值,用法也相同,两者都支持在异常处理语句中(try..except..finally)返回产生值。两者也都支持在for语句及迭代器对象(CSETIter类,Python中是generator对象)中调用产生函数。

CSE中函数未尾的yield并非最后一次返回,而在python中是最后一次返回,如CSE中:

func test:

  declare(i);

  yield i;

  i = i + 1;

  setRet(i);

  yield i + 1;

end;

 

>>> for i in test(3): print(i); end;

3

5

4

Python中:

def test(i):

  yield i

  i = i + 1

  yield i + 1

end;

 

>>> for i in test(3): print(i)

3

5

for语句之外取产生值的书写方式两者有差异,在CSE中:

>>> test(3)

[3,5,4]

>>> IterObj = TIter(test,3)

>>> IterObj.next()

3

>>> IterObj.next()

5

>>> IterObj.next()

4

>>> assert( dummy(IterObj.next()) )

1

CSE中以TIter类实例包装迭代器,而Python采用一次调用赋值得到迭代器,CSE中一次调用产生式函数得到产生值列表,在Python中要用list函数调用得到产生值列表。另外,CSE的迭代器对象在迭代调用结束后,再取产生值得到的始终是dummyPython在迭代结束后再取产生值引发StopIteration异常。如:

>>> list(test(3))

[3,5]

>>> IterObj = test(3)

>>> IterObj.next()

3

>>> IterObj.next()

5

>>> IterObj.next()

Traceback (most recent call last):
  File "", line 1, in ?
StopIteration

5.         操作符与保留字定义

CSE中定义一个函数后,可以将该函数注册为一元、二元或多元操作,也可以注册该函数为编程语言的保留字(如ifelsereturn等),Python没有这种动态定义新语法的功能。我们取duality.cse中的代码作说明:

func `%`(v1,v2):
  iType1 = type(v1);
  if equal(iType1,iIntType):
    setRet(intMod(v1,v2));
  end else if equal(iType1,iStrType):
    setRet(strFormat(v1,v2));
  end else raise(ETypeError,'Type mismatch in operator:%');
end;

registDuality('%',65);

这里按常规语法义定义一个取余函数,再将“%”注册为二元操作符,其优先级为65。然后,下面语句就可以正常执行了:

>>> 5 % 3

2

>>> 'Coverage:%s, rate:%d' % ['LICC',95]

Coverage:LICC, rate:95

定义一元操作符,如:

>>> registUnary('print',1)

0

>>> print 'Coverage:%s, rate:%d' % ['LICC',95]

Coverage:LICC, rate:95

0

上面将print注册为一元操作,设为优先级为1,因print函数已存在,这里不须重复定义它。之后,我们就可以象Pythonprint语句一样使用了,不必非得按函数方式。

定义Notator命令字,如:

>>> registVariety('lambda',0)

0

>>> i1 = 3; i2 = 4

4

>>> lambda: i1,i2; (i1 < 3) or i2; end

4

前面例子我们演示的lambda是普通函数调用,这里,将lambda注册为变元操作符后,我们既可以象普通函数一样调用它,也可以用类似ifelsewhile等句式,即,以“:”开启语句块、以end结束语句块的方式调用它,lambda成为编程语言的关键字了。

介绍过函数定义的差别后,我们再来分析两门语言在类与模块方面的差异。尽管Python支持类与类继承,但对完整的类封装概念来说,是不够完整的。CSE尝试提供完整的类封装与继承,对比这两者,除了Python支持多重继承,CSE只支持单继承外,Python在类特性可以说只是CSE的子集,下面我们罗列主要差异:

1.         CSE解决了Python可见性倒置问题。

如下Python代码:

class T1:

  def getName(self):

    return 'George'

 

  def test(self):

    return self.getName() + ' is wonderful.'

 

class T2(T1):

  def getName(self):

    return 'Peter'

 

  def show(self):

    print self.test()

 

>>> v1 = T1()

>>> v1.test()

'George is wonderful.'

>>> v2 = T2()

>>> v2.show()

'Peter is wonderful.'

所谓可见性倒置,是指基类中函数定义被继承类下同名函数定义覆盖,如上例,基类T1下的方法test调用后打印“George is wonderful.”,该方法被T2继承后再调用,打印结果却不幸被篡改成“Peter is wonderful.”。也就是说,设计T1test函数时,设计师并不假定他当前调用T1.getName方法会发生意外,而事实上T2类定义时因不小心因同名将基类中函数屏蔽了。

可见性倒置破坏了类对象封装性,基类已固化的函数不应看到(或调用)继承类中的函数。如果程序逻辑需要这么做,那是回调函数的设计思路,规划基类时就应预留接口了,比如:

class T1:

  def __init__(self):

    self.getName = self.getBaseName;

 

  def getBaseName(self):

    return 'George'

 

  def test(self):

    return self.getName() + ' is wonderful.'

 

class T2(T1):

  def __init__(self):

    self.getName = self.getNewName;

 

  def getNewName(self):

    return 'Peter'

 

  def show(self):

    print self.test()

CSE的类方法域名查找总与定义它的class类相关联,解决了这个问题。

2.         CSE支持可持久化的类属性,Python无此内容

CSE提供一种函数化的属性操作,类似于Pascal中的“property xxx read getXX write setXX”,如下:

class TT:

  iValue_ = 0;
  sValue_ = 'example';

 

  prop iValue(me,value=nil):

    if nil(iValue):

      setRet(me.iValue_);

    end else:
      me.iValue_ = value;
      setRet(value);

    end;

  end;

 

  prop sValue(me):
    setRet(me.sValue_);
  end;

end;

>>> v = TT()

>>> v.iValue
0
>>> v.iValue = 3
3
>>> v.sValue
example
>>> v.sValue = 'abc'  # TT.sValue is readonly
EArgsError:sValue expect 1 arguments, but 2 passed.

把类属性定义成函数调用方式,可以方便的为属性存取过程添加特定控制,同时,也便于操作接口变得持久,维护的需求可反映在prop函数定义上,接口能一直维持稳定,JAVA持久化技术也采用类似方案,JAVA持久化类包含特定的getXXsetXX方法,用于属性读写控制。

从上面例子还看出,CSEprop定义可用于只读属性控制。

3.         CSE提供protected方法继承,Python未支持,如:

class T1:
  intValue_ := 95;
  strValue_ := '';

  prop showMsg_(me,sName):
    print('%s got score:%d' % [sName,me.intValue_]);
  end;

  prop sValue_(me):
    setRet(me.strValue_);
  end;

end;

class T2(T1):
  func test(me):
    me.showMsg_('George');
  end;
end;

>>> v = T2()

>>> v.test()
George got score:95
>>> v.showMsg_('george') # should raise error
EAttrError:Attribute not exist:showMsg_

上面showMsg_函数在T1及其继承类T2类定义中可见,但在外部不可见。大家或许会问,私有命名的prop函数在继承类可见,是不是破坏了封装原则,如上例sValue_希望在继承类不可见,遇到这种情况只需将prop函数改成常规函数,丝毫不影响其功能实现。

4.         CSE解决了Python中保留方法__get____set__嵌套循环的问题

拿前面TRemoteModule的例子,__get__函数定义如下:

class TRemoteModule:

  sPeer_ := '';

  iWait_ := 5000; # 5 seconds

 

  func __init__(me,sPeer,iWait=5000):

    me.sPeer_ = sPeer;

    me.iWait_ = iWait;

  end;

 

  func __get__:

    declare(me,$var);

 

    s = str($var)

 

 

    if s == 'sPeer_':

      setRet(me.sPeer_);

    end else if s == 'iWait_':

      setRet(me.iWait_);

    end else setRet(rpc.evalEx(local.(bArg_[0]),[$var],

                                     me.iWait_,me.sPeer_));

  end;
end;

__get__函数截获TRemoteModule类对象取成员的操作,但如果__get__函数中也有取自身成员的操作呢?如上面脚本中,“me.sPeer_”“me.iValue_”属于这种情况。是不是再次调用__get__函数呢?若是,就进入无限递归了,Python是按无限递归处理的,CSE附加特别控制,__get__函数尚在运行中是不会重复进入__get__递归调用的。

Python__set__调用也存在类似问题,CSE规避了此情况。

5.         模块与类之间的关系

Python中的模块与类是按两套机制实现的,两者之间不能自由转换,CSE中的类与模块按同一机制实现,如:

class TT:
  ValueInTT = 100;

  func testFunc():
    print('function testFunc() in TT');
  end;
end;

 

>>> uses TT
{ValueInTT:100,testFunc:}
>>> testFunc()
function testFunc() in TT

一个类定义可以改用作模块,这一特性使CSE具备更优良的可组合特性,比方打包编译,多个脚本模块可以无歧义的并成成一个模块,原模块定义归并到新模块的一个类定义下。

最后,我们再介绍CSEPython的扩展接口差异。CSE也像Python一样,提供多种语言扩展接口,既可以用C/C++实现API扩展,也可以用Delphi或其它高级语言做扩展(CSE有计划要支持C#VBA的接口扩展),CSEPython都既可以将扩展命令嵌入到脚本系统中使用,也可以将脚本系统内嵌到其它由C/C++/Delphi等开发的系统中。总体而言,CSE的可扩展性要优于Python,表现在如下方面:

1.         CSE扩展函数中多线程处理比Python要简单

CSEPython都使用全局锁保证同一时刻仅一个脚本线程在执行,比如在C语言程序开发中,创建一个新线程要调用脚本解释器,Python要求初始化该解释器的线程控制块,比较复杂。而在CSE,只须调用一个API函数,如:

Cse_lock(1);
// do something call script system
Cse_lock(-1);

在这两个Cse_lock之间的语句运算CSE脚本都是线程安全的。CSE释放解释器控制权也用到这个API,比如:

i = Cse_leave();
// do something out of script system
Cse_lock(i);

Cse_leave用于释放当前线程对脚本解释器的占用,Cse_lock用于重新获得对解释器的控制权。

2.         使用C/C++扩展一个Python内嵌模块非常复杂,而CSE简单多了

这是两门语言采用了不同机制决定的,Python抽象出不少操作在基础类型定义(PyTypeObject)必须处理,而且Python的模块结构与类结构是两套机制,用户要深入了解其类型格式才能胜任扩展工作。CSE的类与模块使用同一套机制,而且都以字典类型保存,定义一个类对象并不附加特别类型结构。所以,在CSE中用编译语言扩展一个模块非常容易,根据实际经验估算,开发一个规模不大的扩展模块,在CSE中要比Python中快出四、五倍。

举个例子,如下脚本类定义:

class TTest:
  func test(me):

    print('OK');
  end;

end;

若改用Delphi定义它,框架代码如下:

function TTest_test(me:PCseObj):integer; stdcall;
begin

  // to do: define TTest.test
end;


Class_TTest := Cse_NewClass('TTest',CseNilValue); // class TTest: end;

Cse_RegistApi(Class_TTest,'test(me)',@TTest_test,ctFrmtStdcall);

再把TTest类定义放到某模块下(比如MyModule.csb):

MyModule := Cse_NewClass('MyModule.csb',CseNilValue);

Cse_SetRefSpace(Class_TTest,CseBltinModule); // uses '__bltin__.csb'

key := Class_TTest.entry^[1].value;

CseDict_set(_CompilerClass,key,Class_TTest,key.count);

大家感觉一下,是不是很简单。

到这里,CSEPython核心语法的主要差异已介绍完毕,需要强调的是,CSE相对Python,对语言要素的改良多过创新,除了类封装与继承有较多改进外,其余基本上是对Python做优化。毕竞Python产生于上世纪80年代,其体系架构成形后就很难推倒重来了,CSE没有历史负担,可以站在更高起点大胆往前走出一步。实际上,就编程语言的表现形式而言,很难再有多少创新了,C#是一门伟大的语言,也只是将现有数种语言的优点揉合一起而已。

CSE最大亮点应在内核架构上,从词法分析到语法分析,再到语义分析,在常规编程语言中是不可分隔的整体,牵一发而动全身,很少有语言新增关键字而不重写语法分析的。毫无疑问CSE做到了,其内核具有化腐朽为神奇的力量----所有CSE控制结构,包括ifelsewhilefortryexcept等,都是外部扩展的API,立体式的语法分析过程被改造成平面式条条块块,各个语法要素可以象积木一样组装。大家不妨阅读CseCompiler的源码,所有控制语句都在BltinFlow.pas中定义,区区数百行代码就搞掂了。

CSE似乎理顺了“鸡生蛋,蛋生鸡”自我进化的最佳路径,常规编程语言是看管着长大的,在外力作用下,可以推倒重来。但如果改成自我进化,就是另一种要求了,首要一点是:进化的演变过程不能中断。1.5亿年前的始祖鸟只能在树间跳跃滑翔,而现在的北极燕鸥来回迁徙一次,飞行4万公里,能绕地球一周了。进化的力量如此强大,但我们不能因为始祖鸟的羽翼比较原始,把它杀了重造一个,或者,把蛋拿过来改一改让它变凤凰。破坏性重构不是有机体的生存之道,CSE最大的创新主是:她很好的解构了编程基本要素,把语言重构需求限定在局部范围。

CSEPython的版权与商业运作模式差异

Python2.1版本开始完全采用与GPL相兼容的开源协议,这是近乎公共域的授权许可,允许免费修改、免费二次发布,而且对商业应用比较友好。CSE除解释器内核(CseKernel.csd)外采用MPL授权,也允许自由获取源码,允许免费修改、免费二次发布,但要求修改后的代码版权归CSE共享软件基金会,CSE的授权形式对商业应用是友好的,甚至,CSF基金组织鼓励商业机构使用CSE

MPL中对“发布”的定义是“以源代码方式发布的文件”,意味着MPL允许一个企业在自己现有的代码库上追加一个接口,以这个接口作阻隔引入开源代码,除了接口程序的源代码要以MPL形式对外授权外,产品自身代码就不必按MPL要求强制对外开放。所以,商业应用CSE软件是安全的,即便是CSE内核,由《CSF软件最终用户许可协议(ELUA)》规定,内核模块是免费使用、可自由传播的,因为CseKernel.csdREDIST列表之中。

Python的版权形式比CSE要宽松,CSE采取多种授权的策略,为开发者保留了更多权益。其中,CSE内核以共享软件形式提供,用户得不到源码,按作者的话来说,这是为了维护CSE核心语义纯粹性,我们不妨解读为:作者保障大家自由使用CSE的权利,但不希望商业机构重写内核,掺和搅局。

业界开源组织采用MPL授权的,许多情况是因为还没想清楚以后如何发展,CSE似乎有此考虑,她没打算从CSE语言(包括内核)获得收益,但不排除要从CSE的附属产品(比方相关工具软件)获取回报。另外,CSF全称是“CSE Shareware Foundation”,而不是“CSE Opensource Foundation”,也喻示着CSF组织对依赖社会捐赠的模式并不抱十足信心,一方面因为国内开源氛围没法乐观,另一方面,CSE是一个庞大的系统工程,没有充足资金支持是很难发展的。

Python不同,Python完全依赖社会捐赠,CSE走的是一条“具有中国特色”的开源之路,目前CSE扩展模块还很匮乏,CSF并不急着把应用库丰富起来,而是采取稳扎稳打的策略,在良好规划系统框架的前提下,由实实在在的商业应用带动内容建设,用到什么就先开发什么。WAYNE工作室作为CSE发展策略的载体,不只自己开发一些基于CSE的应用,也协助业界开发上层应用,借此方式逐步丰富CSE的内涵。

 

你可能感兴趣的:(编程语言,语言,脚本,python,class,扩展,lambda)