西西河

主题:【原创】介绍一下Go语言(1)之前的话 -- zllwy

共:💬92 🌺231
分页树展主题 · 全看首页 上页
/ 7
下页 末页
                • 家园 语言的简单性

                  什么是语言的简单性,是个很有意思的讨论。

                  我倾向于认为simplicity是指语言设计上的简单性。但语言的易用性是另外一个概念。Design simplicity并不意味着使用上的容易。Go的特点是设计上很简单,比如Go只有25个关键字,比大多数语言都要少(当然不是simplicity绝对的比较),还有Go的compilation不需要symbol table等等,再加上互相独立的一组强大的语言功能特性,使得语言使用比较简单。其实python也有这个特点。设计简单,但功能又很强大,让人不用学太多的复杂语法就能上手。

                  你说的几个例子我感觉是语言的功能强大,使得程序员可以简单地实现一些程序结构,这个更多的是易用性。实际语言本身,我觉得ruby和C#的设计其实不算simple。

                  至于库,其实越来越成为一个语言不可分离的一部分了。不过我那个例子的关键并不在于库。即使Java之类的语言有同样的库支持,写出来的代码也要冗余不少。看来大家不满的是觉得这个例子不够充分说明Go 的简单易用,虽然我个人觉得还是很能说明的。这个就是个人观点的差异了。

                  • 家园 设计上的简单vs使用上的简单性

                    4:21 PM

                    我觉得简单性应该是指使用的简单性,任何一种工业上可用的编程语言,其设计上必需是复杂的,必需提供一大坨业界需要的功能。

                    使用上的简单性,就是说这种语言能把很多概念抽象出来(比如算法,比如数据结构,比如编程思想),用一种简单的近似于透明的方式,暴露给代码民工们。最简单的例子就是GC了。 这种使用上的简单性,在设计实现上往往是非常复杂的。但是,码农们不需要自己需实现jvm啊,理解GC的概念以后,用起来爽就可以了。

                    • 家园 同意

                      其实我们说的不矛盾。我说的设计是语言本身的设计,你说的设计是实现上的设计。以Go为例来说,它的语言设计很简单,其中一个目的也是为了编译的速度。但它的实现其实比较复杂,比如goroutine和channel的实现,gc的实现等等。

    • 家园 【原创】介绍一下Go语言(6)没有的特性

      最后讨论一下Go没有的一些特性。这些特性在其他语言中很常见,但Go还没有实现。

      1 generics。这个可能讨论最多了。对于很多人来说,没有generics就没法写程序了。Go内置了map,所以很大一部分对generics的需要似乎就满足了。另外,可以用interface{}来实现任意类型的container,然后自己unboxing,所以实现generics也不是那么紧急。当然,性能上generics可能要好一些。我个人无所谓,generics似乎对我没有那么重要。

      2 Union类型。似乎对于写某些系统程序比较重要。对大部分应用没有太大影响。

      3 oeprator method。好像对科学计算比较重要。一般的应该没有也没什么。

      4 exception。Go提供了panic/recover起到了部分作用。完整的exception机制对于我来说似乎不是很重要。

      5 method/operator overloading。主要好像是从Go语言本身的简单性,容易实现来考虑的。

      • 家园 overload副作用比较大

        无论是operator还是method overloading

        记得当年自学C++的时候,看到operator overloading,惊为天人。但是到了看别人程序的时候,才明白如果一个短短的表达式里面有几个operator是overloaded,然后每个操作符都要小心翼翼的去查证是否是overloaded,那叫一个痛苦。

        所以后来看到java没弄这个劳什子,还是很开心的。

        method overloading相对好一点,但是如果一个程序员被逼迫到需要用同一个函数名去处理不同的事情,那么要么是这位词语比较贫乏,要么是被requirements给逼的。

        • 家园 我见过最牛的是把【】给overload了

          那代码写的。。。overload的确是双刃剑啊,用得合适需要智慧

        • 家园 同意

          我也很讨厌operator overloading,尤其从读代码的角度来说。科学计算领域似乎确实有这个需要。想象一下a+b都要写成add(a, b)也是挺痛苦的。不过一般语言里面有限的几个operator也不够用的。可能应该允许定义自己的operator。这就是另外一个话题了。

          • 同意
            家园 函数调用其实是polish notation

            还是很强大的,有了prototype,后面跟几个参数都是确定的。

            expression我看主要还是兼容以前的写法,表达能力其实只是对二元操作符最合适,遇到一元的就只好上括号,或者骑到别的操作数肩膀上来避免歧义了。遇到Σ这样键盘上找都找不到的操作符,函数才是最终的办法。

            我倾向于统一用函数调用,只在不产生歧义的地方使用expression

    • 家园 【原创】介绍一下Go语言(5)其他特性

      Go的一个设计目标是在尽量简单的基础上,提供一组正交(orthogonal)的语言特性。使得这些语言特性的应用也比较简单明了。我对Go的感觉就是一套趁手好用的工具,每件工具都有自己独立的功能,都设计得比较精巧,而它们又可以通过简单的结合来提供强大的综合功能。这里把我喜欢的一些语言特性罗列一下:

      1 函数的多返回值。一个函数可以返回多个值。类似于python可以返回一个tuple。这个特性太方便了。所以我把它排在第一位。:-)当然由于这个特性,Go的call convention和C不一样。Go的compiler(非gccgo)不能和C的call convention兼容,在和C进行连接的时候要通过特殊的步骤(cgo)。目前Go可以调用C的函数(通过SWIG可以调用C++)。但反过来还不行。

      2 Array slice。也和python类似的功能一样,可以用来访问一个array的不同区段。

      3 强大的for和switch。Go里面没有了while和do。for可以表达任何循环。和range结合起来基本起到了可以iterate各种type的作用。switch实际上起到连串else if的作用。

      4 内置map。这个很多dynamic language都有,不过static language的还不多见。也算是抄python吧。

      5 closure。这个不用说了吧。

      6 defer。有点像Java的finally。不过可以写在函数任何地方。感觉红来保证资源的释放比finally更方便。

      7 garbage collection。这个也列在这里吧。

      8 程序本身的UTF-8支持。

      9 panic/recover用来处理runtime exception。类似于exception。感觉Java里面exception有点被滥用了。exception应该只用来处理罕见的错误,而不应该用来控制流程。我觉得多返回值很大程度上已经使得错误处理方便很多了。

      10 变量定义的短形式。你可以写

      a := 1

      自动就把a定义为int了。可以少些很多废话。

      11 变量类型定义。终于把C/C++的变态格式改过来了。类型的表达式放在了变量名的后面,初始化放在最后。清楚,简单。

      12 简单的变参定义。又抄了python。

      其他还有很多小的特性。感觉用Go写程序比较轻松简单。我想跟C接近,又消除了C的很多不足,是最大的原因吧。

    • 家园 exception handling

      突然意识到Go没有try-catch-exception,而是用panic/defer/recover.Google 一下发现很多有意思的讨论.

      http://stackoverflow.com/questions/1736146/why-is-exception-handling-bad

      http://groups.google.com/group/golang-nuts/browse_thread/thread/1ce5cd050bb973e4?pli=1

    • 家园 Rob Pike: Geek of the week

      An interview with one of the Go designers: Rob Pike.

      http://www.simple-talk.com/opinion/geek-of-the-week/rob-pike-geek-of-the-week/

    • 家园 【原创】介绍一下Go语言(外篇)JMM

      Java Memory Model (JMM)

      为了说明线程和共享内存模式的问题,可以来看看Java memory model的演化中体现出来的保证共享内存模式正确的微妙性和困难性。

      大家都知道Java中三个关键字final, synchronized和volatile。前两个比较容易理解,final是说被标记的变量是个常量,synchronized是表示一段代码由monitor保护,起到一个互斥的作用。至于volatile,是说被标记的变量不会被cache(register, L1/L2 cache or other buffers),直接写到内存。但由于硬件的复杂性,Java memory model并不是从一开始就把这几个关键字的真正用途实现正确了的。在Java 1.4之前,JMM有很多问题。

      首先说一下导致问题的根源。几个问题,一是memory hierarchy,包括register,cache,buffer和RAM,一个变量赋值以后,很可能没有立即写到内存里去。二是硬件的分布性。在多个CPU/core的情况下,各个cpu/core可能有自己的cache,这就有了cache coherency的问题。一个线程给一个变量赋值,不见得另外一个线程就能马上看到。还有就是程序指令本身很可能被compiler重新排序来提供运行性能。由于Java是compile once, run everywhere,它就需要保证实现一个memory model,使得程序在任何系统上都运行正确。由于C/C++没有这样的保证,所以写多线程程序的时候要特别小心,很可能在一个硬件平台上运行正确的程序,到了另外一个硬件平台上就不对了。而这些因素使得实现一个跨平台的memory model很有挑战性。

      先来看final。在Java 1.4之前,对final的实现不正确。一个final变量,创建的时候先有一个缺省值,然后才赋给初始值,这之间的间隔在多线程的情况下就会导致问题。看下面的例子:

      String s1 = “/usr/tmp”;

      String s2 = s1.substring(4)

      正确的结果,s2应该是”/tmp”。但在Java 1.4之前,多线程情况下,s2可能是”/usr”。这是因为String的实现,有三个final域,包括长度和起始位置,但因为没有对多线程的保证,当String的构造函数被调用时,另一个线程可能会看到final域的缺省值,然后才看到初始值。JSR 133中的新的JMM,保证了这种情况不会出现。

      再来看volatile。Volatile的含义很多程序员都不是很清楚。Volatile是说,被标记的变量的变化,应该立即被所有的观察者看到。但在实际对volatile的使用中,往往会出问题。比如下面的例子:

      Map config;

      volatile boolean initialized = false;

      // in thread A

      Config = new HashMap();

      … // add something to config

      Initialized = true;

      // in thread B

      while (initialized) {

      … // use config

      }

      这里initialized被用作一个guard,保证我们能使用初始化以后的config变量。实际中呢,thread B有可能看到没有初始化过的config。这是因为volatile只保证initialized这个变量立即被其他的线程看到,但由于程序指令的乱序执行,并不能保证initialized赋值之后, config已经准备好了。在JSR 133中,加入了指令的排序,保证了这种情况不会发生。

      最后一个是synchronized。表面上,synchronized意味着被保护的程序在一个 monitor里面运行,也就是说是线程互斥的。但实际上还有更深的含义。简单说,就是还有memory barrier的保护。这保证了在monitor上的线程可以以可预见的方式看到互相之间对内存变量的修改。而没有synchronized的代码就没有这种保证。一个例子就是常见的singleton;

      Class someClass {

      Private Resource resource = null;

      Public Resource getInstance() {

      If (resource == null) {

      Resource = new Resource();

      }

      Return resource;

      }

      }

      在多线程的情况下,需要给getInstance()加上synchronized。有人就会想优化一下,因为synchronized是有代价的。这个优化叫double-checked locking (DCL):

      Class someClass {

      Private Resource resource = null;

      Public Resource getInstance() {

      If (resource == null) {

      Synchronized {

      If (resource == null) {

      Resource = new Resource();

      }

      }

      }

      Return resource;

      }

      }

      改进就是先看一下是不是为空,空的话再做synchronized的操作。但DCL是不对的,因为第一个检查没有synchronized保护,很有可能另外一个线程在创建resource的时候,本线程就看到了,然后在resource的constructor被调用完之前就把resource返回了。这就有可能导致对未初始化的object的使用。DCL在新的JMM下也不行。

      综合以上的例子,可以看到多线程共享内存的复杂性。写程序的时候一定要知其所以然,加上小心,才能尽量避免多线程编程的错误。

      通宝推:铁手,西电鲁丁,
分页树展主题 · 全看首页 上页
/ 7
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河