Get a reference to the instantiated object within its own class method? - methods

I'm trying to return the instantiated object from its own method described in a class, but the only thing I get is the reference to the class, not the instance
class A
a: ()->
console.log(#)
b=()-> console.log(#)
b()
c: ()=>
console.log(#)
yoyo = new A
yoyo.a()
yoyo.c()
And it returns:
A {c: function, a: function}
Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}
A {c: function, a: function}
But what i'd want it the yoyo object to be returned, how can I achieve that ?

Your version doesn't work because b is just a plain old function and # (AKA this) generally depends on how a function is called: if you call a function as a function then # will usually be window.
There are lots of ways around this:
The old self = this trick works in CoffeeScript too:
self = #
b = -> console.log(self)
b()
This requires you to talk about self instead of # though. This approach doesn't seem to be as common as it used to be.
You can create a bound function using the native Function.protype.bind function:
b = (-> console.log(#)).bind(#)
b()
Function.prototype.bind gives you another function that always has the desired #.
You can create a bound function using CoffeeScript's fat arrow (=>) instead of the usual skinny arrow (->):
b = => console.log(#)
b()
This has the same effect as using Function.prototype.bind. This is probably the most common way to do this sort of thing in CoffeeScript.
Specify the desired # when you call the function by using Function.prototype.call or Function.prototype.apply:
b = -> console.log(#)
b.call(#) # or b.apply(#)
Which approach you use depends on your specific situation.

I think this example could say your gotchas
class A
a: false
b: -> alert #.a
yoyo = new A
yoyo.a = true
yoyo.b()
If # is class A not yoyo instance variable, then yoyo.b will tell you always false. but you try this via link

Related

How can I get argument values for a given lambda from the outside, without explicitly returning its `binding`?

I want to be able to run a lambda and get at its argument values (the values of a and b below).
I can achieve this by explicitly having the lambda return a binding, and then getting the values out of this binding:
fun = lambda { |a, b = Time.now| binding }
fun_binding = fun.call(123)
puts "A is #{fun_binding.local_variable_get(:a)} and B is #{fun_binding.local_variable_get(:b)}"
# Outputs e.g.: A is 123 and B is 2022-04-29 20:14:07 +0200
Is it possible to get these values without running any code inside the lambda body? I.e. could I do
fun = lambda { |a, b = Time.now| }
fun.call(123)
and still get the a and b values somehow from outside the lambda?
(To provide context – I'm asking because I've experimented with this as a shortcut syntax for instantiating objects with ivars/readers automatically assigned. At this stage I'm more curious about what's possible than what is advisable – so I invite any solutions, advisable or not…)
I'm not sure how advisable this is, but you can use the TracePoint class with the :b_call event to grab the lambda's binding:
fun = lambda { |a, b = Time.now| }
fun_binding = nil
TracePoint.trace(:b_call) do |tp|
fun_binding = tp.binding
tp.disable
end
fun.call(123)
puts "A is #{fun_binding.local_variable_get(:a)} and B is #{fun_binding.local_variable_get(:b)}"
This is not a perfect solution and will fail if one of the argument default values enters a block on it's own (since the default values are evaluated before the :b_call event is fired for the lambda), but that could be fixed with some additional filtering inside the TracePoint handler.

Scala -> Ruby conversion: Confusing output

Ruby Code:
def fnAdd(x)
return ->(y) { x + y }
end
add1 = 1.method(:fnAdd)
puts add1.call(10)
Output: Proc:0x007f52658d3330#main.rb:2 (lambda)
I am having issues getting the desired output in the above code.
I'm basically trying to write the following Scala code (which calls a function that returns another function) in Ruby.
Scala Code:
def fnAdd (x:Int) = {
(y:Int) => x + y
}
var add1 = fnAdd (1)
var add2 = fnAdd (2)
println(add1(10))
println(add2(3))
Output: 11 5
I've made an attempt at converting the code to Ruby but I'm not sure if it is correct. I don't understand the output, which appears to be some kind of proc object.
Could someone please explain what I need to change to get the desired output?
I'm not sure how your first example is even running, as it produces a NameError on my machine. Regardless, #method is intended for accessing methods on specific objects. You've defined a standalone method which is already curried, not one inside of the Fixnum class. So you simply need to call it as a method.
add1 = fnAdd(1)
Also, Ruby has the same behavior as Scala with regard to returning the last expression in a method, so you don't need to use return in this case.
Edit:
Thanks to #JörgWMittag for pointing out a few flaws here. Defining #fnAdd at the top-level makes it a private instance method on Object. Since everything in Ruby is an object, Fixnum inherits from the Object class. Thus, 1.method(:fnAdd) is simply giving you the fnAdd method without actually passing it any arguments. Thus, it still expects to be called twice.
fnAddMethod = 1.method(:fnAdd)
add1 = fnAddMethod.call(1)
puts add1.call(10)
However, this would be extremely unidiomatic, so it's best to stick with the simpler solution.

Why doesn't Typescript Intellisense show Object extensions?

Consider this code to extend the Object type:
interface Object
{
doSomething() : void;
}
Object.prototype.doSomething = function ()
{
//do something
}
With this in place, the following both compile:
(this as Object).doSomething();
this.doSomething();
BUT: when I'm typing the first line, Intellisense knows about the doSomething method and shows it in the auto-completion list. When I'm typing the second line, it does not.
I'm puzzled about this, because doesn't every variable derive from Object, and therefore why doesn't Visual Studio show the extra method in the method list?
Update:
Even though the Intellisense doesn't offer the method, it does seem to recognize it when I've typed it manually:
What could explain that?!
...because doesn't every variable derive from Object
No, for two reasons:
1. JavaScript (and TypeScript) has both objects and primitives. this can hold any value (in strict mode), and consequently can be a primitive:
"use strict";
foo();
foo.call(42);
function foo() {
console.log(typeof this);
}
Here's that same code in the TypeScript playground. In both cases (here and there), the above outputs:
undefined
number
...neither of which is derived from Object.
2. Not all objects inherit from Object.prototype:
var obj = Object.create(null);
console.log(typeof obj.toString); // undefined
console.log("toString" in obj); // false
If an object's prototype chain is rooted in an object that doesn't have a prototype at all (like obj above), it won't have the features of Object.prototype.
From your comment below:
I thought even primitives like number inherit from Object. If number doesn't, how does number.ToString() work?
Primitives are primitives, which don't inherit from Object. But you're right that most of them seem to, because number, string, boolean, and symbol have object counterparts (Number, String, Boolean, and Symbol) which do derive from Object. But not all primitives do: undefined and null throw a TypeError if you try to treat them like objects. (Yes, null is a primitive even though typeof null is "object".)
For the four of them that have object counterparts, when you use a primitive like an object like this:
var a = 42;
console.log(a.toString());
...an appropriate type of object is created and initialized from the primitive via the abstract ToObject operation in the spec, and the resulting object's method is called; then unless that method returns that object reference (I don't think any built-in method does, but you can add one that does), the temporary object is immediately eligible for garbage collection. (Naturally, JavaScript engines optimize this process in common cases like toString and valueOf.)
You can tell the object is temporary by doing something like this:
var a = 42;
console.log(a); // 42
console.log(typeof a); // "number"
a.foo = "bar"; // temp object created and released
console.log(a.foo); // undefined, the object wasn't assigned back to `a`
var b = new Number(42);
console.log(b); // (See below)
console.log(typeof b); // "object"
b.foo = "bar"; // since `b` refers to an object, the property...
console.log(b.foo); // ... is retained: "bar"
(Re "see below": In the Stack Snippets console, you see {} there; in Chrome's real console, what you see depends on whether you have the console open: If you don't, opening it later will show you 42; if you do, you'll see ▶ Number {[[PrimitiveValue]]: 42} which you can expand with the ▶.)
Does number implement its own toString method, having nothing to do with Object?
Yes, but that doesn't really matter re your point about primitives and their odd relationship with Object.
So to round up:
this may contain a primitive, and while some primitives can be treated like objects, not all can.
this may contain an object reference for an object that doesn't derive from Object (which is to say, doesn't have Object.prototype in its prototype chain).
JavaScript is a hard language for IntelliSense. :-)

creating an instance of another object in javascript

I want to know whether this sentence is correct?
You can do:
var a = new A();
if and only if A is instanceof Function.
Simply you can create an instance of function and you know a function is an object. Why can't we create an instance of other user-defined objects? Like this:
var b={};
var c = new b(); //error
EDIT: How can I change b so that I can create an instance of that?
You can actually use Object.create() to have some sugar around ECMAscript's prototypal nature. Like
var b = { };
var c = Object.create( b );
Now, c will have b on its prototype chain. ECMAscript or more precisely, prototypal inheritance doesn't work exactly the same way as a "classical inheritance". By calling new when invoking a function, you actually receiving a newly created object aswell. You can modify and access that object via the this value within that such called constructor function.
However, you didn't inherit anything so far. You would need to create and fill the .prototype - object for your constructor function before you create instances of it. This pattern annoyed lots of people, so ES5 brought as a more convinient way to directly inherit from other objects using Object.create().
Simply you can create an instance of function and you know a function is an object. Why can't we create an instance of other user-defined objects?
It’s not quite correct to say “you can create an instance of function”. The new keyword is a bit misleading - it makes JavaScript look like it implements object-orientation using classes, when in fact it doesn’t.
What you’re actually doing with new A() is creating an object using the constructor function A. The new keyword tells the JavaScript interpreter to return an object from A - specifically the object referred to as this inside of A.
EDIT: How can I change b so that I can create an instance of that?
In your example, b is an object (var b={};). If you change b into a constructor function, then you can create objects using it. (By convention, constructor functions in JavaScript start with capital letters.)
So:
function B () {
}
var c = new B();
You can add things to the prototype object of B, and they’ll be accessible on c too (and on any other objects you create using B):
function B () {
}
B.prototype.NAME = 'B';
B.prototype.hello = function () {
alert('Hello!');
}
var c = new B();
c.NAME // 'B'
c.hello() // alerts 'Hello!'
Short answer: The new operator requires its operand to have a special internal method [[Construct]] that generic objects do not have.
Long answer:
11.2.2 The new Operator
The production NewExpression : new NewExpression is evaluated as follows:
1. Evaluate NewExpression.
2. Call GetValue(Result(1)).
3. If Type(Result(2)) is not Object, throw a TypeError exception.
4. If Result(2) does not implement the internal [[Construct]] method, throw a TypeError exception.
5. Call the [[Construct]] method on Result(2), providing no arguments (that is, an empty list of arguments).
6. Return Result(5).
The production MemberExpression : new MemberExpression Arguments is evaluated as follows:
1. Evaluate MemberExpression.
2. Call GetValue(Result(1)).
3. Evaluate Arguments, producing an internal list of argument values (11.2.4).
4. If Type(Result(2)) is not Object, throw a TypeError exception.
5. If Result(2) does not implement the internal [[Construct]] method, throw a TypeError exception.
6. Call the [[Construct]] method on Result(2), providing the list Result(3) as the argument values.
7. Return Result(6).
You can also do
var b = new a.constructor();

Uncaught type error with CoffeeScript and Backbone.js

Rails app, learning CoffeeScript and Backbone.js:
Uncaught TypeError: Cannot use 'in' operator to search for 'id' in easy
_.extend.setbackbone.js:205
Backbone.Modelbackbone.js:142
Gamegames.js:13
(anonymous function)games.js:34
jQuery.Callbacks.firejquery.js:1047
jQuery.Callbacks.self.fireWithjquery.js:1165
jQuery.extend.readyjquery.js:436
DOMContentLoadedjquery.js:924
Here is the code, games.js.coffee
jQuery ->
root = global ? window
class Game extends Backbone.Model
initialize: (#n, #diff) ->
console.log "--> Game.initialize()"
difficulty: ->
#diff
name: ->
#n
# Make class Game globally available
root.Game = Game
my_game = new Game('easy', 'hard')
console.log "my_game.name(), my_game.difficulty() --> #{my_game.name()}, # {my_game.difficulty()}"
I am missing something, but having trouble figuring out what...
Backbone model constructor functions expect a dictionary object with keys and values that will be set on that model. You didn't provide an object, and instead provided 2 strings. The error is cause by backbone trying to iterate through the object, but explodes because you can't legally do for (key in "easy").
You also shouldn't be using properties for model data. You should be using an object on instantiation or set() and get(). So, if I may correct your code:
jQuery ->
root = global ? window
class Game extends Backbone.Model
initialize: ->
console.log "--> Game.initialize()"
difficulty: ->
#get 'diff'
name: ->
#get 'n'
# Make class Game globally available
root.Game = Game
my_game = new Game n: 'easy', diff: 'hard'
console.log "my_game.name(), my_game.difficulty() --> #{my_game.name()}, #{my_game.difficulty()}"
See this example working here: http://jsfiddle.net/NMkna/
Note how we no longer accept arguments in initialize now. We can rely on backbone to set the proper attributes in the model, because we now pass in an object when creating the game. And the methods we define simply #get 'propname' in order to retrieve those values.

Resources