`
cloverprince
  • 浏览: 127399 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

GNOME是不是什么地方从根本上错了。。。

阅读更多
大家好。

给大家拜个晚年。假期大家应该休息得不错吧。

不知是不是哪里错了。不知群里有没有熟悉GNOME的高手。

字多杀猫。摘要:
1、大家说说,Gnome编程怎么学?
2、GTK,GObject,GType,GIO这个代码栈有没有什么问题?是不是什么根本的地方弄错了?
3、这个世界是不是都错了?

我已经是第无数次开始尝试学习GNOME下的编程了。

用C和Python语言编过一两个GTK程序。
觉得写GTK程序,按需查资料也就可以了。
但是对GTK的底层的一套框架感到很困惑。

尝试读GObject的文档也已经无数次了,每次都被吓走。
虽然GObject的reference里说过你不用自己实现每个函数。
但是总是觉得,太难,无从下手。
[外部链接:GObject的Reference http://library.gnome.org/devel/gobject/2.18/ ]

(p.s. 我学Haskell,花费了2个多星期才勉强弄懂什么叫Monad,
但是感觉理解GObject要更难。)

我可以选择逃避底层细节。
已经有人给GTK写了Python,C#,Java的Binding。
Python用起来很顺手。
虽然Python没有continuation这种方便的东西,
我用decorator愣是做出了几个比较简便的封装器。
(感兴趣的去北邮人Linux版搜搜我的Python钢琴)

但是,不可能到这里就止步吧。
总有一天,我会想做一个自己的控件。
但是不知道GObject的细节,想做到是不可能的。


另一个问题:我一直觉得GNOME的底层有问题。

首先C语言(靠,这么底层,难道说这个世界上的计算机全都有问题了?)

C语言的优点是有的,就是太容易实现了。
我的感觉,学了汇编,就觉得C好像就是汇编语言的一个"Thin Wrapper"。
局部变量、全局变量的定义,函数调用,循环结构,基本和汇编语言直接对应。

另一个优点就是简单的模块化。
函数调用,函数被封装在一个代码块里。
知道函数所在的库,以及它的名称,就能找到函数地址。
压几个数据到堆栈上,call一下,就行了。
不像Haskell。
为什么Haskell坚持用静态链接,而不使用动态链接库,
就是因为Haskell进行函数应用(对于函数式语言还是不叫"调用"比较好吧)的时候,
很可能会做很多模块间的优化。

但是C语言也有缺点。
缺点就是难以移植。
有人说C语言根本不能成为"平台无关"的语言。
不同机器上,int,long,short长度都不一样。
而且你还不敢确定新的平台上支持不支持64位的整数。


所以嘛,glib给它封装了一层。
gint8,gint16,gint32,gint64保证跨平台的正确性。
不过,如果你的数据的长度和机器的字长不一样,性能就...可想而知。
反正,正确性是保证了。

除此之外,还有一系列常用的数据结构和算法,
像什么数组,链表,二叉树,哈西表,什么的。
然后,gnome那边还有个重新实现的IO库:GIO。
我很奇怪,几乎每一个通用的GUI框架都会自己实现一批算法。
古老的wxWidgets(诞生于92-93年)是这样,自己实现了数组链表哈西,甚至文件操作什么的。
MFC(略晚于wxWidgets)也有自己的一套CArray,CList,CMap,甚至CFIle,CSocket等等一堆。
它们好理解:它们出来之前,C++的STL还没出现呢。
然后呢,glib也有自己的一套算法。
我就觉得,这批轮子一遍又一遍地被人重新发明。是不是该说明什么问题了呢?


然后,GObject出现了。
GObject出现的原因,reference上已经说了:
不同的语言,比如C和python,互相调用是需要glue code的。
通俗的说就是"适配器","桥梁"。
如果你手动写适配器,太麻烦;
如果你自动生成适配器,工作量还是太大,因为每个函数都要一个;
因此,GObject的做法就是做一个"通用"的适配器,
凡是用GObject写的对象,都能用同样的适配器,让别的语言调用。

这个梦想确实不错。不过,用GObject直接写对象是不是太overkill了呢?
C语言没有语言级的对"对象"的支持。
你必须手动写一堆宏,把构造函数,析构函数注册上去。

这就像什么:
这就像用16进制编辑器来写C程序。
就像通过用锤子敲击钢琴内部的琴弦来弹钢琴。
就像通过对草坪上每根草应用转基因技术,来修剪草坪。

不过,我更担心的是,
如果没有语言级别的保护,程序员很容易犯错误。
而且这种错误很难检测,检测出来也难以解释:
到底是在底层语义上,比如构造函数忘记注册到GObject中?或者是复制的字符串内存没有释放?
还是在高层语义上,比如构造函数的内容、逻辑不正确。


用C++吗?
KDE的大厦已经建立起来了。KDE4.2多么华丽。
貌似不是解决办法。
因为C++的ABI很恶心的。不同编译器编出的程序都不兼容。
(比起Haskell,C++的ABI算是好的。Haskell程序,同一个编译器,不同版本,都不兼容。)


这也难怪。C++太"强大"。
它允许函数重载,100多个函数叫同一个名字都没问题。
那么好了,如果100个函数都叫printf,存在libcplusplus.so(举个例子)里面
你怎么找到你要的printf?

一个办法,mangle:让"不同"的函数拥有不同的名字。
首先,在函数名前面附加_x_,因为没有C函数可以以_开头。
然后,在函数名后面附加参数的类型。
如果接受一个int,就是:_x_printf_i_
如果接受一个double和一个char,就是:_x_printf_d_c_
这样不同的函数名字就不同了。
[外部链接:维基上的mangle解释 http://en.wikipedia.org/wiki/Name_mangling ]

可惜,C++指定标准的时候,故意"不规定"这个mangle怎么做。
所以不同的编译器生成的函数都不一样。
然后,你想保证兼容性,不得不extern "C"。
然后又有问题了,C语言没有对象。C++的对象在C里怎么表示呢?

还有,"对象"在库里怎么表示?
怎么在运行时知道一个一个类是不是另一个类的派生类?
MFC有自己的XXX_DYNAMIC_CLASS宏
C++标准库后来终于有了typeinfo

还有异常处理什么的,不同编译器之间,实现方法也不一样。
这还有什么办法呢?


不难想象Java最终有一天会出现。
虚拟机的执行环境,平台也无关了,ABI也统一了。还有什么好争的呢?
.NET是微软对Java的回答。差不多。

不知为什么,Java的程序总给人一种"恐龙"的感觉。
庞大,缓慢……
上次去某图书销售公司参观,
他们给我展示了IBM给他们开发的企业管理系统。
一眼就能感觉出,反应速度不快。
虽然根据种种benchmark,Java程序的速度很接近C,远远超过Python。
每次编程序需要用30秒钟启动eclipse,这是什么感觉。。。很囧。

而且,Java程序总有点跟周围的程序格格不入的感觉。
GNOME上已经有了很多.NET程序。Tomboy,FSpot,Banshee。
奇怪怎么那么难看到Java的影子?
eclipse就是90%为Java开发而存在的吧。
Tomboy,Glassfish什么的你不做服务器也用不着。

Java开源不过1年多。不知以后会不会有所发展。

C#是ISO标准,可以随意实现;
但是貌似.NET的核心库中,隐隐约约有M$的专利在作祟。
我听一些人说中国不承认软件专利,
但是上次RichardStallman来清华,他亲口说中国承认软件专利。
即使Novell和M$签订了龌龊的"Don't sue"协议,
也觉得这肯定不是永久的解决方案。
不起诉,但也许仍然是非法的。非法!这才是关键。只是人家不告你。

理论上,我觉得Java和C#是目前最理想的编程用语言。

Java偏纯粹性,纯粹的面向对象模式。
C#偏实用性,包括LINQ,连函数式编程都往里加。

p.s. ML本来是函数式语言,也有了.NET的实现,就是F#。
奇怪,F#怎么没发现Haskell往.NET上移植很难呢?

另外,Java有JNI,C#也有本地接口。
不知道Java和C#能不能直接透明地应用GObject的对象呢?
按照GObject的说法,应该可以做到。我没有验证。
或者,我们需要一个新的虚拟机来实现GObject?


~~~~~~~~~~~~~~~~~~~~~
怕跑题跑远了,重复一下主题:

貌似Gnome的实现方法很成问题。
用C语言实现,虽然效率高,再加上glib的支持,跨平台性也好。
但是,C语言是不是太底层了呢?
起码用一个面向对象的语言吧。
~~~~~~~~~~~~~~~~~~~~~~


下面说Vala语言,动态语言,Pike语言和IPC


先说说Vala语言。
Vala语言是个极其类似C#的语言。
没错,就是GNOME社区发明的,
专门应对那些因为一个又一个的原因,而不愿意用Java和C#的人。
但是,奇怪的是,它并不运行在虚拟机上。
它的代码将直接翻译成C代码,应用的就是GObject对象系统。

如果这样说,
那么Vala就拥有了C,GLib,GObject的全部兼容性优点,和C#的美观。
GNOME能不能只用C实现基础的库,然后上层直接用Vala实现呢?


再说说动态语言。

Perl不说了。很适合one-liner,但是写超过10行的代码就相当脑残了。

Python是Guido van Rossum上个世纪80年代末弄出来的。
最初写系统管理程序用,然后慢慢成为通用的语言的。

Ruby是松本行弘为了救痛苦的程序员于编程的水深火热之中,
而创造的很人性化的语言。

动态语言的特点就是,什么东西都是运行时决定。
包括变量类型。
不,Python和Ruby里面变量没有类型。
变量只是对象的引用,对象有类型,变量没有。
对象的成员是运行时确定。
一个对象有没有某个方法,不运行就不知道。
如果发现没有,只是抛出一个异常,而且这个异常还可以被处理,
这样,调用一个根本不存在的方法,最后会变成一个"正确"的操作。

典型的Python里的XMLRPC库。
ServerProxy对象,代表一个服务器,本身没有方法,
调什么方法,实际的行为是往服务器发个消息,服务器回应,然后返回值。

这种动态语言适合GNOME这种东西吗?

很多东西,其实,应该在编译期就可以确定的。
比如按钮有什么方法,这我们总是知道的吧。
关键是,有了编译期检查,就可以避免程序员犯很多错误。
要是你压缩一个1G多的文件,压缩完了,告诉你,输出报表的函数拼写错了,
改了一下,又花了1个小时压缩,然后发现又错了。
郁闷吧。
虽然说松本先生说的"Test early, test often"是有道理的。

更要命的是接口。
接口决定了你能对一个对象做什么操作。
这个东西绝对要在运行之前确定。否则程序员可是愁死了。
上次给QuodLibet写插件,
没有API文档,看在它是新软件的份上,我原谅它了。
拿到代码,我都不知道传给函数的是什么类型的对象。
这让我怎么对它操作?我都不知道哪些操作是允许的。
这样的框架,还敢让人用吗?

我就不记得Python有Interface这种东西。
基于Python的Zope系统自己做了"Interface"系统。
新版Python的AbstractBaseClass貌似很抽象。

不过,也不是完全没办法解决。
同样是动态语言,Erlang就很好,
所有的文档里,都明确给出了参数类型,返回值类型。

这种语言用来实现GNOME不是不可以,似乎还是一种趋势。
GOOGLE里搜GTK的API,PyGTK的项目总是在GTK本身的前面。

底层,比如所有的Widget,也用动态语言实现,不知效率行不行。
没听说过有人尝试。
我觉得不是做不到,XServer是用Socket通信的,Socket语言无关。

目前,Python和Ruby的主流实现是用C。
对于跨语言的交互性,确实不太好办。
万一你用Python写了点东西,要用Ruby调用,还麻烦了。
Python和Ruby还不太一样。
用C调用更麻烦。

还是那句话,如果GObject像它声称的那样好,用Python或Ruby来做,语言间交互是不成问题的。


比较冷门的Pike语言。
上次去BLUG聚会的时候有人提到。
Fedora的Repo里还没有。

这种语言,虽然也是静态的,但是有type-inference系统。
这一点类似函数式语言。
你只要有a=1,就知道a是int的。再a="abc"就报错。
你也可以int a=1,显式定义。
可以给程序员节省很多敲代码的时间。

Pike也是面向对象的语言,
支持解释执行,也可以编译成本地代码。
标准库里就有自己的GTK和MySQL支持,
估计是怕没有别人为它做binding吧。


IPC
不能直接调用,我们平等通信,总行了吧。
D-Bus是这么一套系统。
对外公布了D-Bus接口,
不用管对方用什么语言,反正中间都是Socket通信。
效率嘛,肯定没有效率可言了,
不过,桌面上这点事,效率还要多高呢?

不过,奇怪找不到一个相对完整的D-Bus教程。
Reference也还在Draft阶段。正式的Spec还没出来。
如果GObject把我吓跑了10次,
D-Bus起码把我吓跑了5次。

当前IPC的框架也挺多的。
微软有ActiveX, COM, COM+, DCOM, OLE,现在.NET还有WCF。
GNOME以前用CORBA,现在改用D-Bus。
KDE以前用DCOP,现在也在转D-Bus。
还有ICE,貌似是网络上用的。
W3C有SOAP,民间有XML-RPC,都是文本格式的网络通信。



有人说,[外部引用: http://www4.osnews.com/thread?261437 ]
GNOME已经失去了往日的活力。
这么多年,GNOME一直在缓慢地迭代,添加很少很少的新特性。
他虽然也说目前GNOME也有很多新的发展,
但是我的感觉还是缓慢。

虽然说,业精于勤,荒于嘻;
但是,如果发现自己的进步太慢,是不是因为方法不正确呢?



不过,我倒是希望,是我自己的学习方法不正确。
将近10次硬攻GObject失败,也许也是方法不正确吧。
如果说"Given enough eyeballs, all bugs are shallow",
那么,GNOME社区的高手们更应该先发现问题才对。


说到这里终止吧。


---------------------------------

后记:

这是在我们社区的邮件列表上发出的问题。后来得到不少同学的回答。

1. 除了我喜欢的自顶向下的学习方法——一下子看清整个体系结构——以外,还有另一种方法:就是用到哪儿学到哪儿。这种方法也许成本较高,但是相对容易一些。
分享到:
评论
2 楼 cloverprince 2009-12-14  
有道理。

这篇文章是我以前写的。正如你说的,因为知道的太多了,所以会怕不“优雅”而不敢碰程序。现在我知道世界上没有完美的框架。如果怕把手弄脏,什么都学不会。

最近的一批文章写了我用最笨的方法去编,去学习最原始的C语言的GObject,反而发现很轻松,不像我想象的那么糟糕,很多不能理解的东西,发现如果实现起来,非这样做不可。

ileile 写道
你知道的太多了,所以不会写程序了。

如果你真问对了问题,你就会知道如何解答。

其中一些解答需要你变成真正的Programmer而不是Developer。

这种转变是好事也是坏事,不是我装×B说一些故作高深的话;但是BB了几年过来我算是有点明白了:写程序在天分所限之内是一件很简单的事情,没那么多可BB的。

(做工程则是工作量又杂又大的无聊事情)。

在你这里留言,是因为我认为你还学生,所以前途(不是指挣的工资比别人多)还是有的。如果你是这个社区那些不堪就要的老油条,我就懒的说的了。

说的太虚了。其实桌面这点事情,根本不必要用框架,即便是想要和别人保证一样的程序风格也是如此。

唯一一个例外是你和别人一起工作的时候。这个例外虽然在大多数情况下都会碰见,但是它很好解决:和别人写一样的程序、并经常和说话算数的人请教、商量。

至于语言,不要纠缠它们之间的比较、和具体技巧的学习了。它们和桌面一样,只是这些界面是提供给你而不是最终用户使的。

当使用别人发明的东西而感觉不爽的时候,你有两个办法:一个是抛弃它、一个是解决它。采取哪个办法在于成本的评估。

1 楼 ileile 2009-12-12  
你知道的太多了,所以不会写程序了。

如果你真问对了问题,你就会知道如何解答。

其中一些解答需要你变成真正的Programmer而不是Developer。

这种转变是好事也是坏事,不是我装×B说一些故作高深的话;但是BB了几年过来我算是有点明白了:写程序在天分所限之内是一件很简单的事情,没那么多可BB的。

(做工程则是工作量又杂又大的无聊事情)。

在你这里留言,是因为我认为你还学生,所以前途(不是指挣的工资比别人多)还是有的。如果你是这个社区那些不堪就要的老油条,我就懒的说的了。

说的太虚了。其实桌面这点事情,根本不必要用框架,即便是想要和别人保证一样的程序风格也是如此。

唯一一个例外是你和别人一起工作的时候。这个例外虽然在大多数情况下都会碰见,但是它很好解决:和别人写一样的程序、并经常和说话算数的人请教、商量。

至于语言,不要纠缠它们之间的比较、和具体技巧的学习了。它们和桌面一样,只是这些界面是提供给你而不是最终用户使的。

当使用别人发明的东西而感觉不爽的时候,你有两个办法:一个是抛弃它、一个是解决它。采取哪个办法在于成本的评估。

相关推荐

Global site tag (gtag.js) - Google Analytics