[前篇]最好的编程语言(如何不再担忧,爱上代码)

原文:The Best Programming Language (or How to Stop Worrying and Love the Code) by A.
Castro-Castilla

每隔一段时间,就会有人觉得是时候再写一篇帖子讲讲什么编程语言最好,某个古老语言有什么强大的特性,或者哪个新语言做对了。现在,轮到我来写了。我终于能说说我对编程语言的看法了。

首先,免责声明:除非你用过30多种语言,而且受过他人写的所有这些语言(或者大部分)的代码的折磨,否则你就称不上是客观的。所以是的,我有偏向,就像讨论这个话题的大多数人一样。实际上我相信,一旦精通多种语言,这个话题就会显得荒诞。

给懒得读的人:伟大的语言

我特此在本博客范围内宣布以下语言为伟大语言。

  • Assembly:机器的语言。
  • C:系统开发的语言。
  • Javascript:网络的语言。
  • Scheme:轻巧、可嵌入而且极为灵活的语言,可以经编译转化为C和Javascript。

大部分代码例子来自Rosetta Code

适用的语言

我把这些语言称作适用的语言,不是因为他们最好。他们只是当今最常用的语言,因此适用于生产性软件。当然,你可以略过争议,凭直觉做决定。如果是这样,请看下一节。

Ada

我一直对围绕存储安全设计软件这个概念感兴趣。对实时操作系统和各种关键系统中的应用程序而言,这都是个可行的概念。如果你在考虑使用这种语言,你很可能有相当的专业背景,不需要读这个帖子。这种语言是成为高手之后用的语言,而那时候也没有多少选择了。一些Ada代码:

   function Best_Shuffle(S: String) return String is
      T: String(S'Range) := S;
      Tmp: Character;
   begin
      for I in S'Range loop
         for J in S'Range loop
            if I /= J and S(I) /= T(J) and S(J) /= T(I) then
               Tmp  := T(I);
               T(I) := T(J);
               T(J) := Tmp;
            end if;
         end loop;
      end loop;
      return T;
   end Best_Shuffle;

看着就很安全,对吧?:)

Bourne (Again) Shell

我经常想:我真的需要用shell语言写这个Linux脚本吗?真的有必要吗?不用shell写脚本也没关系,因为你迟早得面对面处理这种脚本,然后不禁疑惑在没有stackoverflow.com的裸金属时代,这是怎么写出来的。总之,有合适的书指导,你会发现这种语言只是需要一点修饰(和一致性)。这种语言没什么出色的地方,不会开阔视野、提高效率,业务角度也没有什么可取之处,它只是横行Unix和类Unix的世界。然而不管怎么说,它在系统管理中不可或缺,而且并没有看起来那么差。它有点像Javascript,比起其他语言,需要知道更多的实用规范。

我用Unix Shell做什么?

  • OSX/Linux/POSIX系统管理
  • 任务自动化
  • 解锁命令行的强大功能

以下是一点Bourne Shell代码。欣赏这些boolean表达式吧!

#!/usr/bin/env sh

l="1"
while [ "$l" -le 5 ]
  do
  m="1"
  while [ "$m" -le "$l" ]
    do
    printf "*"
    m=`expr "$m" + 1`
  done
  echo
  l=`expr "$l" + 1`
done

C

就算你不喜欢C,也不得不尊敬它。它可以说是最伟大的语言之一。它能真正地能编写机器级代码(而不是其模型)。它是UNIX之父,是所有类C语言的鼻祖,是系统开发界的通用语。它久经沙场,经历时间的检验,广泛传播。太多的开发,调试,性能分析工具支持着C的发展,这也减少了它作为语言的缺陷(在我看来,缺陷不多)。这是一个真正实现了其目标的语言:适用于所有处理器的万用汇编语言。今天,它甚至能在最奇怪的体系结构中胜任实际上的汇编语言,与C编译器产生的代码相比,要手写出更好的代码十分困难。

因此,C是一个强大的工具,但要掌握好它可不容易。这种语言冷酷无情,你得十分清楚自己在干什么。正因为如此,C语言是教人理解机器的语言。这里面有美妙之处,也有实用的一面:如果没有C语言提供的底层功能,有些事情就没法实现。C语言程序员必须彻底理解自己在干什么,长远来看,这使得他们能产出高度可靠的软件。如果有种语言能影响C语言的神圣地位,那一定是一种很好地支持并发的低级语言,或者是性能如Haskell、风靡如C语言的神一般的语言。

Linux内核中的一些C语言代码

int next_pidmap(struct pid_namespace *pid_ns, unsigned int last)
{
    int offset;
    struct pidmap *map, *end;

    if (last >= PID_MAX_LIMIT)
        return -1;

    offset = (last + 1) & BITS_PER_PAGE_MASK;
   map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];
   end = &pid_ns->pidmap[PIDMAP_ENTRIES];
   for (; map < end; map++, offset = 0) {
       if (unlikely(!map->page))
           continue;
       offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
       if (offset < BITS_PER_PAGE)
           return mk_pid(pid_ns, map, offset);
   }
   return -1;
}

C++

怪物。它是我接触的第一种语言,直到尝试了许多其他语言后,我才明白它多么严重地影响我的效率,限制我的技术。一些著名的程序员对C++评价甚低,对此我完全赞同。C++像是Bjarne Stoustrup把他能想到的所有的功能都加到C中的成果。掌握C++耗费精力巨大,可能使编程效率降低80%以上。这样想吧:你的大脑容量是X,容量有限,不管你有多少的能力,都应该尽可能为重要的事情留出空间。明智的做法是少在语言本身上用脑力,大部分用来解决问题,编写算法。如果语言复杂,无论你有多聪明,都要在语法和语义上花费更多脑力,而不能专注于用代码实现你的想法。

我认为C++是高难度低收益的典型例子。我同意,用C语言编写大的程序很困难(但依然可能,看Linux内核)。从各方面看Go,Rust和D语言都更好,但事实是C++在世界范围内被广泛应用。

下面是一个优秀C++代码的例子,使用了模板。C++代码中像这样的用户代码段比模板或者类的定义好懂的多。

#include <fstream>
#include <string>
#include <iostream>

int main( int argc , char** argv )
{
    int linecount = 0;
    std::string line;
    std::ifstream infile( argv[ 1 ] );
    if( infile )
    {
        while( getline( infile , line ) )
        {
            std::cout << linecount << ": " << line << '\n';
            linecount++;
        }
    }
    infile.close();
    return 0;
}

然后是模板代码,这个例子很简单(但会自然地变得乱七八糟)。

namespace rosettacode
{
  template<typename T> class queue
  {
  public:
    queue();
    ~queue();
    void push(T const& t);
    T pop();
    bool empty();
  private:
    void drop();
    struct node;
    node* head;
    node* tail;
  };

  template<typename T> struct queue<T>::node
  {
    T data;
    node* next;
    node(T const& t): data(t), next(0) {}
  };

  template<typename T>
   queue<T>::queue():
    head(0)
  {
  }

  template<typename T>
   inline void queue<T>::drop()
  {
    node* n = head;
    head = head->next;
    delete n;
  }

  template<typename T>
   queue<T>::~queue()
  {
    while (!empty())
      drop();
  }

  template<typename T>
   void queue<T>::push(T const& t)
  {
    node*& next = head? tail->next : head;
    next = new node(t);
    tail = next;
  }

  template<typename T>
   T queue<T>::pop()
  {
    T tmp = head->data;
    drop();
    return tmp;
  }

  template<typename T>
   bool queue<T>::empty()
  {
    return head == 0;
  }
}

C#

企业语言,为实现在大型机构中的可替换性而着力降低程序员的创造性。面向对象,静态类,冗赘,有大量的库和boilerplate模板,一切都暗示着它身上微软的血统。别误会,这个语言并不差。它只是不诱人,而这正是微软的目标。起码,它与Visual Basic相比有了长足的进步。我在以下情况使用:

  • Windows下开发
  • 游戏开发(好吧,主要是迫于微软,我还是更喜欢老伙计C或者C++)
  • 这个语言里出了轰动性事物:Unity3D, Xamarin, .NET, XNA。

代码示例

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static SortedDictionary<TItem, int> GetFrequencies<TItem>(IEnumerable<TItem> items)
    {
        var dictionary = new SortedDictionary<TItem, int>();
        foreach (var item in items)
        {
            if (dictionary.ContainsKey(item))
            {
                dictionary[item]++;
            }
            else
            {
                dictionary[item] = 1;
            }
        }
        return dictionary;
    }

    static void Main(string[] arguments)
    {
        var file = arguments.FirstOrDefault();
        if (File.Exists(file))
        {
            var text = File.ReadAllText(file);
            foreach (var entry in GetFrequencies(text))
            {
                Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
            }
        }
    }
}

是不是很像Java?

Objective-C

比起C++(和C#),我对Objective-C印象好得多。它的语法不漂亮,但是作为语言我喜欢它。它有一套很好的基于NextStep的库,它是C语言的真正的升华,而且没有扩展到失控、使关键字与其父语言产生歧义。正如我说的,它的代码不太美观并且不容易读懂,尤其是嵌套函数时,但它的美妙在于概念和方法,而不在语法。看这个嵌套调用:

char bytes[] = "some data";
NSString *string = [[NSString alloc] initWithBytes:bytes length:9 encoding:NSASCIIStringEncoding];

对于C语言的后代来说,这是段美妙的代码,用到了Objective-C中所谓的代码块。

#import <Foundation/Foundation.h>

typedef NSArray *(^SOfN)(id);

SOfN s_of_n_creator(int n) {
  NSMutableArray *sample = [[NSMutableArray alloc] initWithCapacity:n];
  __block int i = 0;
  return ^(id item) {
    i++;
    if (i <= n) {
      [sample addObject:item];
    } else if (rand() % i < n) {
      sample[rand() % n] = item;
    }
    return sample;
  };
}

int main(int argc, const char *argv[]) {
  @autoreleasepool {

    NSCountedSet *bin = [[NSCountedSet alloc] init];
    for (int trial = 0; trial < 100000; trial++) {
      SOfN s_of_n = s_of_n_creator(3);
      NSArray *sample;
      for (int i = 0; i < 10; i++) {
        sample = s_of_n(@(i));
      }
      [bin addObjectsFromArray:sample];
    }
    NSLog(@"%@", bin);

  }
  return 0;
}

Clojure

作为Scheme程序员,我对Clojure怀有敬意:这是人们所说的现代Lisp,有着独到的特性。我认为Clojure的长处是与Java之间的互操作性和核心语言中的并发功能。它与Scala如同手足,但各有特点:一个是Lisp,一个是面向对象和函数式语言的混合体,Clojure因为括号过多而较为冷门。选择这两种语言中的哪一个进行编程取决于个人风格,因为两者都没有长期而成功的应用程序产出为其提供支撑,这点上它们不及同样基于JVM的Java和PHP。对于任何基于JVM的语言,另一件需要考虑的事情是虚拟机的启动时间,它们处理起小任务来略显笨重。我会在以下情况用Clojure:

  • 网络编程。网络编程有许多好选择,Clojure族群在这个领域看起来十分活跃。
  • 想绕过Java那一套来使用JVM时。这能让程序员既开心又高效。
  • 探索性的编程,发展成产品代码的探索。这实际上是Lisp的强项,但Clojure基于Java,有许多开源代码资源。
  • 安卓程序开发?安卓程序开发的图形用户借口模式很大程度是基于类继承(这意味着你能将它作为一个插件库使用,而必须遵循某些结构)。这可以实现,但是不像直接用Java继承那样自然。

经典的Clojure代码:

(defn divides? [k n] (= (rem n k) 0))

(defn prime? [n]
  (if (< n 2)
    false
    (empty? (filter #(divides? % n) (take-while #(<= (* % %) n) (range 2 n))))))

Lisp式的简单队列定义,

(defn make-queue []
  (atom []))

(defn enqueue [q x]
  (swap! q conj x))

(defn dequeue [q]
  (if (seq @q)
    (let [x (first @q)]
      (swap! q subvec 1)
      x)
    (throw (IllegalStateException. "Can't pop an empty queue."))))

(defn queue-empty? [q]
  (empty? @q))

D

我以前喜欢D,D就像是完善版的C++。D1像面向底层的Python,比如Python和C的合体之类的。它棒极了:你能感觉到开发起来多迅速,它专注于算法而不是语言,但并不牺牲底层控制,以备不时之需。D2带有许多C++的复杂性,还带着Andrei Alexandrescu的创新意味。一部分人对此不满意,尽管D2对并发性更加重视。D2不再是一种简洁的语言,但因为有许多未测试的功能,它感觉更像个实验性的语言。我还是喜欢它的,但我认为在C++的高使用率面前,它的功能相形见绌(一旦复杂起来)。另外我认为Go正在吞并D本应获得的市场。就算把D做得更快、功能更酷,Walter和Andrei也没法与Google竞争。你可能正如我一样喜欢D,但它前景并不明朗。还是继续用C++,或者试试Go吧,它的本地并发支持更强大。那么,我会在什么时候用D语言呢?

  • 从零开始开发一个与C有接口或者是与C++有联系的项目时。不过,你得提前设想好接口。举个例子,如果需要使用C++的GUI库,我不建议使用D。因为这通常以为着要从内部处理C++的继承,那么所有优势都会被抵消。如果需要C++的插件库,就这么做吧:创建对象,使用其函数,但不用模板或是C++的继承。
  • 进行底层编程并且需要快速二进制功能时。还是那样,做自己的事情,就像一个独立程序。
  • 希望语言能更好地在本地支持并发性时。

我们来看一些带有纯函数和不可变声明的D2的惯用法。

uint grayEncode(in uint n) pure nothrow {
    return n ^ (n >> 1);
}

uint grayDecode(uint n) pure nothrow {
    auto p = n;
    while (n >>= 1)
        p ^= n;
    return p;
}

void main() {
    import std.stdio;

    " N     N2      enc     dec2 dec".writeln;
    foreach (immutable n; 0 .. 32) {
        immutable g = n.grayEncode;
        immutable d = g.grayDecode;
        writefln("%2d: %5b => %5b => %5b: %2d", n, n, g, d, d);
        assert(d == n);
    }
}

表的最大元素:

[9, 4, 3, 8, 5].reduce!max.writeln;

它绝对比C++更简洁,更具表达力,差距不是一点点。

Erlang

这是一个目的明确的语言。Erlang的网页说得很清楚:(……)构建可扩展性强、可用性高的软实时系统。客户遍及电信、银行、电子商务、计算机电话和即时消息等行业。Erlang的运行时系统固有对并发、分布和容错的支持。Erlang经实践证明可靠,而且产出过一些高难度应用程序,例如WhatsApp.

代码本身给人功能强大之感,其语法简洁易读。

看一个简单的并发程序代码:

-module(hw).
-export([start/0]).

start() ->
   [ spawn(fun() ->  say(self(), X) end) || X <- ['Enjoy', 'Rosetta', 'Code'] ],
   wait(2),
   ok.

say(Pid,Str) ->
   io:fwrite("~s~n",[Str]),
   Pid ! done.

wait(N) ->
   receive
       done -> case N of
           0 -> 0;
           _N -> wait(N-1)
       end
   end.

Go

我还没有亲自用过它。但很显然,Google的这一尝试,目的在于创造一种基于C语言、带有C++优点、并发支持比两者都强的语言。它有优于C++的功能,而且简单得多。它没有不安全指针运算,拥有闭包、第一级函数和垃圾回收机制。Go可能是服务器语言的未来。所以,我什么时候会尝试Go呢?

  • 编写对性能和可靠性要求非常高的服务器应用程序,包括网络应用程序。
  • 编写需要底层控制的高并发代码(不然我更喜欢Erlang)。

Go的并发代码

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    words := []string{"Enjoy", "Rosetta", "Code"}
    rand.Seed(time.Now().UnixNano())
    q := make(chan string)
    for _, w := range words {
        go func(w string) {
            time.Sleep(time.Duration(rand.Int63n(1e9)))
            q <- w
        }(w)
    }
    for i := 0; i < len(words); i++ {
        fmt.Println(<-q)
    }
}

Haskell

比起这个列表上的其他语言,这种语言像是一种更高级的思考工具。它有一系列无所不能的程序库,还有一群死忠拥护者。可以说这是一种高门槛的语言。我认为,使用它能开拓思路,还能让你接触到编程界最聪明的人。

就算不用来写真正的程序,我认为Haskell也很值得学。虽然它是一种相对模糊的语言,但我把它定位为“适用”,因为它在某些方面有实际用处,金融业首当其冲。

Haskell的代码往往非常紧凑,表达力强,尽管有点抽象(因为很多函数是概念上的操作,而不是过程中的一步)。我个人不喜欢它的语法(我认为太多了),但至少它服务于一个目的,不混乱(说你呢Perl!)。这种语言漂亮而连贯,自己看吧:

binarySearch :: Integral a => (a -> Ordering) -> (a, a) -> Maybe a
binarySearch p (low,high)
  | high < low = Nothing
  | otherwise =
      let mid = (low + high) `div` 2 in
      case p mid of
        LT -> binarySearch p (low, mid-1)
        GT -> binarySearch p (mid+1, high)
        EQ -> Just mid

后篇将于明天发布,敬请期待

本文经原作者许可翻译,未经许可禁止转载

时间: 2024-11-11 06:10:12

[前篇]最好的编程语言(如何不再担忧,爱上代码)的相关文章

[Redhat9.0]Models-3安装备忘录之LINUX篇

[Redhat9.0]Models-3安装备忘录之MODELS-3篇(未完待续……) 2010-01-26 11:32:54|  分类: Models-3|举报|字号 订阅 写在前面:不知道是因为版本还是机器的问题,总之smoke现在进入瓶颈阶段了,僵持了N久之后导师终于坚持不下去了,现在models-3只好暂时停止,真是可惜啊.现在主攻MM5,期望不要再出什么状况,时间不是我能耗的起的啊! ----------------------------------------------------

从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十六 ║ Vue前篇:ES6初体验 &amp; 模块化

缘起 昨天说到了<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象&字面量&this>,通过总体来看,好像大家对这一块不是很感兴趣,嗯~~这一块确实挺枯燥的,不能直接拿来代码跑一下那种,不过还是得说下去,继续加油吧!如果大家对昨天的小demo练习的话,相信现在已经对JS的面向对象写法很熟悉了,如果嵌套字面量定义函数,如何使用this关键字指向.今天呢,主要说一下ES6中的一些特性技巧,然后简单说一下模块化的问题,好啦,开始今天的讲

【Linux】数据流重导向(前篇)

数据流重导向 (redirect) 由字面上的意思来看,好像就是将『数据给他传导到其他地方去』的样子? 没错-数据流重导向就是将某个命令运行后应该要出现在屏幕上的数据, 给他传输到其他的地方,例如文件或者是装置 (例如打印机之类的)!这玩意儿在 Linux 的文本模式底下可重要的! 尤其是如果我们想要将某些数据储存下来时,就更有用了! 1)什么是数据流重导向? 什么是数据流重导向啊?这得要由命令的运行结果谈起!一般来说,如果你要运行一个命令,通常他会是这样的: 我们运行一个命令的时候,这个命令可

医疗时鲜资讯:医疗行业未来的变革(续前篇)

背景: 上周参加完展会后,有感而发,将以往自己所阅读的或者了解的关于目前医疗行业的部分时鲜资讯进行了总结分析.尤其是文末猜测了未来可能会发生变革的几大方向,最近在健康界等医疗热门媒体中又发现了与自己想法类似的文章,此处就不强调谁资浅资厚,不争论谁先谁后,仅就未来医疗行业的发展趋势,继续啰嗦几句. 医疗变革: 全科医生培训: 深圳商报的吴江[1]在"'家庭医生'服务实至名归还差什么?"一文中提到了家庭医生服务的概念.文中也提到了,在国外"'全科医生'其实就是'家庭医生'&quo

《1024伐木累》-小白篇之开发网站,三天!(前篇)-总章节八

往期回顾: 空军k所,老王留下迷惘的耗仔独自与吴博士沟通需求,回到公司,老王又指定耗仔为新项目负责人,在退居"二线"月侠的热心帮助下,耗仔重新调整工作计划,新来的明儿也即将加入,一切似乎都在顺风顺水的发展着,下班时,一通电话打破了平静局面,光大人,月侠,耗仔要火速赶往空军某部,三天时间开发航空某部网站.   小序 人生! 若白驹过隙,匆匆而已, 光阴似锦,无法倒流, 青春宝贵,奋斗无休, 北漂! 有激情,有迷茫,有机遇,有挑战, 不拼搏又何必留恋? 年轻,真好! 引子 “走,走,快!吴

luogu P1120 小木棍 [数据加强版]

二次联通门 : luogu P1120 小木棍 [数据加强版] /* luogu P1120 小木棍 [数据加强版] 暴搜 + 剪枝 枚举可能的长度 挨个检查答案 二分显然正确性不能保障 搜索时从最大的开始找 放上当前木棍后的长度比枚举的长度要大, 则退出 若当前的长度与当前扫到的木棍长度相同, 或是还需要的长度与枚举的长度相同,则退出 若当前的木棍不符合要求, 则后面与它长度相同的木棍都不行 */ #include <algorithm> #include <iostream>

概率法求解三阶幻方[C语言]

#include <stdio.h> #include <string.h> int in[9]={1,2,3,4,5,6,7,8,9}; int s[9]; int re[3][3]; int sum(int su[]) { int i,re=0; for(i=0;su[i];i++) re+=su[i]; return re; } int main() { int i,j,k,count=0; memset(s,0,sizeof(s)); int SUM = sum(in);

WCF研究-前篇

前篇 1.从SOA说起 2.什么是WCF 3.WCF通信模型 4.Endpoint与ABC以及元数据 1.SOA (Service Oriented  Architecture) Ø 一种组件架构模型 Ø 主要特点 每个服务具有明确的服务边界. 服务独立,低耦合. 采用标准的契约定义和通信协议. 服务是自解释的. 2.WCF (Windows Communication  Foundation) Ø 是微软为SOA(Service-Oriented  Architecture)而设计的一套完整的

文本分类需要CNN?No!fastText完美解决你的需求(前篇)

http://blog.csdn.net/weixin_36604953/article/details/78195462?locationNum=8&fps=1 文本分类需要CNN?No!fastText完美解决你的需求(前篇) fastText是个啥?简单一点说,就是一种可以得到和深度学习结果准确率相同,但是速度快出几个世纪的文本分类算法.这个算法类似与CBOW,可爱的读着是不是要问CBOW又是个什么鬼?莫急,听小编给你慢慢到来,一篇文章,让你了解word2vec的原理,CBOW.Skip-