How do I assign the super method to a variable without calling it in CoffeeScript? - coffeescript

In CoffeeScript, I'd like to be able to assign the super method to a variable without calling it.
class a
one: ->
class b extends a
one: ->
mySuper = super
However doing the following actually calls the super method rather than returning it - here's the compiled code:
return mySuper = b.__super__.one.apply(this, arguments);
How do I actually assign the super method to a variable rather than calling it?
I know I could do:
class b extends a
one: ->
mySuper = b.__super__.one
But it isn't that clean.

Coffee script provides no syntax sugar for this use case. So do it yourself.
I would do it like this:
class B extends A
one: ->
mySuper = A::one
mySuper.call this # calls the saved super method
Example
:: is a shorthand for prototype. So A::one compiles to A.prototype.one which is where your super method actually is.
But this seems like a red flag to me. I can't think of a case where this would be a good idea. I'd wager it's not part of the language because if you design your classes properly, you shouldn't need this. You say you want something clean, but the thing you want to do here I wouldn't consider clean at all.

Related

Different field instances in class and parent/Call super constructor with method

I am trying to call the super constructor from a class using a method. The whole setup looks like this:
class Straight(hand: Hand) extends Combination(Straight.makeHandAceLowIfNeeded(hand), 5)
object Straight {
private def makeHandAceLowIfNeeded(hand: Hand): Hand = {
...
}
}
While this does compile, it has some rather odd runtime behaviour. While debugging, I noticed that the Straight instances have the "hand" property defined twice. Can somebody tell me what is going on, and what the proper way is to call the super constructor with different arguments?
In my use case, I want to call the super constructor with a modified hand in which I replaced a card compared to the original constructor argument.
Debugger screenshot with duplicate field:
.
It's a perfectly fine way to call the superclass constructor. These are two private fields and they don't conflict, though you can rename one of them to avoid confusion during debugging (or if you want to access the superclass' value from the subclass). However, the field should only be generated for a class parameter if it's used outside a constructor, and in your case it doesn't appear to be. Did you simplify the definition of Straight?

Override a method in a mock object

I need to write a unit test in which one of the dependencies of the tested object will be mocked. In that mocked object I would like to override one function (I do not care about the other functions at all).
What I need to do, is to provide a completely new implementation of that function. I am not particularly happy with providing mockito-style when / thenResult pairs for each potential input, i.e. I do not want to write:
when(mock.foo(5)).thenResult(3)
when(mock.foo(7)).thenResult(121)
...
I would rather like to write something like:
mock.foo = (a: Int) => if (a == 5) 3 else ...
Which mocking framework should I choose to substitute the whole implementation of a function in an easy way?
You don't need a mocking framework at all if you're only overriding one method and want to do it by actually defining the method.
If it's a class, just extend your class, override the method and inject your extension.
If it's an object or a final class of course you can't extend, but then you wouldn't be able to mock with many frameworks either, or inject an alternate easily.
http://scalamock.org/user-guide/advanced_topics/
See "onCall" method
(fooMock.increment _) expects(*) onCall { arg: Int => arg + 1}

Scala: late side effect initialisation

If I want late initialisation of an expression, I can use a lazy val. But what can I use to to do late side effect initialisation?
I want to do things like creating a menubar in a base class. The actual content of the menus are finalised in API independent traits, which are mixed into sub classes of the API dependant base class. Early initialisation does not work, because there are multiple vals that would have to be early initialised in every sub class.
Another alternative is to create a procedure and call it in the constructors of all the final sub classes. But this is still inelegant and not DRY.
Edit: I don't think Delayed Init will work, as far as I understand it because that will put the whole constructor /initialisation code into a delayed method , and I need to put only part of it at the end of the construction process.
I'm not entirely sure if I get the question right, but perhaps you could do something like this:
abstract class AbstractFoo {
lazy val menuBar = computeMenuBar
def menuBar: MenuBar
}
class ConcreteFoo extends AbstractFoo {
def menuBar: MenuBar = MenuBar("One", "Two")
}

CoffeeScript: what does the keyword 'super' do in this context?

class Animal
constructor: (#name) ->
move: (meters) ->
alert #name + " moved #{meters}m."
class Snake extends Animal
move: ->
alert "Slithering..."
super 5
So I was going through the CoffeeScript docs and ran into the above illustration of class extension. Can someone explain to me exactly what is happening when the line super 5 is executed? I vaguely understand it is calling the super class's definition of move with the argument, 5, but what would the output look like if one called mySnake.move assuming my snake's name is Robert?
super will call the move method on the base class. Specifically, it will call the Animal move method and pass in 5 as the meters parameter.
If you run the example on the CoffeeScript page, you should see an alert with "Sammy the Python moved 5m."
super is useful when your subclass has its own logic to run in addition to the base class implementation. You can place super right at the beginning of the method, or after additional code runs. Order might matter depending on the logic that's in place.

Using mixins in Coffeescript

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.