CoffeeScript Encapsulation and Variable Access - coffeescript

Trying to understand how CoffeeScript instance and class variable works I came with this code (and the results are in the comments).
class A
x: 1
#y: 2
constructor: (#z) ->
#console.log "const x", x #ReferenceError: x is not defined
console.log "constructor y", #y #undefined
console.log "constructor z", #z # = 3 for A and 6 for B
get: () ->
#console.log "get x", x #ReferenceError: x is not defined
console.log "get y", #y #undefined
console.log "get z", #z # = 3 for A and 6 for B
get2: () =>
#console.log "get2 x", x #ReferenceError: x is not defined
console.log "get2 y", #y #undefined
console.log "get2 z", #z # = 3 for A and 6 for B
#get3: () ->
#console.log "get3 x", x #ReferenceError: x is not defined
console.log "get3 y", #y # = 2
console.log "get3 z", #z #undefined
#get4: () =>
#console.log "get4 x", x #ReferenceError: x is not defined
console.log "get4 y", #y # = 2
console.log "get4 z", #z #undefined
class B extends A
constructor: (#w) ->
super(#w)
console.log '------A------'
i = new A 3
console.log "i.x", i.x # = 1
console.log "i.y", i.y #undefined
console.log "i.z", i.z # = 6
i.get()
i.get2()
A.get3()
A.get4()
console.log '------B------'
i = new B 6
console.log "i.x", i.x # = 1
console.log "i.y", i.y #undefined
console.log "i.z", i.z # = 6
console.log "i.w", i.w # = 6
i.get()
i.get2()
B.get3()
B.get4()
console.log '------------'
There are some strange things happening here:
x var
I was expecting to access it from any method but x var can't be accessed from any method or constructor (ReferenceError). I'm only able to access it from a instance of A or B (i.x). Why is that?
#y var
I was expecting to get #y var value from any method but it has no value in most of places (undefined value, not a ReferenceError exception). #y has value only on #get3 and #get4 (instance methods?). If it is defined, why I can't get its value?
#y and #z var
Both #y and #z are instance variables, but because #z was initialized in the constructor, it has a differentiated behavior. #y is valid on #get3 and #get4 and #z is valid on get and get2. Again, what is happening here?
The thing is that I'm really confused by these behaviors. Is this code correct? So, should I learn more about JS generated by CS?
Tks

In function bodies, # refers to this and in class definitions, # refers to the class itself rather than the prototype.
So in the example above, the definition of #y refers to A.y, and not A.prototype.y. It's tricky to refer to it because of the way this is bound in the various ways of defining methods. You can access it using #y from methods named #get because in this case this always refers to A.
The definition of x refers to A.prototype.x and so from your get methods you should access it via #x in get1 and get2.
As a basic guide, try not to use # outside of function bodies and everything will make a lot more sense:
class A
constructor: (#a) ->
b: 2
tryStuff: =>
console.log(#a) #will log whatever you initialized in the constructor
console.log(#b) #will log 2
EDIT: you could consider methods defined as #something to be static methods of that class, so you can call them with classname.something() but as static methods, they can't access any instance variables.

To respond to your questions:
x = 1 within the class body would create a variable named x within the scope body. But x: 1 within the class body defines a property x on the prototype. If you change console.log x to console.log #x, then you'll get 1.
Within the class body, # points to the class itself. Within the constructor (and in methods called as instance.method), it points to the particular instance. Change console.log #y to console.log A.y, and you'll get 2. (You can also use #constructor to get a reference to the class from the instance, because in JavaScript, the class actually is the constructor function.)
Since # in the constructor points to the instance, you're setting the instance's z property to the given value.
And yes, I do recommend understanding the underlying JavaScript—I know it's a bit odd for # to have so many different meanings, but it makes a lot of sense once you understand JavaScript's this (one of the trickier parts of the language, to be sure). Incidentally, my book has a lot more info on this.

Related

Dynamic variables, CALLERS, Scalars, and assignment

I recently noticed that that re-initializing dynamic variables does not have the semantics I expected in most cases using assignment (binding works the way I expected it to, however).
Specifically, in this code:
sub g {
my $*i = CALLERS::<$*i> // 0;
my $*a1 = CALLERS::<$*a1> // Array.new;
my #*a2 = CALLERS::<#*a2> // Array.new;
$*i++;
$*a1.push: 'v1';
#*a2.push: 'v2';
dd $*i;
dd $*a1;
dd #*a2;
}
sub f {
my $*i = 0;
my $*a1 = Array.new;
my #*a2 = Array.new;
g; g; g;
}
f
I expected output of 3, ["v1", "v1", "v1"], and ["v2", "v2", "v2"] but instead get 1, $["v1", "v1", "v1"], ["v2"]. Switching to binding solves the issue, so there's no problem I'm trying to solve – but I would very much like to understand why assignment doesn't work here. I notice that a Scalar pointing to an Array works, but a Scalar pointing to an Int doesn't. But in either case, I would have thought that the newly assigned variable would receive the value from CALLERS. What am I missing about the semantics of assignment?
What am I missing about the semantics of assignment?
I think what you're missing, doesn't have anything to do with dynamic variables per se. I think what you're missing is the fact that:
my #a = Array.new;
is basically a noop. Because of the single argument rule, it is the same as:
my #a = ();
which is the same as:
my #a;
So, in your example in sub f, the:
my #*a2 = Array.new;
in is just setting up an empty array in a dynamic variable.
Then in sub g the:
my #*a2 = CALLERS::<#*a2> // Array.new;
is just basically doing (because of the single argument rule):
my #*a2;
and hence you don't see the pushes you've done before, because every call it starts out fresh.
Regarding the value of $*i in sub g: that also is just incrementing a copy of the callers $*i, so the value remains at 1 in every call.
The reason that $*a1 works, is that containerization stops the flattening behaviour of the single argument rule. Observe the difference between:
sub a(+#a) { dd #a }; a [2,3,4]; # [2,3,4]
and:
sub a(+#a) { dd #a }; a $[2,3,4]; # [[2,3,4],]

Cartesian macros on type fields in Julia

The Base.Cartesian module offers the #nref macro:
using Base.Cartesian
i_1, i_2 = 1, 1
A = rand(3,3)
#nref 2 A i
This returns A[1,1]. However, #nref does not work with fields of a (custom) type:
type Foo
bar::Matrix
end
foo = Foo( rand(3,3) )
i_1, i_2 = 1, 1
#nref 2 foo.bar i
This results in an error:
ERROR: MethodError: `_nref` has no method matching _nref(::Int64, ::Expr, ::Symbol)
Closest candidates are:
_nref(::Int64, ::Symbol, ::Any)
The error seems reasonable as foo.bar is really the expression getfield(foo, bar).
Wrapping the #nref in a function and passing foo.bar works:
function baz(A)
i_1, i_2 = 1, 1
#nref 2 A i
end
baz(foo.bar)
But is there a way to make #nref 2 foo.bar i work?
If you assign foo.bar to a variable, like TT = foo.bar, then #nref 2 TT i works. This is basically free, as no copy is made, and inside a function optimization makes TT identical to foo.bar.

How do I refer to an outside alias from inside a piglatin macro?

I have an alias which I want to use in a macro:
foo = ....;
define my_macro (z) returns y {
$y = join $z in id, foo on id;
};
a = my_macro(b);
Alas, I get the error:
Undefined alias: macro_my_macro_foo_0
I can, of course, pass foo as en argument:
define my_macro (foo, z) returns y {
$y = join $z in id, $foo on id;
};
a = my_macro(foo,b);
Is this the right way?
If foo is actually a relatively complicated object, will it be recalculated for each macroexpansion of my_macro?
Yes the second approach is right one, you need to pass the alias as an argument to macro otherwise it will not be visible inside macro.
on the other side, alias defined inside the macro will not be access outside, in-case if you want to access the alias then use this format macro_<my macro_name>_<alias name suffixed with an instance>
I have simulated both the options
1. accessing alias from outside to inside macro(using argument)
2. accessing alias from inside macro to outside (using macro expanded name format)
example
in.txt
a,10,1000
b,20,2000
c,30,3000
in1.txt
10,aaa
20,bbb
30,ccc
Pigscript:
define my_macro (foo,z) returns y {
$y = join $z by g1, $foo by f2;
test = FOREACH $y generate $0,$2;
};
foo = LOAD 'in.txt' USING PigStorage(',') AS (f1,f2,f3);
b = LOAD 'in1.txt' USING PigStorage(',') AS (g1,g2);
C = my_macro(foo,b);
DUMP C;
--DUMP macro_my_macro_test_0;
Output of option1:
DUMP C
(10,aaa,a,10,1000)
(20,bbb,b,20,2000)
(30,ccc,c,30,3000)
Output of option2:
DUMP macro_my_macro_test_0
(10,a)
(20,b)
(30,c)
There are some restrictions in using the macro, like
1. not allowed inside nested for each stmt
2. not allowed to use any grunt commands
3. not allowed to include a user-defined schema
I suggest you to refer the below document link, this will definitely give some better ideas about macros and also how to use inside pig script.
http://pig.apache.org/docs/r0.13.0/cont.html#macros

Call by reference, value, and name

I'm trying to understand the conceptual difference between call by reference, value, and name.
So I have the following pseudocode:
foo(a, b, c)
{
b =b++;
a = a++;
c = a + b*10
}
X=1;
Y=2;
Z=3;
foo(X, Y+2, Z);
What's X, Y, and Z after the foo call if a, b, and c are all call by reference?
if a, b, and c are call-by-value/result?
if a, b, and c are call-by-name?
Another scenario:
X=1;
Y=2;
Z=3;
foo(X, Y+2, X);
I'm trying to get a head start on studying for an upcoming final and this seemed like a good review problem to go over. Pass-by-name is definitely the most foreign to me.
When you pass a parameter by value, it just copies the value within the function parameter and whatever is done with that variable within the function doesn't reflect the original variable e.g.
foo(a, b, c)
{
b =b++;
a = a++;
c = a + b*10
}
X=1;
Y=2;
Z=3;
foo(X, Y+2, Z);
//printing will print the unchanged values because variables were sent by value so any //changes made to the variables in foo doesn't affect the original.
print X; //prints 1
print Y; //prints 2
print Z; //prints 3
but when we send the parameters by reference, it copies the address of the variable which means whatever we do with the variables within the function, is actually done at the original memory location e.g.
foo(a, b, c)
{
b =b++;
a = a++;
c = a + b*10
}
X=1;
Y=2;
Z=3;
foo(X, Y+2, Z);
print X; //prints 2
print Y; //prints 5
print Z; //prints 52
for the pass by name;
Pass-by-name
Call by Value : normal way... values of actual parameters are copied to formal parameters.
Call by Reference : instead of the parameters, their addresses are passed and formal parameters are pointing to the actual parameters.
Call by Name : like macros, the whole function definition replaces the function call and formal parameters are just another name for the actual parameters.
By value - there is no changes out the function. all your actions vanish when the function finished.
By reference - your actions indeed changes the variables.
By name - I've never heard ...
Passing x+1 is not change, just tells to the function 3 instead 2 or etc...
This won't change the value of X, Y or Z if it is pass-by-value. When you use a function such as "foo()", it basically copies the variables (x, y and z) into other variables (a, b, and c) and does certain actions with them, without changing the originals (x, y and z). For you to change a value you would have to return a value, something like this:
foo(a, b, c)
{
a = a++;
b = b++;
c = a + b * 10;
return c;
}
x = 1;
y = 2;
z = 3;
z = foo(x, y+2)
Then x and y would be the same, but z would be (x+1)+(y+1)*10 which in this case would be 32.
in javascript :
primitive type variable like string,number are always pass as pass
by value.
Array and Object is passed as pass by reference or pass by value based on these condition.
if you are changing value of that Object or array with new Object or Array then it is pass by Value.
object1 = {item: "car"};
array1=[1,2,3];
here you are assigning new object or array.you are not changing the value of property
of old object.so it is pass by value.
if you are changing a property value of an object or array then it is pass by Reference.
object1.item= "car";
array1[0]=9;
here you are changing a property value of old object.you are not assigning new object or array to old one.so it is pass by reference.
Code
function passVar(object1, object2, number1) {
object1.key1= "laptop";
object2 = {
key2: "computer"
};
number1 = number1 + 1;
}
var object1 = {
key1: "car"
};
var object2 = {
key2: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1.key1);
console.log(object2.key2);
console.log(number1);
Output: -
laptop
bike
10
In Call by value, a copy of the variable is passed whereas in Call by reference, a variable itself is passed. In Call by value, actual and formal arguments will be created in different memory locations whereas in Call by reference, actual and formal arguments will be created in the same memory location.

Variable scope in coffeescript for loop?

array = [1,2,3,4]
for num in array
//do something
What is the value of num in the context of the rest of the function? Does num get scoped to the loop?
No, num doesn't get scoped to the loop. As you can see in compiled JS (as #epidemian pointed out) it is current scope variable, so you can access it also in the rest of the function (e.g. rest of the current scope).
But be careful in case of defining function callback inside the loop:
array = [1, 2, 3]
for num in array
setTimeout (() -> console.log num), 1
outputs
3
3
3
To capture current variable inside the callback, you should use do which simply calls the function:
for num in array
do (num) ->
setTimeout (() -> console.log num), 1