HN user

showell30

43 karma
Posts3
Comments38
View on HN

I'm one of the original developers of Zulip. The long comment I'm replying to is a somewhat rant-y critique of Zulip, but it's basically valid. We honestly have a hard time communicating the stream/topic paradigm, even though in some sense it's just forum/subfora.

I encourage vanderZwan and others to come to https://chat.zulip.org/# to talk to us. We're real people. We like the app we've developed, but we know it's far from perfect, and we especially know that our marketing could use some constructive feedback.

It's an interesting idea. My assumption is that stronger JS engines already do a good job of optimizing simply-written JS, whether the JS is hand written or produced by a transcompiler.

Transcompilers that were target-specific could probably target server-side JS at first. e.g. If you're just building a node.js app, there's no reason for the polyfill language to make any concessions to IE, for example. So one "optimization" is simply avoiding legacy cruft in the generated output. But I could also see exploiting specific features of cutting-edge JS engines.

I'm personally in favor of leaving JS mostly alone, especially at the syntax layer, and then let transcompiler solutions like CoffeeScript evolve to relieve the syntax burden and add semantic improvements.

CoffeeScript is far from perfect--it has syntax quirks of its own--but it's more pleasant for me to write in, being used to Python and Ruby. (And, yes, I understand JavaScript too; I just don't like the syntax.)

Eventually transcompiler languages will evolve to take advantage of different JS engine improvements. So far, this isn't a goal of CoffeeScript, but other abstraction layers might already be doing that.

The tool obviously works best with a fairly wide browser window, but patches are more than welcome to improve the CSS, which is obviously kind of primitive. For simple stuff, filing an issue would be great--no need for a full-blown pull request.

I agree with you that are some skeptics who will continue to move the goalposts. I also think that the tool itself won't change any minds.

My hope is that it can help early adopters get over the initial debugging barrier, which, despite the hype, is a legitimate concern. The tool can also be an aid for advocates in teaching coffeescript.

I also think that lack of line-number mappings is a fair criticism of coffeescript. If the article is rejecting FUD, then it should target statements like "debugging is a nightmare." I agree with the author's overall point that you can usually track down problems without a lot of fuss.

CoffeeScriptLineMatcher lets you see CoffeeScript/JavaScript code side by side. It's mostly geared toward debugging, but it also helps you examine the transformations made by the CS transcompiler.

I hope you change your mind about visiting the US, and the Silicon Valley in particular. If you're concerned about your safety or enjoyment while you're here, that's fine, but I wouldn't boycott the US to make a political statement. The strange minority of Americans who don't understand freedom aren't gonna get the message. Your boycott is gonna hurt the Americans who most want our country to be a diverse, welcoming place.

I highly recommend San Francisco in particular. We have a decent sized French expat population, and the city is fairly multi-cultural and liberal, even by European standards, I think. Once you arrive here, you're in driving range of stunning natural beauty--redwood forests, SF Bay, Yosemite National Park, Big Sur, etc.

Ok, I'll dial back the snark and just be blunt. I think all your concerns about CoffeeScript are hypothetical exaggerations. I don't think you've written much CoffeeScript at all, and I suspect that if you did, you'd quickly see that your concerns are overblown. In theory, you could have thousands of lines in a single file, and two commits from a separate branch could cause an undetectable accidental naming collision. In practice, this rarely happens. Files tend to be smaller, merge changes do to tend to get scrutiny, and name collisions often have fairly obvious symptoms once you run your tests on the code.

barrkel, I think you should create a new programming language with more sensible scoping than CoffeeScript, so that developers can create bug-free code while working in parallel on thousand-line codebases without close reviews. I would start by using "$" as a sigil to prevent top-level variables from being reassigned in nested scopes. It would be a visual shorthand that indicates that you are definitely not creating a new local symbol. This would prevent developers from needing to know the full set of symbols in the top scope. In fact, by eliminating the inadvertent reuse of variable names, you would eliminate the failure mode whereby what one developer thought to be a global symbol actually turned out to be modified. Eliminating this unexpected codeflow would be tantamount to eliminating memory corruptions in VM.

You should definitely go down this track. It would be a massive achievement.

Your example does demonstrate how CS works. When you assign bar a new value inside its original scope, the value of bar does indeed change.

  bar = ->
    "I called bar!"

  foo = ->
    console.log bar()
    bar = "I manually assigned bar!"
    return bar

  console.log foo()
  console.log bar()
  
Here is a slightly less contrived example:
  log = (data) ->
    console.log data
    
  enhance_logging = ->
    i = 0
    log = (data) ->
      i += 1
      console.log i, data

  log "no line numbers"
  enhance_logging()
  log "line one"
  log "line two"
  
Here is the output:
  > coffee foo.coffee 
  no line numbers
  1 'line one'
  2 'line two'

When I said the two programs have the same behavior, I was simply referring to the end result--what they output. I understand how both languages work here. Ruby solves a problem that simply doesn't exist in CS. In JS/CS "bar" never implicitly refers to "this.bar", so there's no ambiguity in the first place.

Well, this is a case where the equivalent CS behaves exactly like Ruby.

  class Foo
    bar: -> 'bar'
    baz: ->
      bar = "foo"
      console.log bar
    bang: ->
      console.log @bar()

  foo = new Foo()
  foo.baz()  # => "foo"
  foo.bang() # => "bar"

The problem with mandatory conventions is that they represent a different kind of user hostility--you're not trusting the developer to make his own decisions about variable names.

To give an example, many CoffeeScript programmers do follow simple naming conventions to call out top-level variables, such as CamelCase for classes or ALL_CAPS for constants. When you follow these conventions, it's pretty easy to avoid naming collisions.

In certain cases, though, you want a top-level variable to be lowercase, perhaps for stylistic reasons. If your files are relatively small, it's pretty easy to check for naming collisions when you introduce top-level variables after the fact, so a developer might decide that the risk is acceptable, especially if there is good test coverage.

Another kind of user hostility is to optimize for safety at all costs. I don't think any scoping mechanism totally eliminates the possibility of bugs, but some schemes do err on the side of safety over convenience. There's nothing wrong with trading off convenience for safety, but, on the other hand, you can make judgment calls that convenience and/or simplicity of the scoping model outweigh the risk of naming collisions.

Obviously, I like CoffeeScript, so I think Jeremy's made the correct tradeoffs. All languages work a little different--JavaScript, CoffeeScript, Python2, Python3, and Ruby all have different rules--and none of them are perfect in all situations. In all of the languages, though, it's reasonably straightforward to write correct code once you adopt general good practices--be careful with your names, and understand the language's approach to scoping.

You are correct about "last", "start's, etc., but there are also good examples in the CS sourcecode of easily avoiding naming conflicts with a sensible naming convention:

  browser.coffee:CoffeeScript = require './coffee-script'
  coffee-script.coffee:{Lexer,RESERVED} = require './lexer'
  coffee-script.coffee:    {Module} = require 'module'
  command.coffee:{EventEmitter} = require 'events'
  grammar.coffee:{Parser} = require 'jison'
  lexer.coffee:{Rewriter, INVERSES} = require './rewriter'
  nodes.coffee:{Scope} = require './scope'
  nodes.coffee:{RESERVED} = require './lexer'
  repl.coffee:{Script}     = require 'vm'

I wish that you would allow comments on your blog, so that folks following your twitter link would be able to see both sides of the issue, but I obviously understand your spam issues, which is why I said "wish" and not "should".

I wish that you would engage the CS community on this topic without the sole agenda of getting this fixed. It's true that the issue was put to rest a while ago, but the decision wasn't made in a vacuum--there was consensus involved. I think it's a little unfair to say that Jeremy "has expressed his unwillingness to deal with this issue"; that makes it sound like he was dismissing you or dismissing further debate on this, when in fact he just told you what had already been decided.

When I say you're overreacting on this issue, it's just my opinion, so don't get too worked up about it. You had a bug. "Log" means two things. IMHO you don't need to fork coffeescript; that would be a gross overreaction, but YMMV.

You are not doing anything wrong by taking the time to write up your opinion in a blog--if I implied that in any way, it was not out of malice; it was just imprecise writing on my part.

Just to be completely clear, variables are only at top level scope if you declare them at top-level scope. The variables "x" below are completely encapsulated within f1 and f2. The variables at top-level scope are intentional in the code below--I really do intend f1, f2, and how_many_times_functions_have_been_called to refer to the same entity throughout the file.

  how_many_times_functions_have_been_called = 0

  f1 = ->
    how_many_times_functions_have_been_called += 1 # refers to top-level scope
    console.log x # undefined
    x = 1
    console.log x # 1

  f2 = ->
    f1() # refers to f1 at top-level scope
    how_many_times_functions_have_been_called += 1 # refers to lop-level scope
    console.log x # undefined
    x = 2
    console.log x # 2

  f1() # you can call f1, it's at top-level scope
  f2() # you can call f2, it's at top-level scope
  console.log how_many_times_functions_have_been_called # 3, refers to top-level scope
  console.log x? # false, x does not exist at top_level scope

You are correct that variable scoping goes all the way to the top, but nobody is forcing you to create top-level variables with overloaded names like "log". Seriously, if you have a file that uses log files and logarithms, just take some care to distinguish the concepts. Use "log_file" for log files; use "logarithm" or "Math.log" for inverse exponentation.

In fairness, Armin (the author the blog post) did engage Jeremy (the author of coffeescript) on this issue over twitter. I wish that he would allow comments on his blog. I also wish that he could engage the broader CS community in a proper forum before dissing the language and/or creating a fork of the language. He's overreacting. This whole blog post apparently started because he had a naming collision with "log" in one of his programs. CS does have a mailing list, but most of the action happens via github issues.

Nope, I get it, you were suggesting ":=" as a replacement for the "nonlocal" keyword in Python. I'm not sure how my comments demonstrate any lack of reading comprehension. All I said about ":=" and "nonlocal" is that they are overly complicated once you accept that top-level variables can have wide scope.

Obviously, plenty of folks managed to write bug-free code in Python before "nonlocal" was invented. I'm not saying it's a bad idea, but you can avoid bugs without it.

CoffeeScript's approach toward top-level variables is quite elegant and simple. When you declare a variable at top-level scope, it is equally available to all code within that file for both reading and writing, with no strange "nonlocal" or ":=" syntax to complicate manners.

Once you understand the reach of CoffeeScript's top-level variables, it is easy to write bug-free code. Since you know that top-level variables have wide scope, you simply need to be judicious about putting variables at top-level scope. If a variable is not needed at top level scope, don't put it there.

My intro CS class in college started with a week of Karel. It was incredibly fun for me, but I can't vouch for it as a first language, since I had already learned Basic and Pascal in high school. (Yep, I'm old). Karel variants are actually very challenging in a way--the syntax is dead simple, but its lack of constructs forces you to be fairly clever.