Wednesday, November 30, 2011

JS Automatic Semicolon Insertion

Semicolon; Why should I care?

"Javascript is the only language which people dare to use before learning"
- Crockford

Actually I, myself belong to that category of people whom crockford mentions :)
But trying to be out..

So, What's new today?
Just a informative writeup about ASI

Ya, Javascript Automatic Semicolon Insertion

What is a legal statement in Javascript?
Following are some
var a=10;
;;; // 3 Empty Statements
var a = function() { };

Lets start
Try the following
var a=10;
function test() {
    var b;
    b = a;

Even though I didn't insert any semicolon [Statement Terminator] in line 5 and 7, the JS engine never throws an syntax error.
Reason: ASI Construct

Rules to remember:
    ** ASI will insert one for you, if you specify a line terminator @ [no line terminator] mentioned
       in the grammar specification
    ** Whenever a statement misses a semicolon and if the statement following it makes sense along with the former.
       Then JS engine will not place a semicolon. Perhaps it parse them as a single statement
    ** If the statement is the last one inside a scope then you might consider missing semicolons. ASI will take care of

Where ASI will mislead?
There are 6 places
1 return
2 break
3 continue
4 Post ++
5 throw
6 Anywhere :P

Let's see the grammar for the first five
1. Return Statement             ->    return [no line terminator] (space expression)
2. Break Statement              ->    break [no line terminator] (space label)
3. Continue Statement         ->    continue [no line terminator] (space label)
4. Post Increment Statement ->    [operand] [no line terminator] ++
5. Throw Statements             ->    throw [no line terminator] [space expression]

Try it yourselves:
function test() { //Sample 1 Fails Silently
    var a =10;
        avalue: a

function test() { //Sample 2 Throws Syntax Error
    var a =10, b = 10;
        avalue: a,
        bvalue: b

function test() { //Sample 1 Fails Silently
    var a =10;
    return; --ASI rule 1-- Returns Undefined
        avalue: a

function test() { //Sample 2 Throws Syntax Error
    var a =10, b = 10;
    return; // --ASI rule 1-- Returns Undefined 
    {    //Considered as a Block Statement            
        avalue: a,  //Considers avalue as label and 'a' as the statement under it
        bvalue: b   //Considers bvalue as label and 'b' as the statement under it

According to ASI rule 1, there should not be any line terminator between return keyword and optional value.
If there is line terminator then JS parser inserts one ';' for you and makes your life difficult in case 2 and even more in case 1 [fails silently]

Try it yourselves:
These things likely won't happen but...
outer:for(j=0;j<3;j++) //Sample 1
    test:for(var i = 0;i < 3; i+=1) {
            if(i === 2) {
                break     // JS Engine Inserts a ; and 'outer' becomes a reference to outer loop

var a = -10;        //Sample 2
var b = 10        
+a;        // Rule 2
console.log(a+' '+b);

var a, b = 10, c = 10, d = 1, e = 3;  //Sample 3
a = b + c
(d + e).toString(2);    //Rule 2

var a = 10;    //Sample 4

var b = 1; //Sample 5

var a = 10, b = 10; //Sample 6
    b++        // Rule 3

Tidy programming always helps and will keep javascript good :)

Monday, November 21, 2011

Making Javascript Good :)

Somethings I learnt from Crockford :)
Keep it right always :)
function a()  //Seems to be working but not :)
        name: 'a'

function a() {  //Keep braces always right. It works :)
    return {
        name: 'a'

There is no concept of block level scoping in javascript but the syntax exists. So, the former falls in that block hole and returns undefined.

It's not c or c++
var i = 'tamil';
for(var i = 0;i < 10;i++){

This is misleading because declaring 'var i' @ initialization of for-loop doesn't mean 'i' has the scope of the loop & it doesn't interfere with the one out.
There is no other scope than function scope in javascript. All our declarations are hoisted up to function scope no matter where ever they are. So, don't get misleaded :)

All you spend is 0 but you get a lot :)
function sample() { something
    var j = 10; something

As I mentioned earlier there are no other scopes other than functions. So, what happens here is
function sample() {
    var j = undefined; // Hoisted to the top always. Better we do it meaningfully as var j = 10; something
    j = 10; something

Keep the declarations @ the beginning always. It costs you nothing but it might save your time in future :)

You might know what you are doing :)
if(a = b) { //1

if(a == b) a(); c(); //2

You might know what you are doing, but don't expect others
I might think for 1, It as either
if(a == b) { //typo
a = b;
if(a) {

For 2
if(a == b) {
if(a == b) {

Be clear for others too :) It helps

ALL is always bigger than LOT :) U gotta believe :P
0 == false //true
'0'==false //true
'false'==false //false

These might not affect in lots of places but lot !== all :P So, Always use
0 === false //false
'0' === false //false
'false' === false //false

Without with
var test = {    //1
             name: 'xxx',
             age: 12
var age = 100;
with(test) {
    age = 200;

var test = {    //2
             name: 'xxx',
var age = 100;
with(test) {
    age = 200;

1 & 2 are not the same. So, don't rely on unreliable things out there :)

I think I'm becoming Crockford's fan :)

Thursday, November 17, 2011

A Javascript Introduction

Had a chance to read a nice javascript tutorial on variables and data types :)
Let's share :)

Q: How will I declare a variable?
var variablename;

Q: I don't like variablename I wish to have $$$$$, Is it possible?
A: Ya you can there is no restriction on varible names except
1. It should start with either a alphabet or $ or _
2. It should not use any reserve words like function, break, var, etc.,
3. It should not use any of the operators [!@#%^&*()-+=]

Q: Is there any javascript practise to declare variables?
A: The answers is upto you. But most common practise is using CamelCase [Inherited from java]
 var testvariable;
 function testFunction() {
 testObject = new Object();
Another way is Hungarian Notation - appending type of the field/variable to its name
var intAge = 19; //Interger
var strName = "xxxx"; //String
var bSet = false; //Boolean
var fpRate = 12.22; //Floating Point
var fMember = true; //Flag
Following such conventions would increase the readability factor of the code.

Q: What are the primitive types available?
A: numeric, string, boolean are the 3 primitive types available in JavaScript.
All these 3 Primitive types are wrapped by in-built Number, String and Boolean objects

Q: Wrapped by - means?
A: Number, String and Boolean are in-built objects, that support predefined methods for its instances.
Applying such methods over primitive types will also work, though they are not an instance of any of the above mentioned in-built objects.

Q: How is it possible?
A: On applying those methods over primitive types an anonymous instance of respective in-buit object is created and destroyed once the process is completed
var age = 12;
var hexAge = age.toString(16);
Here, a Number object is created and it wraps primitive type of 'age', then toString is applied. Once the result is assigned, the instance created is destroyed

Q: What about case sensitiveness?
A: Javascript is Case Sensitive
var age = 12;
var Age = 22; //Valid and Different from age

Q: What is this var? Why not int, float, String?
A: Javascript supports loose typing. Type of the variable is defined based on its content
var age; //Type undefined
var intAge = 12;  //Type numeric
var fpAge = 12.12; //Type numeric
var bAge = true; //Type boolean
var strAge = '12'; //Type string
var arMarks = new Array() //Type Array object
intAge = true; //Changes type to boolean
Every Un Initialized variable either declared or not will be initialized with undefined;
Every variable has a boolean value associated with it, to mention whether it is set or not

Q: How does String work?
A: Strings are array of characters quoted either using '' or "" [Either make no difference].
var strName = 'xxxx'; //valid
var strCity = "zz";  //valid
var strHobby = "I'm writing a blog"; //valid
var strMe = 'This is my number "12345"'; //valid
var strIV = 'I'm single'//Invalid
var strValid = 'I\'m single' //valid
Escaping characters is allowed and meaning is the same as other languages
Ex: \n, \t, \\, \'

Q: Guess the value of vars
var a = 1+2+3+'4';
var b = '4'+3+2+1;
A: a = 64 & b = 4321
+ -> Means Concatenation over strings and Addition over numerics
This is the only operator which converts numeric to string implicitly
Others convert the other way round

Q: Guess the value of vars
var a =  12/'4';
var b = '12'/'4';
var c = '12' > '4';
var d = '12' > 4;
A: a = 3 , b = 3 , c = false & d = true
Reason for c:
Both the operands are string so, it is equal to strcmp

Q: Guess the value of vars
var test = new Array('1',{"sample":'2'},'3',4,5,1.2,3.4);
var a =  test[0];
var b = test[1].sample;
var c = test[7];
var d = test['element'];
A: a = '1' ,b = 2 & c = undefined & d =undefined
Array in javascript itself is an in-built object. It is just a heterogenous collection.
It is always a hash where key for the hash is the index
So referencing an outof bound index [7] or not even an index ['element'] will never throw an error instead returns undefined

Some Typeconversion Facts
    Any arithmetic expression does implicit conversion [except + as mentioned earlier]
null---------Nan or 0 [Browser Dependent]
string-------corresponding value 
    + operator
object------[ObjectType object]
number------false if value is 0 or NAN, true other wise
string------true if not empty [empty is not equal to null]

What ever might be the type while outputting to the browser everything is converted to string :)

If we use some undeclared variable a prototype chain is followed to figure out its value.
var test = {
      'testFunc':function sampleFunc(){}

Chain:test->object [object is parent of all & end of prototype chain]

Here object test has its own prototype. On executing test.hai JS engine checks for hai in test's prototype. If not defined, it follows the prototype chain of test which is followed by object. If it couldn't find it in it's prototype it returns undefined instead any error.

You cannot access undefined of undefined, Means
var hai;
var sample = hai.test;//Invalid Will throw Type Error since base is undefined; // Invalid Will throw Referrence Error. Since bar is not even declared

Try all these yourself
false == 'false'
false == null
false == ''
false == undefined
false == 0
false == Nan
false == 'false'
true == 'true'
true == '1'
false == '0'
And wonder :)

I hope I'm Done :)

Tuesday, November 15, 2011

CQL(Cassandra Query Language) Reference

I think now I'm eligible to publish a blog post regd CQL. I wish this blog to be a tutorial rather a Syntax provider for various CQL queries

Points to remember
1. CQL doesn't support Composite Types[likely to chage]
2. CQL doesn't support Super columns
3. Counter values are returned in native format [atleast in php/using cqlsh]

Why should I prefer CQL?

1. Readability
2. Ease of use
3. SQL like
4. Stable

PHP => My Posts using PHPCassa
Python => Refer Here and Download it here
Java => JDBC Driver and Example is here
Ruby => This might help

Creating a Keyspace:
cqlsh> CREATE KEYSPACE sample WITH strategy_class = 'org.apache.cassandra.locator.SimpleStrategy' 
    ... AND strategy_options:replication_factor = 2;
: => Option Specifier

Use a Keyspace:
cqlsh> USE sample;
Don't forget to USE before use
'Sample' and 'sample' are different.

Create Column Family:
cqlsh> CREATE COLUMNFAMILY Test (date ascii PRIMARY KEY, name ascii, age int) WITH default_validation=ascii
    ... AND comparator=ascii
    ... AND replicate_on_write=true;

Insert Row:
cqlsh> INSERT INTO Test ('date', 'name', 'age') VALUES ('123', 'tamil', 12)
    ... AND TTL 20;

Update Counter Row:
cqlsh> UPDATE COUNTERTEST SET 'samplecounter' = 'samplecounter'+5 WHERE KEY='testkey';

Update Standard Row:
cqlsh> UPDATE Test SET 'name'='Tamil' WHERE 'date'='123'
We have named row key as 'date'
If you specify KEY instead 'date' your terminal might knock with
Bad Request: Expected key 'KEY' to be present in WHERE clause for 'Test'

cqlsh> SELECT * FROM Test WHERE 'date'='123';
date | age | dept | desc |  name | rollno |
 123 |  12 |  yyy |  zzz | tamil |    xxx |

cqlsh> SELECT 'a'..'f' FROM Test WHERE 'date'='123';
age | dept | desc |
 12 |  yyy |  zzz |

cqlsh> SELECT FIRST 2 'a'..'z' FROM Test WHERE 'date'='123';
age | dept |
 12 |  yyy |
cqlsh> SELECT REVERSED 'z'..'a' FROM Test WHERE 'date'='123';
rollno |  name | desc | dept | age |
   xxx | tamil |  zzz |  yyy |  12 |
cqlsh> SELECT FIRST 2 REVERSED 'z'..'a' FROM Test WHERE 'date'='123';
rollno |  name |
   xxx | tamil |

cqlsh> SELECT * FROM Test;
date | age |  name |
 123 |  12 |  yyy |  zzz | tamil |    xxx |
 345 |  12 | pamil |
 234 |  12 | camil |
cqlsh> SELECT * FROM Test LIMIT 2; 
date | age |  name |
 123 |  12 |  yyy |  zzz | tamil |    xxx |
 345 |  12 | pamil |

--After some random insertions
cqlsh> SELECT * FROM Test where 'date' in ('123', '124', '125');
date | age |  name |
 123 |  12 | tamil |
 124 |  12 | tamil |
 125 |  12 | tamil |


cqlsh> TRUNCATE Test;


cqlsh> DROP KEYSPACE sample;

Using Secondary Indexes we can query columns based on values rather by their names.
Creating Index
cqlsh> CREATE INDEX name_test_key ON Test (name);

Using the index
cqlsh> SELECT * FROM Test where name = 'tamil';
 date | age |  name |
  127 |  13 | tamil |
  123 |  12 | tamil |
  124 |  12 | tamil |

cqlsh> SELECT * FROM Test where name = 'tamil' and age > 12;
 date | age |  name |
  127 |  13 | tamil |

Note: I'm able to query based on age's value too as there is an index existing on name
So, I'm done :) Just refer this guy's blog for all constants, arguments and options

Friday, November 4, 2011

Cassandra CQL PHP Part 2

I have explained the way to execute CQL Queries from PHP via PHPCassa in my previous blogpost here and tutorial on cql queries here

It was difficult for me to remember the syntax of update and select CQL queries for Cassandra. Hence I wrote wrappers for them which are listed below

Update Counter Query:
  * $counterMap => Associative array of CounterColumn names and corresponding value for given $key
  * Ex: UPDATE TestCounterFamily SET 'counter'='counter'+1, 'counter2'='counter2'+3 WHERE KEY='test'
function generateUpdateCounterQuery($columnFamily, $counterMap, $key) 
  $colArgs = "";
  foreach($counterMap as $counter => $value)
      $colArgs=$colArgs."'".$counter."'='".$counter."'+".$value.", ";
  $colArgs = rtrim($colArgs,", ");
  return "UPDATE ".$columnFamily." SET ".$colArgs." WHERE KEY='".$key."'";

Update Standard Column Query
  * $columnMap => Associative array of Column names and corresponding value for given $key
  * Ex: UPDATE TestColumnFamily SET 'name'='abc', 'country'='IN' WHERE KEY='test'
function generateUpdateStandardColumnQuery($columnFamily, $columnMap, $rowKey) 
  $colArgs = "";
  foreach($columnMap as $columnKey => $value)
     $colArgs=$colArgs."'".$columnKey."'='".$value."', ";
  $colArgs = rtrim($colArgs,", ");
  return "UPDATE ".$columnFamily." SET ".$colArgs." WHERE KEY='".$rowKey."'";  

Select Column Query
 * $column = Column to be selected from Cassandra $columnFamily
 * Ex: SELECT 'name' FROM TestColumnFamily WHERE KEY='test'(Updated)
function generateSelectQuery($columnFamily, $column, $key, $limit='-1', $reversed='0', $range=false) 
     if($reversed == '1' && $range)
       return "SELECT REVERSED '".$column."' FROM ".$columnFamily." WHERE KEY = '".$key."'";
     return "SELECT '".$column."' FROM ".$columnFamily." WHERE KEY = '".$key."'";
    return "SELECT FIRST ".$limit." '".$column."' FROM ".$columnFamily." WHERE KEY = '".$key."'";
  return "SELECT FIRST ".$limit." REVERSED '".$column."' FROM ".$columnFamily." WHERE KEY = '".$key."'";

Generate Range Queries
function selectColumnRange($columnFamily, $from, $to, $key, $limit='-1', $reversed='0') 
 return $this->generateSelectQuery($columnFamily ,$from."'".".."."'".$to, $key, $limit, $reversed, $range=true);

Execute Selects and Updates
function executeCQLSelect($query, $compression=cassandra_Compression::NONE) 
  $resultSet = $raw->client->execute_cql_query($query, $compression);
  return $resultSet;

function executeCQLUpdate($query, $compression=cassandra_Compression::NONE) 
  $raw->client->execute_cql_query($query, $compression);

Sample ColumnMap array would be like
$columnMap = array("name"=>"test", "country"=>"IN")

My solution to test ResultSet returned by Select Query
function isResultNull($resultSet)
      return (isset($resultSet->rows[0]) && $resultSet->rows[0] instanceof cassandra_CqlRow && count($resultSet->rows[0]->columns) > 0);

Hope this helps :)

Tuesday, November 1, 2011

Auto-Complete in Eclipse&Zend

[Try right click on project and see if there is Configure > Add PHP Support, If it is there use it]

This is a inference of mine while using Eclipse/Zend as IDE for PHP in linux [Not sure abt windows]

I was able to notice that PHP perspective over a SVN checked out PHP project didn't function as it was doing for a regular PHP project created via eclipse.
For Ex:
1. No syntax errors where highlighted/notified
2. CTRL press over a variable or a class or a function didn't give the option to navigate to the point its declaration
3. Autocompletion was completely disabled

After lots of searching, I figured out that whenever we create a project via eclipse, it will create two configuration files along with it



SVN projects might have these files not being configured properly or might even miss them

So, inorder to overcome this, either you can create one by hand or create a new PHP project and export the files you checked out in to the newly created project.

Following are the sample configuration files. You can use them to create one by hand. Place the files in your project's root directory

<?xml version="1.0" encoding="UTF-8"?>
    Your Project Name
Including the previous file itself should fix the issue. If not then go on with this too. Select the correct path for the following file
<?xml version="1.0" encoding="UTF-8"?>


In linux these file will be by default hidden. Use CTRL+h to unhide them. If they don't exist then create new ones and restart your eclipse
Hope this helps :)