Coffeescript namespacing with different files - class

Consider the following classes:
class A
constructor: ->
#nestedA = new NestedA()
class NestedA
constructor: ->
#NestedA = NestedA
#A = A
class B
constructor: ->
#nestedB = new NestedB()
class NestedB
constructor: ->
#NestedB = NestedB
#B = B
In this way, classes A and B are available in the global namespace, and NestedA and NestedB are only available through the A and B namespaces, respectively. I like this approach, but this can lead to the separate coffeescript files getting rather large. Thus I was wondering whether there was a way to separate the classes (NestedA and NestedB) into separate coffeescript files and still maintain the namespaces?

You could use RequireJS to load NestedA.coffee as a dependency into A.coffee (and do the same for the Bs). And then use RequireJS to load A.coffee into your main application in the same way.
Class A
#NestedA = require('cs!NestedA)
This should work but it might be a bit of an architectural shift if you are not already using RequireJS.

I would do it this way. This approach is very similar to what TypeScript does, but the pattern fits just as well in CoffeeScript.
#a.coffee
A = do (A = A ? {})->
class Foo
constructor: ->
#nestedFoo = new NestedFoo()
class NestedFoo
constructor ->
greet: ->
console.log('Hello World')
#exports
A.Foo = Foo
A.NestedFoo = NestedFoo
A
#somwhere-else.coffee
foo = new A.Foo()
foo.nestedFoo.greet() #yields 'Hello World'
This approach has the advantage that you can add as many other features to the namespace from whatever other files you want.

Related

Why this map function does not give traits' simple names

I try to get names of all trait a class extends using getInterfaces which returns an array of trait's names. When I manually access each member of the array, the method getName returns simple names like this
trait A
trait B
class C() extends A, B
val c = C()
val arr = c.getClass.getInterfaces
arr(0).getName // : String = A
arr(1).getName // : String = B
However, when I use map function on arr. The resulting array contains a cryptic version of trait's names
arr.map(t => t.getName) // : Array[String] = Array(repl$.rs$line$1$A, repl$.rs$line$2$B)
The goal of this question is not about how to get the resulting array that contains simple names (for that purpose, I can just use arr.map(t => t.getSimpleName).) What I'm curious about is that why accessing array manually and using a map do not yield a compatible result. Am I wrong to think that both ways are equivalent?
I believe you run things in Scala REPL or Ammonite.
When you define:
trait A
trait B
class C() extends A, B
classes A, B and C aren't defined in top level of root package. REPL creates some isolated environment, compiles the code and loads the results into some inner "anonymous" namespace.
Except this is not true. Where this bytecode was created is reflected in class name. So apparently there was something similar (not necessarily identical) to
// repl$ suggest object
object repl {
// .rs sound like nested object(?)
object rs {
// $line sounds like nested class
class line { /* ... */ }
// $line$1 sounds like the first anonymous instance of line
new line { trait A }
// import from `above
// $line$2 sounds like the second anonymous instance of line
new line { trait B }
// import from above
//...
}
}
which was made because of how scoping works in REPL: new line creates a new scope with previous definitions seen and new added (possibly overshadowing some old definition). This could be achieved by creating a new piece of code as code of new anonymous class, compiling it, reading into classpath, instantiating and importing its content. Byt putting each new line into separate class REPL is able to compile and run things in steps, without waiting for you to tell it that the script is completed and closed.
When you are accessing class names with runtime reflection you are seeing the artifacts of how things are being evaluated. One path might go trough REPLs prettifiers which hide such things, while the other bypass them so you see the raw value as JVM sees it.
The problem is not with map rather with Array, especially its toString method (which is one among the many reasons for not using Array).
Actually, in this case it is even worse since the REPL does some weird things to try to pretty-print Arrays which in this case didn't work well (and, IMHO, just add to the confusion)
You can fix this problem calling mkString directly like:
val arr = c.getClass.getInterfaces
val result = arr.map(t => t.getName)
val text = result.mkString("[", ", ", "]")
println(text)
However, I would rather suggest just not using Array at all, instead convert it to a proper collection (e.g. List) as soon as possible like:
val interfaces = c.getClass.getInterfaces.toList
interfaces .map(t => t.getName)
Note: About the other reasons for not using Arrays
They are mutable.
Thet are invariant.
They are not part of the collections hierarchy thus you can't use them on generic methods (well, you actually can but that requires more tricks).
Their equals is by reference instead of by value.

Using a Lens on a non-case class extending something with a constructor in Scala

I am probably thinking about this the wrong way, but I am having trouble in Scala to use lenses on classes extending something with a constructor.
class A(c: Config) extends B(c) {
val x: String = doSomeProcessing(c, y) // y comes from B
}
I am trying to create a Lens to mutate this class, but am having trouble doing so. Here is what I would like to be able to do:
val l = Lens(
get = (_: A).x,
set = (c: A, xx: String) => c.copy(x = xx) // doesn't work because not a case class
)
I think it all boils down to finding a good way to mutate this class.
What are my options to achieve something like that? I was thinking about this in 2 ways:
Move the initialization logic into a companion A object into a def apply(c: Config), and change the A class to be a case class that gets created from the companion object. Unfortunately I can't extend from B(c) in my object because I only have access to c in its apply method.
Make x a var. Then in the Lens.set just A.clone then set the value of x then return the cloned instance. This would probably work but seems pretty ugly, not to mention changing this to a var might raise a few eyebrows.
Use some reflection magic to do the copy. Not really a fan of this approach if I can avoid it.
What do you think? Am I thinking about this really the wrong way, or is there an easy solution to this problem?
This depends on what you expect your Lens to do. A Lens laws specify that the setter should replace the value that the getter would get, while keeping everything else unchanged. It is unclear what is meant by everything else here.
Do you wish to have the constructor for B called when setting? Do you which the doSomeProcessing method called?
If all your methods are purely functional, then you may consider that the class A has two "fields", c: Config and x: String, so you might as well replace it with a case class with those fields. However, this will cause a problem while trying to implement the constructor with only c as parameter.
What I would consider is doing the following:
class A(val c: Config) extends B(c) {
val x = doSomeProcessing(c, y)
def copy(newX: String) = new A(c) { override val x = newX }
}
The Lens you wrote is now perfectly valid (except for the named parameter in the copy method).
Be careful if you have other properties in A which depend on x, this might create an instance with unexpected values for these.
If you do not wish c to be a property of class A, then you won't be able to clone it, or to rebuild an instance without giving a Config to your builder, which Lenses builder cannot have, so it seems your goal would be unachievable.

coffeescript scope of variable assignment vs property assignment in object's other properties

I'm writing some widgets for Ubersicht. It uses a node.js server and treats each .coffee file as a standalone widget object. I'm having issues defining constant settings to be used throughout one file. Currently I know of two ways to define this type of constant at the top of the file.
# Way 1
foo_1 = true
bar_1 = false
# Way 2
foo_2: true
bar_2: false
Further down in the same file either a property is assigned as a string or as a function. Each of the above two ways of defining an option only works in one of the two property types.
staticProperty: """Output #{foo_1} works here
but output of #{foo_2} doesn't work
"""
methodProperty: (input) ->
if foo_1 # Raises foo_1 is not defined
if #foo_1 # foo_1 is undefined which is expected
if #foo_2 # This works fine
I understand that way 2 add to the object's properties, but I'm not too sure how the way 1 assignment works given that the file is essentially defining an object. Can you explain this?
Also is there a way to define a variable that can be accessed from both places?
We'll look at a big ugly example to see what's going on:
class C
a: 6
b: #::a
c = 11
d: c
#e = 23
f: #e
g: -> #a
h: -> C::b
i: -> c
j: -> #constructor.e
a is a normal old property, in JavaScript it looks like:
C.prototype.a = 6;
b is also a normal old property that is attached to the prototype; here:
b: #::a
# is the class itself so in JavaScript this is:
C.prototype.b = C.prototype.a
and everything works just fine.
c is sort of a private variable. In JavaScript it looks like this:
var C = (function() {
function C() {}
var c = 11;
//...
})();
I've included more JavaScript context here so that you can see c's scope. c is visible to anything inside the definition of C but nowhere else.
d is another property that is on the prototype and looks like this in JavaScript:
C.prototype.d = c
This assignment happens inside the SIF wrapper that is used to build the class so var c = 11 is visible here.
e is a class property and in JavaScript is just:
C.e = 23;
f is another property on the prototype. # is the class itself in this context (just like in b):
f: #e
so we can get at e as #e and the JavaScript looks like:
C.prototype.f = C.e;
The g and h methods should be pretty clear. The i method works because it is a closure inside the SIF that is used to define C:
C.prototype.i = function() { return c; };
The j method works because it uses the standard constructor property to get back to C itself.
Demo: http://jsfiddle.net/ambiguous/tg8krgh2/
Applying all that to your situation,
class Pancakes
foo_1 = true
foo_2: true
We see that you can use either approach if you reference things properly:
staticProperty: """Output #{foo_1} works here
and so does #{#::foo_2}
"""
methodProperty: (input) ->
# foo_1 should work fine in here.
# #foo_1 is undefined which is expected
# #foo_2 works fine
I'm not sure why you're having a problem referencing foo_1 inside your methodProperty, it should work fine and does work fine with the current version of CoffeeScript.

Coffeescript classes and scope and fat and thin arrows

In a fat arrowed function of a coffeescript class, how can I access the scope of the class as well as the function?
Example:
class Example
foo: ->
$('.element').each => # or ->
#bar($(this)) # I want to access 'bar' as well as the jquery element
bar: (element) ->
element.hide()
So in this example, if I use a => then the # refers to the this of the class but the 'this' is then wrong, whereas if I use a -> for the each, then the 'this' is correctly scoped but but then how do I reference the class function bar?
Thanks!
While mak is right, he fails to point out that in coffee script you rarely need jQuery's each method, which as you noticed, punches your execution context in the face without your permission.
class Example
foo: ->
for element in $('.element')
#bar $(element)
bar: (element) ->
element.hide()
Coffee script's looping features support the concept of each without any actual custom library code at all. And they also do not generate a new scope or context meaning you dont need a fat arrow of any kind.
That's because in CoffeeScript # is an alias for this i.e. when you compile your .coffee to .js # will be replaced with this.
If Example::bar is ugly, I don't think there are 'prettier' solutions.
You can store a reference to this before calling .each:
class Example
foo: ->
self = #
$('.element').each ->
self.bar($(this)) # or self.bar($(#))
bar: (element) ->
element.hide()
After checking different solution. Here something appear for me as the most complete sample with each and click :
class MainApp
self = []
constructor: ->
self = #
toDoOnClick: (event) ->
self.bar($(event.target)) #hide the clicked object
bar: (element) ->
element.hide()
sampleMethod:->
$(".myDiv").click (e) -> self.toDoOnClick(e)
$('.element').each ->
self.bar($(this))

Extend class and pass all constructor arguments to super

How would you extend a class using CoffeeScript, but have the construction arguments passed to super?
Eg:
class List extends Array
# Some other stuff to make it work...
list = new List(1,2,3)
console.log list
[1, 2, 3]
In general, this would work without additional code; the parent constructor is used unless expressly overridden:
class A
constructor: ->
console.log arg for arg in arguments
class B extends A
new B('foo') # output: 'foo'
And the problem isn't that Array doesn't have a constructor method:
coffee> Array.constructor
[Function: Function]
The problem is just that Array is just plain weird. While arrays are "just objects" in principle, in practice they're stored differently. So when you try to apply that constructor to an object that isn't an array (even if it passes the instanceof Array test), it doesn't work.
So, you can use Acorn's solution, but then you may run into other problems down the road (especially if you pass a List to something that expects a true array). For that reason, I'd recommend implementing List as a wrapper around an array instance, rather than trying to use inheritance from a native object type.
While we're on the subject, one very important clarification: When you use super by itself, that does pass all arguments! This behavior is borrowed from Ruby. So
class B extends A
constructor: ->
super
will pass along all arguments to A's constructor, while
class B extends A
constructor: ->
super()
will invoke A's constructor with no arguments.
class List extends Array
constructor: ->
#push arguments...
toString: ->
#join('-')
list = new List(1, 2)
list.push(3)
list.toString()
=>
'1-2-3'
Using extends in CoffeeScript expects the superclass to be in CoffeeScript too. If you're using a non-CS class, e.g. Array in the original question, then you may encounter problems.
This solved the general case for me. It's a bit of a hack because it uses _super which probably isn't intended to be used in the compiled JS.
class MyClass extends SomeJsLib
constructor: ->
_super.call #, arg1, arg2
Or if you just want to pass thru arguments from the caller:
class MyClass extends SomeJsLib
constructor: ->
_super.apply #, arguments
In my exploration of javascript I required a generic way to create a class with a dynamic number of constructor arguments. As mentioned this won't work for array as far as I know, it will only work for coffee-script style classes.
Calling a specific function with a dynamic number of arguments is easy enough through .apply
args = [1, 2, 3]
f = measurement.clone
f.apply measurement, args
A class can extend a class saved in a variable. As a result we can write a function that returns new sub-classes.
classfactory = (f) ->
class extension extends f
Putting it all together we can create a function that returns new sub-classes in which we apply arguments to the super class's constructor.
classwitharguments = (f, args) ->
class extension extends f
constructor: () ->
extension.__super__.constructor.apply #, args
To use this new factory
args = [1, 2, 3]
instance = new (classwitharguments Measurement, args)
Thoughts? Comments? Suggestions? Limitations I didn't think about? Let me know.