由于人的月历和知识的有限性,性能和开发效率的矛盾,一门语言的发明者不可能满足所有程序员的要求。随着高级语言的普及,那些不满于现状的程序员们会越来越多的选择定制自己的语言,当然我这里不是说想Lisp那么干,而是真正的从语言特性上定制。
说到这里,就不得不提及语言特性优劣该如何量化问题。简单的说就是我们该怎么判断一门语言的某个特性是优秀的还是表现一般呢?对于主观性很强的问题往往难以量化。我个人的量化标准是它对实际问题的抽象程度,抽象度越高越慢、越高级、越智能、开发效率越高。
比如C语言的for循环,相较于汇编的jump或者loop,抽象程度更低,它封装了更加抽象的循环过程——人们日常计数的行为过程:起始点,终点,步长,每次计数后干点什么。功能都可做到一致,但是表达方式的变化对于人们的理解有很大的影响。
这里出现了人们的日常行为,我觉得很重要,如何将底层的操作抽象成人们熟悉的日常操作行为是语言设计的重要问题。
另一个问题是如何将智能引入到语言本身,比如类似Object-C的智能垃圾回收,这个我觉得将是下代高级语言的发展方向。
为了简洁化描述,这里以lua为参考对比描述,没有申明的地方就和lua一样,参见《Programming in Lua》。有时间就不断补完,闲下来就自己试着写这个语言的解释器,首选还是用C来实现。另外影响动态类型语言编程快感的最大问题之一就是难以设计智能IDE,我打算将强制类型用一种巧妙的方式嵌入到语法中,专门为IDE设计铺路,概念有点类似于IDE引导。
代码块
基本相同,但是同时又如同vhdl一样可以为代码块给一个名字,下面给出一个例子以示区别:
1 2 3 4 5 6 7 8 9 10 11 |
do block_outside ... do block_inside ... do ... end ... end block_inside ... end block_out |
特殊符号
字符串
用中括号包围字符串如:
1 2 3 |
str = [hello world!] # unicode编码,支持中文对象名 字符串 = [content...] |
这个不同于以往的语法,意图明显,更容易判断字符串的开始和结尾,即使类似下面的情况也无需使用转义符:
1 |
str = ["hello [out] world!"] |
这样就不用纠结于普通字符串的转义问题了。比起输入双引号的语言,省去按shift键。
在字符串中嵌入代码:
1 2 3 4 5 6 |
in = [test] str = [show @in content] # 嵌入代码块 str = [show @(in + str) content] # 大括号不返回值 str = [show @{ a = 10, a++ } content @a] |
这个思想和C#的Razor引擎一样。比起Ruby的做法更加智能简洁。@比#键离shift更近。
重定义
任何运算符都是对象,都可以通过系统提供的对象接口重定义。提供内部的语法系统接口。
字典对象
这个的定义由于字符串占用了中括号,而代码块又没有像C语言那样使用大括号,于是定义像如下这样:
1 2 3 |
a_01 = { 1, 1 } a_02 = { [string], 2, 3 } a_03 = { 0: a_02, key: [value], 5, 8 } |
循环
不使用for、while、do之类有歧义的关键词,对初学者不太好理解。循环只用一个关键词loop。虽然比for多一个字母,但循环关键词使用的次数并不像变量和函数那样频繁。就像ruby的宗旨那样,语言应该像说话一样,简洁而易于理解记忆。输出不是print,而是echo,以例子说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
loop i from 2 to 17 by 1 do echo i end # 效果同上,单行可以省略end关键词, 如果i没有定义,则使用默认值0,步长默认为1或-1 i = 2 loop i to 17 do echo i # 键值遍历,这个有点像php,by会自动判断后方的对象,然后选择适当的方式遍历 a = {[string], 7, key: [string] } loop a by k: v do echo k, v # infinity是系统对象,无穷大值。loop也对自动判断后方对象,选择适当的方式循环 loop infinity do echo [str] # 即使这样也行 XD 系统直接支持大数运算,普通整数不声明的话默认不会有溢出问题 loop i to -1/0 do echo i |
import
和java一样使用这个来导入外部类,但用除号“/”分隔命名空间,而不是点号“.”,很容易理解为什么这么干,这是利用了uri定义,于是也支持所有uri的特性。举几个具有代表性的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# as用于重命名空间名,以便于调用。这里都是调用 静态方法,下面这个是本地相对路径。 import :ys/os/graphics as g # 远程的库也完全没有问题,支持http,ftp等流行协议和缓存, 下面这个是https import https://ys.org/os/sounds # 导入文件夹中所有的类 import :ys/sys/ g.paint_rect(0, 0, 10, 10) # 和上面等价 :ys/lang/graphics.paint_rect(0, 0, 10, 10) # 导入之后协议类型可以省略 :ys.org/os/sounds.play([./show.mp3]) |
信号和线程
Windows里将信号称为消息。直接将这两个常用的项目集成到语言特性。线程定义和定义函数一样,这有点像并行语言。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 定义一个线程,加前缀 ! ,表示此线程不会阻塞父进程,默认为了安全共享资源,线程是等价于普通lua函数的。 # 当window对象接收到系统传递的click信号时,触发事件。 window.click += clicked thread_run def clicked: echo window.title end def !thread_run: echo [Clicked window.] end |