Wednesday, April 27, 2016

When do two variables refer to the same object, and how to copy a variable

One of my greatest confusions of JavaScript (and sometimes, greatest vexation) is when two variables refer to the same object. For example, ab, but c is not the same object as d here:
var a = b = [1, 2, 3];
a.shift();                     // 1
b;                             // [2, 3]
var c = d = "Hello, World!";
c = c.slice(0, -1);            // "Hello, World"
d;                             // "Hello, World!"
Here is the rule: when assigning one variable to another, the variables refer to the same object if and only if the object is not a primitive. So, if the object is a string, boolean, or number, they do NOT refer to the same object. Otherwise, they refer to the same object.

Overcoming variable reference with clones!

So, what can be done? What if I want to copy an object? I use a trick for Arrays all the time, inline in code: array.slice() returns a new copy of array, so that you can modify it without affecting the original. For objects, this is rather intuitive: iterate over each property and put it in a new object. So here's some code for a JavaScript "clone" method:
function clone(value){
	// throw an error for undefined input
	if(typeof value === "undefined")
		throw new ReferenceError("expected argument at 0: value from {clone}");
	
	// check for primitives
	if(typeof value === "number" ||
	   typeof value === "string" ||
	   typeof value === "boolean")
	   return value;	// nothing needs to be done
	
	// check for array/sliceable objects
	if(typeof value.slice !== "undefined")
		return value.slice();
	
	// otherwise, let's iterate through the object
	var retObj = {};
	for(var prop in value){
		retObj[prop] = value[prop];
	}
	return retObj;
}
Rather succinct, I like it enough.

Wednesday, April 20, 2016

Null-coalescing operators: when and when not to use them

Alright, this is something I've seen too many times in JavaScript code—even professionally—so I am going to address it here. This mistake is an easy one to make, and I use to make this mistake all the time; it's easy, simple, tempting, and nigh impossible to debug. I present to you: the null-coalescing operator. That is, the simple double-bar ||. Now, you might be wondering, "what's so bad about it?" Well, nothing. It's just bad programmers using it incorrectly.

The || operator is used in JavaScript not only to describe a disjunction, but also to specify default parameters to a function. (It's used in place of default parameter assignment, i.e. the one in function foo(bar=5){}, setting bar to 5.) It might be used (correctly) in the following situation:
function add(x, y, z){
 z = z || 0;
 return x + y + z;
}
This function successfully does what it's supposed to: add x and y, and z if specified. This works because of the short-circuiting property of ||. This operator is roughly equivalent to the following function:
function disjunction(LHS, RHS){
 if(LHS){
  return LHS;
 } else {
  return RHS;
 }
}
In this case, when the LHS is undefined, the value of the expression is RHS. However, the obverse of the statement (i.e. when LHS is defined then the value is not RHS and is thus is LHS) does not hold. Observe:
function multiply(x, y, z){
 z = z || 1;
 return x * y * z;
}
This works for most testcases (try it yourself) except for when z === 0; the expected result is 0, but what we get is x * y. Why? Well, let's look at what the disjunction yields. z = z || 1 becomes z = 0 || 1, which becomes z = 1, the incorrect result. This is why I follow this rule: when the RHS to the disjunction is truthy, use typeof z === "undefined" ? default : z; otherwise, one can use ||.

Saturday, April 2, 2016

Atoms and Tokens

The atomic score (or a.s., as abbreviated further in this post) of a program is the number of functional tokens in the program. Sometimes, the atomic score does not take into count separators such as parentheses and semicolons, in some languages. However, it is not immediately clear as to how many of these there are in a program.

I found a neat rule-of-thumb technique for calculating the a.s. of a JavaScript program, and any other line-independent program: put the smallest amount of code you can en each line without changing the program (i.e., without causing a syntax error). Let's look at the following program:
var userInput = Number(Prompt("Give me some input!!"));
userInput += 20;
alert("Your number plus twenty: " + userInput);
userInput >>= 1;
alert(userInput);
Let's line-ify this! We'll remove what whitespace we can in the process.
var
userInput
=
Number
(
Prompt
(
"Give me some input!!"
)
)
;
userInput
+=
20
;
alert
(
"Your number plus twenty: "
+
userInput
)
;
userInput
>>=
1
;
alert
(
userInput
)
;
This is 31 lines, or roughly 31 tokens. If we remove separators (parens etc.) and remove non-significant tokens (e.g. var and the trailing semicolon), this becomes 21 tokens:
userInput
=
Number
Prompt
"Give me some input!!"
;
userInput
+=
20
;
alert
"Your number plus twenty: "
+
userInput
;
userInput
>>=
1
;
alert
userInput

Examples

Let's try a some more examples that compare JavaScript, Jolf, a procedural golfing language, and some other various languages. For each task, I will provide a table for each language/language style and its respective a.s. Each program will be golfed to the intent of minimizing the a.s. This means that they will retain whitespace for readability. Each tokenized program will be followed by its a.s.

Task 1: Add two inputs

JavaScript (full program) Tokenized
alert(Number(prompt()) + Number(prompt()));
alert
Number
prompt
+
Number
prompt
a.s. = 5
JavaScript (ES6 arrow function) Tokenized
(a, b) => a + b;
a
,
b
=>
a
+
b
a.s. = 7
Jolf Tokenized
+jJ
+
j
J
a.s. = 3
Japt Tokenized
U+V
U
+
V
a.s. = 3
J, Jelly, APL Tokenized
+
+
a.s. = 1

Task 2: Summation over array

Takes input as [a, b, c, …, z] and outputs a + b + c + … + z.
JavaScript (full program) Tokenized
alert(prompt().split(",").reduce(function(p, c){
    return p + c;
}));
alert
prompt
.
split
","
.
reduce
function
p
,
c
return
p
+
c
a.s. = 15
JavaScript (ES6 arrow function) Tokenized
x => x.reduce((p, c) => p + c);
x
=>
x
.
reduce
p
,
c
=>
p
+
c
a.s. = 11
Jolf Tokenized
ux
u
x
a.s. = 2
Japt Tokenized
UrAB{A+B
U
r
A
B
{
A
+
B
a.s. = 8
J, Jelly, APL Tokenized
+/
+
/
a.s. = 2
Jelly Tokenized
S
S
a.s. = 1

Final remarks

Jelly is wicked short, and it's absolutely fantastic. Japt is beautiful, and I probably did something horribly wrong in my summation attempt. Finally, Jolf is my child, and it will also be first place in my mind.

Also, feel free to correct me if I'm wrong.