美国通用电气(GE) 的Magik编程语言简介


很少人知道 GE (General Electric, 美国通用电气) 是 Magik 编程语言的主人(当今, Google有Go, 甲骨文有 Java, 苹果有 Swift, Object-C, 微软有 C#, TypeScript 等等)

一般来说, 一个公司要能创造出一门编程语言, 就一定程度说明这个公司的技术实力还是挺牛逼的.

Magik语言的历史

Magik语言最早是1989年由Arthur Chance领头设计的, 已经30年了. Magik语言是面向对象动态类型的语言. 该语言在版本5之前, 是由C语言编写, 源代码(扩展名 .magik) 由 Magik Compiler编译成类似 Java 的 Bytecode 运行在 Magik Virtual Machine 上.

Java出来的时候是1995年, 不得不说Magik的这个理念在当时还是很先进的. 不仅如此, 很多该语言的特色也被其它语言借鉴了, 比如在 Magik 里可以用 * 来复制多个字符串(这个和 Python 是一样的):

1
Magik> "Magik"*2  # 得到是 "MagikMagik" 字符串
Magik> "Magik"*2  # 得到是 "MagikMagik" 字符串

在2012年, GE把Magik编译器用Java重写, 然后自然而然就可以把Magik代码编译成 Java的 .class ByteCode. 这么一来得到好的就很多了, 拥抱Java世界, 同时可以用到很多开源Java的库. 不得不说GE的这个决定还是挺明智的, Magik语言在移植到Java虚拟机上, 运行效率就提升了几倍以上.

刚入职GE的第一天, 感谢组里的大牛(Senior Staff SE)和我讲了Magik的历史, 讲了包括最开始还没引入代码管理的那些时候多人是如何修改一份源代码的, 讲到GE管理层没有把Magik编译器开源就有点遗憾. 如果开源了, Magik现在可能就非常强大和有名了. 当然现在类似在Java虚拟器上跑动态语言的比如还有 Ruby.

说到Magik语言, 就不得不说GIS软件 (Geographic Information System 地理信息系统). GE的这个GIS软件叫 Smallworld, 原来是一个公司, 后在2000年被GE收购软件名就一直沿用至今.

全世界GIS软件GE有很大一部分份额, 特别是在电网领域的应用Smallworld占据较大的比例. Smallworld的一大优势就是这个Magik语言, 除了底层是由C/C++, Java编写, GIS软件的框架, API, 还有上层的应用, 都是大量的 Magik 语言编写的. Magik 语言的动态性, 多态性, 还有和Java世界的无缝结合, 再加上GE在90年代开发出的VMDS-类似当今多版本管理和控制等, 都使Smallworld这个GIS方案颇受欢迎.

很多第三方的公司都是在 Smallworld上进行二次开发, 比较有名的是澳洲的一个叫MagikMind的公司. 也有很多招Magik的开发职位.

Magik IDE

GE内部开发了一个IDE, 可惜并不是很好用, 所以并没有流行开来. 2019年的时候GE的一个 Staff Software Engineer 在 VS Code 上开发了一个很好用的 Magik插件, 然后公司内部就推荐VS Code作为 编写开发Magik的主要工具. 也有民间的人开发了几个, 比如这个 VS Code Magik插件也不错.

在VS Code之前, 开发 Magik 主要在 Emacs 上, 这是个很难用, 快捷键很难记很反人类的工具, 不过类似 vi/vim, 组里的许多大牛对 emacs 都很熟练, 很多开发人员都用了十几二十年了, 熟能生巧.

第三方公司MDT有一个IDE, 不过是付费的.

magik_development_perspective 美国通用电气(GE) 的Magik编程语言简介 I.T. 资讯 软件资料

Magik IDE MDT

Magik 基本语法

Magik关键字是不区分大小写的, 不过一般以小写为主, 可以含有问号, 比如变量: going_to_be_rich? 写代码的时候就很清楚了, 一看就是布尔值. Magik关键字以 下划线 _ 开始, 比如 _if, _then, _while, _true 等等.

注释

这个Python和Magik一样, 都用 #来表式行注释.

1
# 这是注释
# 这是注释

赋值

用两个减号表示赋值, 和R语言一样:

1
2
3
a << 1.234         # a = 1.234
b << b + a         # 把b的值加上a
c << "foo" + "bar" # 字符串连接
a << 1.234         # a = 1.234
b << b + a         # 把b的值加上a
c << "foo" + "bar" # 字符串连接

用等号 = 来表示逻辑判断. 类似C/C++里的 +=, 在 Magik 里也可以:

1
b +<< a # 等同于 b << b + a
b +<< a # 等同于 b << b + a

我们可以用 write, print, debug_print 或 show 来向控制台显示内容 (不同的格式)

1
2
a << "hello"
write(a)
a << "hello"
write(a)

交换

这个估计 Python 是和 Magik学的:

1
(a, b) << (b, a) # 交换 变量 a 和 变量 b的值. 
(a, b) << (b, a) # 交换 变量 a 和 变量 b的值. 

符号

JS里有Symbol构造, Magik里可以用冒号来定义一个符号, 并且可以用两竖号来定义含有特殊字符的符号(如空格). 在引用Java类的时候就得用 |..|来保持大小写.

1
2
a << :hello  
b << :|hello world|
a << :hello  
b << :|hello world|

动态类型

所有数据类型都是对象, 并没有 简单类型. 不需要定义类型就可以用.

1
2
a << 1.2     # 变量 a 是浮点值
a << "1.2"   # 变成了 字符串了
a << 1.2     # 变量 a 是浮点值
a << "1.2"   # 变成了 字符串了

类/对象

Magik支持多继承, 用关键字 def_slotted_exemplar(范例)来定义类.

1
2
3
4
def_slotted_exemplar(:my_object, {
    {:slot_a, 34},
    {:slot_b, "hello"}
}, {:parent_object_a, :parent_object_b})
def_slotted_exemplar(:my_object, {
    {:slot_a, 34},
    {:slot_b, "hello"}
}, {:parent_object_a, :parent_object_b})

该代码段将定义一个名为my_object的新示例, 该示例具有两个插槽(或字段), 分别称为slot_a(预初始化为34)和slot_b(预初始化为”hello”), 它们继承自两个现有的示例, 它们分别称为parent_object_a和parent_object_b.

比较

Magik实现了所有常用的逻辑运算符(=, <, <=, >, >=, 〜= / <>)以进行比较. _is和_isnt运算符用于比较对象的特定实例, 或对象引用而不是值.

1
2
3
4
5
6
7
8
9
10
a << "hello"
b << "hello"
 
a = b # 值相等
a _is b # 不同对象
 
a << "hello"
b << a
a = b # 值相等
a _is b # 引用相等, 同样对象
a << "hello"
b << "hello"

a = b # 值相等
a _is b # 不同对象

a << "hello"
b << a
a = b # 值相等
a _is b # 引用相等, 同样对象

方法

为类定义方法:

1
2
3
_method my_object.my_method(a, b)
  _return a + b
_endmethod
_method my_object.my_method(a, b)
  _return a + b
_endmethod

一般来说, 定义 new 和 clone 来提供初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 构造函数
_method person.new(name, age)
  _return _clone.init(name, age)
_endmethod
 
# 初始化
_private _method person.init(name, age)
   # 父类构造
   _super.init(name, age)
   # 初始化类成员
   .name << name
   .age << age
  _return _self
_endmethod
# 构造函数
_method person.new(name, age)
  _return _clone.init(name, age)
_endmethod

# 初始化
_private _method person.init(name, age)
   # 父类构造
   _super.init(name, age)
   # 初始化类成员
   .name << name
   .age << age
  _return _self
_endmethod

_clone创建对象的副本. _super语句允许对象在父示例上调用方法的实现. 对象可以使用_self语句引用自己. 使用点符号访问和分配对象的成员.

可以使用_private语句将不属于对象的公共接口的方法标记为私有. 私有方法只能由_self, _super和_clone调用.

可以使用_optional语句声明可选参数. Magik将未传递的可选参数分配给特殊对象_unset(等效于null). _gather语句可用于声明可选参数的列表.

1
2
_method my_object.my_method(_gather values)     
_endmethod
_method my_object.my_method(_gather values)     
_endmethod

循环

关键字 _while, _for, _over, _loop 和 _endloop.

以下Magik代码在一个代码块 _block里用_while循环从1加到100并赋值于块.

1
2
3
4
5
6
7
8
9
10
_block
    _local s << 0 
    _local i << 0
    _while i <= 100
    _loop 
        s +<< i 
        i +<< 1 
    _endloop
>> s
_endblock
_block
	_local s << 0 
	_local i << 0
	_while i <= 100
	_loop 
		s +<< i 
		i +<< 1 
	_endloop
>> s
_endblock

这里两个大于号 >> 就是 _return 的意思. 非常人性化(象形符号).

1
2
3
4
5
6
7
8
9
10
11
_method my_object.my_method(_gather values)
  total << 0.0
  _for a _over values.elements()
  _loop
     total +<< a
  _endloop
  _return total
_endmethod
 
m << my_object.new()
x << m.my_method(1.0, 2, 3.0, 4) # x = 10.0
_method my_object.my_method(_gather values)
  total << 0.0
  _for a _over values.elements()
  _loop
     total +<< a
  _endloop
  _return total
_endmethod

m << my_object.new()
x << m.my_method(1.0, 2, 3.0, 4) # x = 10.0

代码还是较清楚易懂, values.elements() 是跌代器 iterator. 比如可以用 _iter 和 _loopbody 来定义 iterator:

1
2
3
4
5
6
7
8
9
_iter _method my_object.even_elements() # 偶数
  _for a _over _self.elements()
  _loop
    _if a.even? _is _true
    _then
       _loopbody(a)       
    _endif
  _endloop
_endmethod
_iter _method my_object.even_elements() # 偶数
  _for a _over _self.elements()
  _loop
    _if a.even? _is _true
    _then
       _loopbody(a)       
    _endif
  _endloop
_endmethod

过程

过程 procedure 就是不存在于对象上的方法. 用 _proc 和 _endproc 来定义.

1
2
3
4
5
my_procedure << _proc @my_procedure(a, b, c)
  >> a + b + c  
_endproc
 
x << my_procedure(1, 2, 3) # x = 6
my_procedure << _proc @my_procedure(a, b, c)
  >> a + b + c  
_endproc

x << my_procedure(1, 2, 3) # x = 6

正则表达式

和JS类似, 用 // 来定义正则表达式. 有一点不同: 在JS里//表示行注释, 而在Magik里这是个正则式(匹配空)

1
2
3
_if /Hello\,\s(\w)+!/.matches?("Hello, Magik!") _then
    write("Got a match!")
_endif 
_if /Hello\,\s(\w)+!/.matches?("Hello, Magik!") _then
    write("Got a match!")
_endif 

匹配分组有点怪:

1
2
/sw([0-9]+)-([0-9]+).*/.replace_all("sw65456-324sss", "$1") # "65456"
/sw([0-9]+)-([0-9]+).*/.replace_all("sw65456-324sss", "$2") # "324"
/sw([0-9]+)-([0-9]+).*/.replace_all("sw65456-324sss", "$1") # "65456"
/sw([0-9]+)-([0-9]+).*/.replace_all("sw65456-324sss", "$2") # "324"

HTTP库

类似 Node里的 request库. 通过http库, Magik可以请求 http/https链接.

1
2
3
magikhttp << http.new()
magikhttp.url("https://www.google.com").get()
magikhttp.url("https://www.google.com").post({"User-agent", "Bot"}, "数据")
magikhttp << http.new()
magikhttp.url("https://www.google.com").get()
magikhttp.url("https://www.google.com").post({"User-agent", "Bot"}, "数据")

英式英语

由于Magik最初是在英国开发的, 因此核心小世界库中的方法都是使用英式英语拼写的. 例如: Initialise 而不是 Initialize

集合 Collections

取名都比较怪, 比如 rope 绳子用于定义动态数组.

1
2
a << rope.new_with(1, 2)
a.add(3) # 现在变成了 (1, 2, 3)
a << rope.new_with(1, 2)
a.add(3) # 现在变成了 (1, 2, 3)

来有 哈希表 hash_table, 集合 set等. 甚至有 Java里的concurrent_hash_map 等高级对象. 由于 Magik 和Java底层互通, 所以在Magik编译器的内核有很多 magik语言封装的 Java API.

Hello World in Magik
1
write("Hello World!")
write("Hello World!")

一些Magik程序片段

Fizzbuzz:
fizzbuzz-magik-exercise 美国通用电气(GE) 的Magik编程语言简介 I.T. 资讯 软件资料

Fisher Yates 随机Shuffle算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
_package sw
$
 
_pragma(classify_level=public, topic=random)
_method random.shuffle(list)
    ## Shuffle an array using Fisher–Yates
    ## 
    _local i << 1, len << list.size
    _while i <= len
    _loop
        _local j << _self.between(i, len)
        (list[i], list[j]) << (list[j], list[i]) # swapping in Pythonic way.
        i +<< 1
    _endloop
    >> list
_endmethod
_package sw
$

_pragma(classify_level=public, topic=random)
_method random.shuffle(list)
    ## Shuffle an array using Fisher–Yates
    ## 
    _local i << 1, len << list.size
    _while i <= len
    _loop
        _local j << _self.between(i, len)
        (list[i], list[j]) << (list[j], list[i]) # swapping in Pythonic way.
        i +<< 1
    _endloop
    >> list
_endmethod

参考

https://en.wikipedia.org/wiki/Smallworld
https://en.wikipedia.org/wiki/Magik_(programming_language)
https://www.mdt.net/index.php/working-with-magik.html
http://www.magikemacs.com/page/6/
https://www.gegridsolutions.com/geospatial/Mobile_solutions.htm

GD Star Rating
loading...
本文一共 1656 个汉字, 你数一下对不对.
美国通用电气(GE) 的Magik编程语言简介. (AMP 移动加速版本)
上一篇: 伦敦北部的 BangBang Food Hall 美食广场
下一篇: 到英国 Norfolk Horsey 看海豹

扫描二维码,分享本文到微信朋友圈
936d72b4fdbff8019ab3868287728497 美国通用电气(GE) 的Magik编程语言简介 I.T. 资讯 软件资料

评论