a bit of a theoretical question here. I'm currently writing a JSL Scripting tutorial for my colleagues and so I am trying to make sure I have a good understanding of the way JSL works.
I once read on a forum that you should always use an 'Else' statement inside an 'If' loop, even if that meant adding Empty() as the 'Else' statement.
To see the difference, I tried playing around with the script editor:
y=if(1>2, 1); z= if (1>2, 1 , Empty()); Show (y); Show (z); Show (Is Missing (y) ); Show (Is Missing (z) ); Show (Is Empty (y) ); Show (Is Empty (z) ); x= If (y==z, "true", "false"); Show (x);
// results :
y = .;
z = Empty();
Is Missing(y) = 1;
Is Missing(z) = 1;
Is Empty(y) = 0;
Is Empty(z) = 1;
x = .;
So the value Empty() is both a missing and an empty value but '.' is missing but not empty. What difference does that make ? Given the fact that they both return a missing value when used in comparison operators, why should I bother using Empty() as an 'Else' statement ?
This also illustrates the fact that when the condition tested in the if statement returns missing, it is neither true nor false, so the loop returns neither of the two statements, which is always good to keep in mind!
I have been scripting longer than most people (1998). I am an author of and teach all our scripting courses. I am not aware of a 'best practice' that recommends always including an argument for the 'else' condition or using empty in cases where there isn't a specific return value. I certainly never missed it or paid for not using it. I think that this issue is another case of 'it depends.' What are you trying to do with the conditional If() function? What do you expect it to return?
The default return value of the If() function is missing when the first argument evaluates to false and there are only two arguments. You demonstrated this behavior with the value stored in y. The If() function has behaved as such since JSL was first introduced in JMP 4 in 2000.
You can supply a third argument to the If() function that is evaluated and returned when the first argument evaluates as false. You demonstrated this behavior with the value stored in z where you supplied the Empty() function as the third argument.
Missing represents an unknown value. It most often represents data values that are unknown or the result of evaluating an impossible numeric expression such as Log( -1 ). I think that missing makes a lot of sense as the default return value for a condition that is not represented by an argument.
Empty is just that. It represents the state where there is nothing there. For example, if you call Current Data Table() with no argument when no data tables are open, it returns empty.
You ask some big questions.
My basic point is that, as with any computer programming language, JSL syntax and idioms are our friends but we are not slaves to them. My question, "What do you expect?" was intended only to point out that we need the answer to this question every time we write or modify code. A clear answer makes all the difference to our code.
Yes, functions are a key element to writing scripts. By definition, every function returns a result. But we are some times more interested in a side effect of the function than the result that is returned. For example, the V List Box() function returns a reference to the display box object that it creates. I might be more interested in the box itself (the side effect) than I am in the reference.
Many novice scripters think that If() and For() are statements or commands. They are functions. The statement mindset can limit your creativity. The mindset is important. The following script shows two approaches to accomplish the same thing but the second approach would never occur to someone with a statement mindset.
Names Default to Here( 1 ); dt = Open( "$SAMPLE_DATA/Big Class.jmp" ); mean weight = Col Mean( dt:weight ); // assign within the If() function call dt << New Column( "Condition 1", Numeric, Continuous ); For Each Row( If( :weight < mean weight, dt:Condition 1 = -1, dt:Condition 1 = 1 ); ); // assign with the returned result from the If() function call dt << New Column( "Condition 2", Numeric, Continuous ); For Each Row( dt:Condition 2 = If( :weight < mean weight, -1, 1 ); );
I agree that computer programming in general and JMP scripting in particular are serious topics. Saving scripts and hacking together scripts written by others will only get you so far. Confusion and frustration usually result.
I am sorry that our training is not an option. Our introductory course is mature (about two decades) and well-received. I am not aware of any other training for JSL, free or for a fee. There might be some free videos that cover specific topics but I doubt that they convey the mindset. They usually are a ‘how to’ or ‘cookbook’ style.
Perhaps another Community member knows about training that would suit you.
The way that I use Is Empty(), is to see if a variable has ever been assigned. Thus avoiding a syntax error for:
names default to here(1); show(z);
one can check to see if the variable "z" has ever been referenced:
Names Default To Here( 1 ); If( Is Empty( z ) == 0, Show( z ) );
A better example is the one below.
Names Default To Here( 1 ); x=1; If( x > 2, z = 7 ); If( Is Empty( z ) == 0, Show( z ) );
Since JSL is an interpreted language, it follows the logic flow of the JSL So, if x <= 2, JSL will not execute (not even look at) z = 7, and therefore without the checking to see if z Is Empty() is required since JSL would give a syntax error.
In your example, you are using a different form of assigning the value to z
names default to here(1); z=(if(1>2, 7)); show(z);
The variable z will take on the value of 7 if 1>2, but if not true, z is no longer not assigned, so it will take on a missing value, ".". The advantage here, is that once the assignment is made, JSL has processed the variable z and will not have a syntax error if z is referenced later in the program flow.
This brings us to the question of should one assign Empty() as the result of a false being returned in an If() function.
names default to here(1); z=(if(1>2, 7, Empty())); show(z);
It then simply comes down to, do you not want to have z as a missing value and would rather check for Is Empty() vs. Is Missing(). I personally prefer the missing value route, since it leaves Empty() as a verification that z has never been assigned. .
FWIW I never use an ELSE statement if I don't have an ELSE condition. Keeps my code simple and tight. I am aware that if() is a function and I know how to use it as such. Maybe it's a holdover from other languages I've used.