|
Go语言的有些方面其实设计的挺好的,能够细粒度的控制内存布局,又有垃圾收集器来避免内存问题。是易用性和性能的很好折中。但是Go的语法很怪异,在"最丑编程语言"的回答里面都被多次提名。而且缺少继承多态、异常处理、泛型(最近可能会有)等关键特性。如果能有一种编程语言,语法和C一致,有指针和GC,能灵活的控制内存布局,能解决内存安全问题,那我一定会用的。可惜没有见到这样的语言,我只能自己来设计了。
指针安全性
有指针以后,第一个安全问题就是野指针问题,也就是长生命期的引用了短生命期。我的解决方案是将指针生命期分为三类。生命期: 堆内存/全局变量>参数/返回值>局部变量。编译器检查规则是:长生命期可以引用短生命期,短生命期不能引用长生命期。
参数和本地生命期情况:
B* foo4(B *b) {
B b2;
return &b2; //compile error: 本地生命期 < 参数/返回值生命期
return b; //ok
}指针有一个heap关键字来表示是在堆上分配的。heap关键字有三个作用:1.表明指针是堆上分配的,2.在堆上分配内存,3.将栈上对象boxing到堆上。鉴于heap关键字这么常用,那么这个编程语言就叫heap语言。
struct A {
B* b;
}
struct B {
int i;
}
struct C {
B b;
}
A a;
void foo1(heap B* b) {
a.b = b;
}
void foo2(B* b) {
a.b = heap b;
}
void foo3(B b) {
a.b = heap b;
}
x := C();
foo1(&x.b) //compile error
foo1(head x.b)
foo2(&x.b)
foo3(x.b)
y := heap C();
foo1(&y.b)
foo2(&y.b)
foo2(y.b)
结构体内部成员的生命期取决于父级的生命期。
继承与多态
我觉得继承和多态是语言抽象能力的重要体现。并且这种抽象没有性能开销。如果信了组合优于继承的话,可以不用这个特性,不是强制的。
和Java一样的单类多接口继承。只有标记为virtual的结构才能有虚方法。
interface I {
virtual void foo() { ... }
}
virtual struct B {
int a;
virtual void bar() { ... }
}
struct A : B, I {
B* b;
override void foo(B* b) {
...
}
override void bar() {...}
}因为有GC,所以不需要RAII,不需要构造函数和析构函数。
指针使用
指针使用点语法调用方法,而不用->
A a;
A* b;
a.foo();
b.foo();指针类型转换
int *a = cast<int*>(p);指针默认不允许运算,除非使用专用函数
int* p;
int *p2 = unsafe_move(p, 1);数组
数组定义和C一致,但是传参数时变成一种胖指针。数组传参时自带长度,并且debug编译模式下运行时检查越界。
int[14] a;
foo(int[] a) {
print(a.length);
print(a[0]);
}
foo(a);数组和指针相互转换
int *p;
int[] a = as_array(p, 5);
int *q = a.pointer;异常
众所周知C++中没人使用异常。并不是异常不好,而是异常和手动内存管理不兼容。既然选择了GC,那么异常和GC很搭配。所有可能抛出异常的函数必须使用throws关键字标记。
void foo() throws {
}
void dar() throws {
foo();
}
void bar2() {
try {
foo();
}
catch (Exception *e) {
}
}模板泛型
使用了C++类似的模板来支持泛型。
struct Bar<T> {
void foo(): T {
...
}
}
null
指针默认不能为null,除非后面有问号
B* a;
B*? a = null;垃圾收集
为什么一定要有GC。手动管理很容易造成内存安全问题。有GC也避免了RAII和析构函数这些机制。GC的开销其实也没有很大,在可接受的范围。
getter/setter
使用操作符重载的方式来定义getter/setter。
struct Bar {
private int _size;
setter void size(int s) {
this._size = s;
}
}
Bar b;
b.size = 2; // call b.size(2);去掉的特性
并不是特性越多越好,去掉很多C++的特性。
- 不支持引用,只有指针。
- 没有class,只有struct。
- 没有头文件
- 不支持函数通过参数重载
- 不支持一次定义多个变量。
- 不支持RAII
- 没有构造函数、析构函数(析构函数功能会有其他的替代方案)
- 不支持嵌套函数、嵌套类、嵌套命名空间等。
- 没有命名空间(有其他的替代机制)
- 不支持宏
- 不支持模板约束,模板元编程。
- 不支持union类型。
- 不需要前向声明
- 没有static的三层意思。
- 别名定义只能在顶部的import语句中。
- 可变性是简单的final,没有C++那么复杂的规则。
- 没有友员机制,默认internal访问级别。
- 不支持多继承,不支持私有继承
- ++i和i++只保留一个,并且不返回任何值。
- 不支持switch语句贯穿
- 不支持do while, goto语句。
其他
后面还会有闭包和运算符重载等,不再详细写,其他语法参考C++。
基本就是C+OO+GC。没有各种语法糖、没有怪异语法。
最后,heap语言只是开始设计和征求意见,并没有开始开发。 |
|