Hacker News new | ask | show | jobs
by cheald 5286 days ago
Also, Ruby can shadow method names with local variable names just fine:

    class Foo
      def bar
        "bar"
      end

      def baz
        bar = "foo"
        puts bar
      end

      def bang
        puts bar
      end
    end

    foo = Foo.new
    foo.baz  # => "foo"
    foo.bang # => "bar"
1 comments

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"
Not quite; @bar is "this.bar", and is an unambiguous reference, not just "bar". In Ruby, because self can be implicit, it's literally just "bar" in both cases, and Ruby gives the local variable precedence over the method name. You can still invoke the method via self.bar, but accessing the method as just "bar" is shadowed by the variable. Additionally, even though the method may be invoked by referencing bar, you can't redefine the method by assigning a new method to bar. Neither Javascript nor Coffeescript has that behavior.

Here's a better example:

Ruby:

    def bar
      "I called bar!"
    end

    def foo
      puts bar
      bar = "I manually assigned bar"
      return bar
    end

    puts foo()
    puts bar()

    # =>

    I called bar!
    I manually assigned bar
    I called bar!
Coffeescript:

    bar = ->
      "I called bar!"

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

    console.log foo()
    console.log bar()

    # =>

    I called bar!
    I manually assigned bar!
    TypeError: string is not a function
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.
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'