cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Choose Language Hide Translation Bar

Why do these ways of referencing columns give different results?

I'm struggling to understand how JSL handles column references and keep running into bugs in my scripts for that reason.

Why are the following expressions giving different results?

What is the best way of dynamically passing column references to functions?

 

dt = New Table("test",
New Column("abc"),
New Column("def")
);

collist = {:abc, :def};

col = AsName("abc");
colname = "abc";

Show(Contains(collist, col));
Show(Contains(collist, AsName(colname)));

The output is:

 

Contains(collist, col) = 0;
Contains(collist, As Name(colname)) = 1;
1 ACCEPTED SOLUTION

Accepted Solutions
Craige_Hales
Super User

Re: Why do these ways of referencing columns give different results?

Virtual rabbit hole ahead. Mark's answer may be all you need.

 

Is a fascinating question. It sure looks like you should get the same answer, but...

 

Unlike C and many other languages, the arguments to functions are not evaluated before the function is called. Instead the function determines how to handle its parameters. And, JSL has a variable type called expression, closely related to the value AsName returns. When you call a function with an expression argument, the function can choose what to do with the parameter. It might evaluate the expression; a+2 requires looking up the variable a and adding 2. Or it might manipulate the expression; head(a+2) returns add. In your example, the expression is abc, and looking it up means getting its value from a row in the data table.

 

(This is hard, I spent an hour trying to make the comments correct and clear. I think they are correct.)

dt = New Table( "test", New Column( "abc" ), New Column( "def" ) );

collist = {:abc, :def, .}; // <<< added a missing value in position 3

col = As Name( "abc" );// the Right Hand Side evaluates to the expression abc, 
// and the expression is assigned to col. The 2nd argument to contains() is
// a name expression, and contains() evaluates that argument. It
// evaluates to missing because there is no subscript to pick a row.
Show( Name Expr( col ), Type( col ), Contains( collist, col ) ); // looks for a missing value
// Name Expr(col) = abc;
// Type(col) = "Number";
// Contains(collist, col) = 3;

colname = "abc";
// contains() evaluates the 2nd argument to a name, but does not
// do another evaluation of the name, so it locates the name
// in the list of names
Show( Type( As Name( colname ) ), Contains( collist, As Name( colname ) ) );
// Type(As Name(colname)) = "Name";
// Contains(collist, As Name(colname)) = 1;

finally,

Show( Name Expr( col ), Type( col ), Contains( collist, Name Expr(col) ) );

does what you want; the 2nd argument to contains() has the nameexpr() wrapper that causes contains() to evaluate it to the name of the expression, abc, not the value.

 

edit: this is never easy! @hogi  points out the head(a+2) example (above) is wrong in Does Head evaluate its argument? ; I think the answer is head() peeks at the argument to see if it is a variable holding an expression, and if not, evaluates it to see if it will produce an expression.

Craige

View solution in original post

3 REPLIES 3

Re: Why do these ways of referencing columns give different results?

This expression does not store a column reference:

col = AsName("abc");

So the Contains() function returns 0 (false).  You should use the Column( "name" ) if you want to store a column reference.

 

Craige_Hales
Super User

Re: Why do these ways of referencing columns give different results?

Virtual rabbit hole ahead. Mark's answer may be all you need.

 

Is a fascinating question. It sure looks like you should get the same answer, but...

 

Unlike C and many other languages, the arguments to functions are not evaluated before the function is called. Instead the function determines how to handle its parameters. And, JSL has a variable type called expression, closely related to the value AsName returns. When you call a function with an expression argument, the function can choose what to do with the parameter. It might evaluate the expression; a+2 requires looking up the variable a and adding 2. Or it might manipulate the expression; head(a+2) returns add. In your example, the expression is abc, and looking it up means getting its value from a row in the data table.

 

(This is hard, I spent an hour trying to make the comments correct and clear. I think they are correct.)

dt = New Table( "test", New Column( "abc" ), New Column( "def" ) );

collist = {:abc, :def, .}; // <<< added a missing value in position 3

col = As Name( "abc" );// the Right Hand Side evaluates to the expression abc, 
// and the expression is assigned to col. The 2nd argument to contains() is
// a name expression, and contains() evaluates that argument. It
// evaluates to missing because there is no subscript to pick a row.
Show( Name Expr( col ), Type( col ), Contains( collist, col ) ); // looks for a missing value
// Name Expr(col) = abc;
// Type(col) = "Number";
// Contains(collist, col) = 3;

colname = "abc";
// contains() evaluates the 2nd argument to a name, but does not
// do another evaluation of the name, so it locates the name
// in the list of names
Show( Type( As Name( colname ) ), Contains( collist, As Name( colname ) ) );
// Type(As Name(colname)) = "Name";
// Contains(collist, As Name(colname)) = 1;

finally,

Show( Name Expr( col ), Type( col ), Contains( collist, Name Expr(col) ) );

does what you want; the 2nd argument to contains() has the nameexpr() wrapper that causes contains() to evaluate it to the name of the expression, abc, not the value.

 

edit: this is never easy! @hogi  points out the head(a+2) example (above) is wrong in Does Head evaluate its argument? ; I think the answer is head() peeks at the argument to see if it is a variable holding an expression, and if not, evaluates it to see if it will produce an expression.

Craige
hogi
Level XI

Re: Why do these ways of referencing columns give different results?

@Craige_Hales .
Thank you for this post - I will add it to my list of treasures


It gives some hint why Name Expr(As Column(colname))
[e.g. by @jthi in Re: Need help with expressions, column references, formulas and column renaming] is so useful!


I would have liked to say: I think I really understand now  - but some of the below results are still surprising to me.

I am still searching for a comprehensive documentation - e.g. how to find out how a function handles its parameters.

When searching via contains, why does Jmp know that Column("abc") = :abc?

dt = New Table( "test", New Column( "abc" ), New Column( "def" ) );

collist = {:abc, :def, .}; // <<< added a missing value in position 3
row()=0; //to be sure that the row index is really 0 :)
colname = "abc";
col = As Name( colname); // abc
col2 = :name("abc"); // .
col3 = As Column(colname); // .
col4 = Name Expr(As Column(colname)); // :abc
col5 = Column(colname); // Column("abc")
col6 = Name Expr(Column(colname)); // Column( colname )

col;  // .
col2; // .
col3; // .
col4; // .
col5; // Column( "abc" )
col6; // Column( "abc" )

Show( Name Expr(  col ), Type(  col ), Contains( collist,  col ) ); // :abc, Number, 3
Show( Name Expr( col2 ), Type( col2 ), Contains( collist, col2 ) ); // . , Number, 3
Show( Name Expr( col3 ), Type( col3 ), Contains( collist, col3 ) ); // ., Number, 3
Show( Name Expr( col4 ), Type( col4 ), Contains( collist, col4 ) ); // :abc, Number, 3
Show( Name Expr( col5 ), Type( col5 ), Contains( collist, col5 ) ); // Column("abc"), Column, 1 (!)
Show( Name Expr( col6 ), Type( col6 ), Contains( collist, col6 ) ); // Column(colname), Column, 1 (!!)

Show( Contains( collist, Name Expr(col) ) ); //  1
Show( Contains( collist, Name Expr(col2) ) ); // 3
Show( Contains( collist, Name Expr(col3) ) ); // 3
Show( Contains( collist, Name Expr(col4) ) ); // 1
Show( Contains( collist, Name Expr(col5) ) ); // 1
Show( Contains( collist, Name Expr(col6) ) ); // 0