#function in CoffeeScript does not work as advertised - coffeescript

Rails 3.2.8. In converting some of my JS functions over to CoffeeScript, I have come across several questions that say declaring a function like so:
#foo = (bar) ->
puts foo in the global namespace. But it doesn't, because my function calls elsewhere in the application, especially ones that are in .js.erb files.
Here's what does work:
foo = (bar) ->
window.foo = foo
With that, all my calls in .js.erb files work fine.
What is the reason that the #foo = notation doesn't work as I am expecting it to? That would be a lot easier than having to remember to add an extra line to expose the function to the global namespace.

#foo translates to this.foo
foo translates to var foo
There is a big difference between the two of those.
For example:
bar = (baz) ->
#bar = 5
lemon = #bar + baz
#foo = (bar) ->
lemon
return #
Bar = new bar(12)
Translates to:
var Bar, bar;
bar = function(baz) {
var lemon;
this.bar = 5;
lemon = this.bar + baz;
this.foo = function(bar) {
return lemon;
};
return this;
};
Bar = new bar(12);
See fiddle demo of generated code: http://jsfiddle.net/maniator/rXWw2/
Here is a link showing you the CoffeeScript and it's generated code

I just wanted to add something that seems important to understanding why the initial
#foo = () -> "abc"
doesn't add to the global window object.
Coffeescript wraps - once compiled, it wraps all contents of every .coffee-file into a surrounding anonymous function that is immediately executed.
Thusly, and explicitely for that reason, the global namespace is not polluted, thereby implicitely protecting the dev from creating "evil" globals.
So, your foo becomes a member function of an anonymous wrapper function - how seriously useless gg ...
I guess what you want anyway is your global config object or something, to which you simply add your definitions --- you surely didn't mean to really create globals just for quick and easy access now, did you?? :)

Related

How to use let with typedef signals?

I'm trying to use let-constructs instead of `define in my TB to access some signals via hierarchical paths. It's not going that great. "Normal" signals seems to work and I can access them, but typedef-signals act strange.
Here's a super simple example code that I use to trigger the error:
module dut();
// Create a type
typedef struct {
int foo;
int bar;
} ty_fooBar;
// Instantiate the type
ty_fooBar fooBar;
// Create an "alias" for fooBar
let fooBar2 = fooBar;
// Assign some values and try to access the struct members
initial begin
fooBar.foo = 3;
fooBar.bar = 7;
$display("fooBar: %p", fooBar );
$display("fooBar2: %p", fooBar2 );
$display("fooBar.fooBar: %p", fooBar.foo );
// $display("fooBar2.fooBar: %p", fooBar2.foo ); <- ERROR
end
endmodule
Simulation gives this result:
# fooBar: '{foo:3, bar:7}
# fooBar2: '{foo:3, bar:7}
# fooBar.fooBar: 3
So, fooBar should now be the same as fooBar2, ModelSim shows this with the $display command, but for some reason I can access fooBar.foo but not fooBar2.foo. I tried reading the IEEE standard but that didn't enlighten me.
What's the deal with let and typedef? Do I have some profound misunderstanding?
The let statement combines the flexibility of a `define macro with the well formed structure of function.
Like a macro. the let arguments get replaced into the body of its definition. they may be typeless.
Like a function, a let declaration is local to a scope, including a package that can be imported. References to identifiers that are not arguments are searched from the point of the declaration. And finally the problem that you are facing is that a let statement can only be called where an expression is allowed. In fact it places parenthesis around the body before substituting.
So your reference to fooBar2.foo gets expanded as (fooBar).foo which is not legal.

Scope inconsistencies with coffeescript?

I am a beginner with coffeescript and I can't really understand the scoping. I have read that coffee always redefines variables so that it is impossible to leak anything. But look at the following code :
b = 2
bla = () ->
a = 1
b = 2
null
a = 1
which compiles to
(function() {
var a, b, bla;
b = 2;
bla = function() {
var a;
a = 1;
b = 2;
return null;
};
a = 1;
}).call(this);
So basically while exactly the same operations, in the same scopes, happen to a and b, the result is very different. b leaks outside of the bla function, while a doesn't. Is it a bug or maybe a feature I don't understand?
It's a designed behavior of CoffeeScript.
See Lexical Scoping and Variable Safety section of CoffeeScript docs for more info:
Notice how all of the variable declarations have been pushed up to the
top of the closest scope, the first time they appear.
In case of CofeeScript, it's a correct behavior, because it allows you to use upper-level variables, visible in your current lexical scope.
The thing that CoffeeScript lacks is a way to forcibly re-declare variable.

Coffeescript classes and scope

While learning coffeescript, I'm trying to create an instance of class A inside a method of class B, this is the code:
class #A
constructor: (#x) ->
show: ->
alert #x
class #B
constructor: (#y) ->
show: ->
a = new #A("eric")
alert a.x
alert #y
b = new #B("daniel")
b.show()
the error is TypeError: undefined is not a function.
Any help is appreciated.
Thanks
You have two problems:
# is just another way of saying this in CoffeeScript. That's all it means.
Classes are (more or less) just variables or properties like any other in CoffeeScript.
So when you say #A, you're just looking for the A property of this and your show is really saying:
a = new this.A("eric")
In that context, # will be an instance of B and Bs don't have A properties. Instead you should just say:
a = new A('eric')
Using # when defining a class:
class #A
#...
is just a way to make a class globally available. At the top level, # will (almost always) be window in a browser so you're really saying:
class window.A
#...
and window properties are globals. Keep in mind that each CoffeeScript file is wrapped in a function when it is converted to JavaScript:
Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.
So if you just said:
class A
then A would only be available to other code in that file. Saying:
class #A
makes A global.
If you're only working with one file then you don't need the #s on your classes:
class A
constructor: (#x) ->
show: ->
alert #x
class B
constructor: (#y) ->
show: ->
a = new A("eric")
alert a.x
alert #y
b = new B("daniel")
b.show()
Don't get in the habit of prefixing everything with #, only use it on classes when you need it and you know exactly what it will do. Even when you need it, there are better ways: use require.js to manage your dependencies, use an global application-specific object to manage scopes, ...

Getting Coffeescript to create a local variable in a FOR loop

How can I get dealViewItem into the scope of the FOR loop? Currently, dealViewItem is scoped outside of it, and all my event listeners are added to the last dealViewItem.
for deal in dealArray
dealViewItem = dealViewFactory.DealDetail(deal)
dealViewItem.addEventListener 'click', ->
dealCart.push(deal.dealId)
dealViewItem.setAddedToCart()
btnTakeDeals.setEnabled = true
dealHolder.add(dealViewItem)
this is what the do keyword is for. It will run a function immediately and any local variables with the same name as one of the arguments will be passed into it, ensuring proper closure scope.
for deal in dealArray
do (deal) ->
dealViewItem = dealViewFactory.DealDetail(deal)
dealViewItem.addEventListener 'click', ->
dealCart.push(deal.dealId)
dealViewItem.setAddedToCart()
btnTakeDeals.setEnabled = true
dealHolder.add(dealViewItem)
Check out the compiled version here
do can also be used outside of loops for self executing functions.
#coffeescript
do ->
foo = 'bar'
// javascript
(function() {
var foo;
return foo = bar;
})();

How to dynamically create named classes in Coffeescript without using eval?

I want to be able to write:
generate 'Cat', 'meow'
and define the generate function in such a way that it produces:
class Cat
meow: ->
#.__proto__.constructor.name + ' says meow.'
so that I can write:
garfield = new Cat
garfield.meow() # "Cat says meow"
If you don't mind polluting your global namespace, I actually got this snippet running in the 'try coffeescript' runner at the CoffeeScript site:
root = exports ? window
alert = alert or console.log
gen = (clsname, val) ->
root[clsname] = class
meow: => "#{clsname} says #{val}"
gen 'Cat', 'meow'
g = new root.Cat
alert g.meow()
gen 'Dog', 'woff'
d = new root.Dog
alert d.meow()
Not 100% what you asked for, but it's almost what you wanted, isn't it?
Edit: Actually, the first script only worked in the browser, not the (Node.js-based) CLI, corrected the script.
If you know you'll only live in the browser, you can loose root.Cat and only say Cat, but if you want Node.js and browser compat, you'll have to live with root.*
Edit 2: It's generally a better idea to return the class from the generating function rather than magically putting it in a namespace. It's also possible to make the method names dynamic. With some inspiration from #Loren, the asker (notice how it doesn't need to refer the global object anymore):
alert = alert or console.log
gen = (clsname, val) ->
C = class
C.prototype[val] = -> "#{clsname} says #{val}"
C
Cat = gen 'Cat', 'meow'
console.log Cat
g = new Cat
alert g.meow()
Dog = gen 'Dog', 'woff'
d = new Dog
alert d.woff()
If by "named class" you mean "a class with a named function," what you're asking for isn't possible—in CoffeeScript or JavaScript. Without eval, there's no way to create the equivalent of function FuncName() {...}. You can only use the __proto__.constructor.name property on functions defined with that syntax.
The class syntax is the only way of creating named functions in CoffeeScript, for reasons explained in the FAQ.