Since the release of Meteor 0.6.0 and the addition of file-level JavaScript variable scoping, I'm facing an issue using CoffeeScript classes, each of them being defined in its own respective file.
foo.coffee:
class Foo
...
subfoo.coffee:
class Subfoo extends Foo
...
As expected, and because of the changes introduced in Meteor 0.6.0, I'm getting the following error:
ReferenceError: Foo is not defined
Here's my question: how should one handle class definitions across files with CoffeeScript and Meteor >0.6.0? Ideally: is there a convenient way not to modify too much the way classes are defined in order to make sure these definitions (and core parts of my application) are not Meteor-dependent?
As noted in the CoffeeScript section of the docs:
Global variables can be set in CoffeeScript by using this (or
CoffeeScript's # shorthand)
As it turns out, CoffeeScript classes can be defined like:
class #Foo
which compiles to:
this.Foo = (function() {
function Foo() {}
return Foo;
})();
Assuming that foo.coffee is loaded before subfoo.coffee you can then do:
class #Subfoo extends Foo
Assuming, of course, that Subfoo needs be be assigned to the global scope. It's also worth mentioning that you'll need to expose your collections in a similar way. For example:
#Players = new Meteor.Collection 'players'
Also note that classes such as "Foo" are themselves a value, that you can assign to variables or put into a namespace yourself.
Using class #Foo is a great shortcut when you want to put that value directly into the global namespace.
But if you want to, you can also leave variables local and then add them to the global namespace yourself:
class Foo
...
Players = new Meteor.Collection 'players'
doThat = -> ...
_.extend(this, {Foo, Players, doThat})
Or if you'd prefer, you can have your "foo" module define just one global object foo that contains the exported values:
#foo = {Foo, Players, doThat}
Now modules that use the "foo" module can reference the values through the global variable foo:
class Subfoo extends foo.Foo
...
Or, if you'd rather be able to type just Foo even when exporting only foo, you can unwrap foo at the top:
{Foo, Players, doThat} = foo
class Subfoo extends Foo
...
Related
This question already has answers here:
ES6 - declare a prototype method on a class with an import statement
(3 answers)
Closed 5 years ago.
With an ES6 Class, you can declare methods as follows:
class Foo {
bar() {}
}
However, I need to import methods from an external file and load them into the class. Something like this:
const barMethod = require('./bar');
class Foo {
bar: barMethod
}
However, this doesn't work. I've looked around a while for the syntax for this and it isn't really mentioned. What is the right way to do this?
Is there a way to extend the Class perhaps? Because the Class is so big, I am breaking it out into several files for organizational purposes, but each method needs to be able to refer to the Class with this.
Mixins perhaps?
A class in ES6 still uses the .prototype so you can extend a class definition after its declaration, by adding methods to the `.prototype.
Original declaration:
class Foo {
bar() {}
}
Add some new methods:
Foo.prototype.newBar = someNewMethod;
Or, in a more modular way, perhaps you want to just pass Foo to each module in it's module constructor and it can just add its methods to Foo.prototype.
Or, each module could just define its own class with its own set of methods (all designed to eventually be Foo methods and then you could use one master function to import all the sub-definitions and copy all the methods from each of the imported classes to your main Foo class prototype to end up with one master class.
Keep in mind that methods are just functions on the prototype object, even when the class is declared with the ES6 class syntax. They can be assigned to other objects with regular Javascript that just operates on properties of an object.
You can .call() barMethod from Foo instance bar property, optionally setting this to this : Foo instance
class Foo {
bar() {
barMethod.call(this)
}
}
In Java I understand class fields as variables that are accessible from the whole everywhere in the class and that kind of describe the state-structure of instances. In Java field are defined outside any method (and this is the only thing that can be outside of methods).
In Scala "outside any method" is the main constructor - in other words: there is no "outside any method". Thus fields are defined in the main constructor. Thus any variable/value in the constructor is a field. Even arguments given to the constructor are automatically class fields and not local constructor variables as in Java.
In case I got all that right: Are there local variables/values in Scala constructors?
If not: Why was it decided that such a thing is not needed?
Clarficiation: I ask about concepts, not a specific case. Also I do not ask about how to work around to get something like local variables (although I would appreciate it if the answer were that there aren't any).
The entire class body is "the contructor".
You can always restrict the scope of any variable to be a small as you like with a pair of braces, so there is no reason to introduce an additional "concept", that serves no specific purpose. Occam's razor.
class Foo(bar: String) { // constructor parameter
val baz = "baz"; // class member
{
val bat = "bat" // "local" variable
println(bar + baz + bat) // all three are visible
}
println(bar + baz) // only first two are accessble
}
println (new Foo("bar").baz) // only class member can be accessed here
I am trying to use global variable in Scala. to be accessible in the whole program .
val numMax: Int = 300
object Foo {.. }
case class Costumer { .. }
case class Client { .. }
object main {
var lst = List[Client]
// I would like to use Client as an object .
}
I got this error :
error: missing arguments for method apply in object List;
follow this method with `_' if you want to treat it as a partially applied function
var lst = List[A]
How can I deal with Global Variables in Scala to be accessible in the main program .
Should I use class or case class in this case ?
This isn't a global variable thing. Rather, you want to say this:
val lst = List(client1, client2)
However, I disagree somewhat with the other answers. Scala isn't just a functional language. It is both functional (maybe not as purely as it should be if you ask the Clojure fans) and object-oriented. Therefore, your OO expertise translates perfectly.
There is nothing wrong with global variables per se. The concern is mutability. Prefer val to var as I did. Also, you need to use object for singletons rather than the static paradigm you might be used to from Java.
The error you quote is unrelated to your attempt to create a global variable. You have missing () after the List[Client].
If you must create a global variable, you can put it in an object like Foo and reference it from other objects using Foo.numMax if the variable is called numMax.
However, global variables are discouraged. Maybe pass the data you need into the functions that need it instead. That is the functional way.
I've come across the following syntax while looking through the Gatling source code:
private[http] def build = {
// ...
}
What is the syntax inside square brackets?
When I click through it in my IDE it is an alias to a fully qualified package (com.excilys.ebi.gatling.http) but I can't find where that alias was defined.
See the scala reference, specifically, chapter 5.2. Some excerpt:
The private modifier can be used with any definition or declaration in a template. Such members can be accessed only from within the directly enclosing template and its companion module or companion class (§5.4). They are
not inherited by subclasses and they may not override definitions in parent
classes.
The modifier can be qualified with an identifier C (e.g. private[C]) that must
denote a class or package enclosing the definition. Members labeled with
such a modifier are accessible respectively only from code inside the package C or only from code inside the class C and its companion module (§5.4).
Such members are also inherited only from templates inside C.
In short: this is used for scope protection:
private[C] means that access is private "up to" C, where C is the
corresponding package, class or singleton object.
Same to protected[C]
protected[C]: access is protected "up to" C, where C is the
corresponding package, class or singleton object.
I want to split up a large class by using mixins.
I am using this mixin code from the Little Book
#include: (obj) ->
for key, value of obj when key not in moduleKeywords
# Assign properties to the prototype
#::[key] = value
obj.included?.apply(#)
this
class FooMixin
b: => #something = 2
class Foo extends Module
#include FooMixin
a: => #something = 1
Problem is that # in FooMixin is FooMixin. I want it to be Foo instead.
I have tried adding the line _.bind(#::[key], #) at the end of #include() but it doesn't help. Any suggestions?
Okay, few things I was doing wrong.
1.
#include from the Little Book takes an object not a class. To get it to work with classes you need to write #include FooMixin::. However, I have since begun using objects instead.
2.
When using an object instead of a class, the fat arrow adds a line inside the CoffeeScript wrapper right at the top which reads _this = this. All methods are bound to the global context which is not what we want. To fix we must convert fat arrows to thin arrows, and bind each function to our Foo instance. Using Underscore I added this to the constructor of Foo:
constructor: ->
for fname in _.functions FooMixin
#[fname] = _.bind #[fname], #
super
I tried _.bindAll #, _.functions FooMixin but it gave me an error saying something like At Function.bind, could not run bind of undefined. Weird error, seeing as the code above is pretty much identical to the _.bindAll method.
So now I can split my classes up for better readability and code sharing.
UPDATE: The problem with _.bindAll is that it takes a splat not an array. Fix is to use _.bindAll #, _.functions(FooMixin)....
UPDATE: Found a better solution.
Same as original post. Use classes for mixins.
Use #include FooMixin:: or change #include to operate on a prototype instead of properties.
In the Foo constructor write FooMixin.call # which binds the methods correctly.
This works well and is nice and clean.
The only potential issue is that mixins will be overridden by existing properties. The only way to get around this that I can see is to do something like:
after = ->
_.extend Foo, FooMixin::
class Foo
# define...
after()
Or pass the extend method to _.defer but this is so hacky and probably won't work.