CoffeeScript的多行注释缩进地狱

CoffeeScript是一个长久以来被我诟病的语言, 说是语言其实有点超过了, 它不过是一个JavaScript的编译器而已. CoffeeScript的问题很多, 但为了编码效率, 我有时也不得不用它, 我的软件XiamiThief就是用它编写的.

CoffeeScript使用了类似于Python的缩进来区别代码块, 但不成熟的缩进机制会带来不必要的麻烦, 下面我将展示多行注释在CoffeeScript中的一些问题.

在JavaScript中编写多行注释是这样的:

/* 这是注释 */

在CoffeeScript中, /**/统一被用###来替代, 但这一点好处都没有. 试想我们有这样的代码:

func = ->  
  '这是这个函数的第一行'
  '这是这个函数的第二行'
  '这是这个函数的第三行'

由于一些原因, 我们需要把这个函数体的一部分注释掉, 像这样:

func = ->  
###
  '这是这个函数的第一行'
  '这是这个函数的第二行'
###
  '这是这个函数的第三行'

你会惊讶的发现, 编译器给出了一个UNEXPECTED INDENTATION错误, 因为你没有按统一的缩进添加注释.

理所当然, 我们会修改代码缩进来让编译器正常编译:

func = ->  
  ###
  '这是这个函数的第一行'
  '这是这个函数的第二行'
  ###
  '这是这个函数的第三行'

这里要注意, 如果你是使用空格缩进并且没有使用专业的代码编辑器的程序员, 很可能敲多或少敲一个空格导致缩进错误使得编译后的JavaScript与设想的不同.

比如

func = ->  
  ###
  '这是这个函数的第一行'
  '这是这个函数的第二行'
  ###
  '这是这个函数的第三行'

会被编译成

var func;

func = function() {

  /*
    '这是这个函数的第一行'
    '这是这个函数的第二行'
   */
};

'这是这个函数的第三行';  

当然专业人士是不会犯这种错误的, 继续说缩进的问题.

代码写到一半, 计划有变, 这个函数需要被注释掉, 所以我们修改代码:

###
func = ->  
  ###
  '这是这个函数的第一行'
  '这是这个函数的第二行'
  ###
  '这是这个函数的第三行'
###

嗯? 怎么又是UNEXPECTED INDENTATION错误.

简单想一想, 就知道是###出了问题, 这段代码中

###
func = ->  
  ###

是一段注释, 而

  ###
  '这是这个函数的第三行'
###

又是一段注释. 从这里可以看出, ###比//组成的注释结构, 不存在任何优势, 因为###的注释与//同样无法进行嵌套使用, 并且###强制要求代码缩进(判定方法也很奇怪), 难以分清头尾的关系.

相比之下, /**/是一种可以让你知道头尾的注释, 不需要代码加亮的编辑器, 不强制缩进, 如果不缩进, 可读性可能还会更高. 比如这样:

var func = function(){  
/*
  '这是这个函数的第一行'
  '这是这个函数的第二行'
*/
  '这是这个函数的第三行'
}

CoffeeScript在改良语言时, 却没有想到这点. 如果要注释的内容里已经包含了很多多行注释, 又不想删掉注释标记, 是很麻烦的.

在CoffeeScript中若想用/**/作为自定义注释标记, 会遭到编译器的阻止, 只好再想一个别的, 比如/##/, 像这样用:

###
func = ->  
  /#
  '这是这个函数的第一行'
  '这是这个函数的第二行'
  #/
  '这是这个函数的第三行'
###

不然的话, 代码就会演变成:

###
func = ->  
###
###
  '这是这个函数的第一行'
  '这是这个函数的第二行'
###
###
  '这是这个函数的第三行'
###

另一个问题是你已经将代码进行了多层缩进, 又有需要将其中的一部分代码独立出来运行, 缩进带来的麻烦会再次出现:

func1 = ->  
  func2 = ->
    func3 = ->
      func4 = ->
        console.log 'something'

注释掉func2到func4的函数嵌套:

func1 = ->  
  ###
  func2 = ->
    func3 = ->
      func4 = ->
  ###
        console.log 'something'

报错UNEXPECTED INDENTATION, 原因是console.log ‘somgthing’的缩进不对, 需要修改成:

func1 = ->  
  ###
  func2 = ->
    func3 = ->
      func4 = ->
  ###
  console.log 'something'

或者:

func1 = ->  
        ###
  func2 = ->
    func3 = ->
      func4 = ->
        ###
        console.log 'something'

JavaScript是这样实现:

var func1 = function(){  
  /*
  var func2 = function(){
    var func3 = function(){
      var func4 = function(){
  */
        console.log('something')
  /*
      }
    }
  }
  */
}

可以看出, JavaScript不需要退回缩进, 缺点只在于需要同时注释掉}. 而CoffeeScript虽然使用缩进来节省代码, 却没有让缩进变得灵活, 只能说是一种退步.

总结:

CoffeeScript缺乏灵活实用的缩进机制, 强硬的要求缩进, 没有考虑实用性, 并且###替代/**/的效果并不理想.

因为不能嵌套注释, 所以C类语法的教条是尽量少使用/**/, 而CoffeeScript使JavaScript脱离了C类语法的教条限制, 却没能实现嵌套注释, 着实令人失望.

也许有人认为这只是语言设计上的小问题, 无伤大雅, 但真正写很长的代码遇到需要注释大段内容时, 会让人很不爽.

个人认为, CoffeeScript使用###进行缩进, 还不如直接用JavaScript的/**/, 反而能减少误会.

如果要问什么语言支持嵌套注释的话, Apple在WWDC上新发布的Swift语言是支持的, 部分C/C++编译器也是支持的.