VBScript conditional short-circuiting workaround - asp-classic

I have a large classic ASP app that I have to maintain, and I repeatedly find myself thwarted by the lack of short-circuit evaluation capability. E.g., VBScript won't let you get away with:
if not isNull(Rs("myField")) and Rs("myField") <> 0 then
...
...because if Rs("myField") is null, you get an error in the second condition, comparing null to 0. So I'll typically end up doing this instead:
dim myField
if isNull(Rs("myField")) then
myField = 0
else
myField = Rs("myField")
end if
if myField <> 0 then
...
Obviously, the verboseness is pretty appalling. Looking around this large code base, the best workaround I've found is to use a function the original programmer wrote, called TernaryOp, which basically grafts in ternary operator-like functionality, but I'm still stuck using a temporary variable that would not be necessary in a more full-featured language. Is there a better way? Some super-secret way that short-circuiting really does exist in VBScript?

Nested IFs (only slightly less verbose):
if not isNull(Rs("myField")) Then
if Rs("myField") <> 0 then

Maybe not the best way, but it certainly works... Also, if you are in vb6 or .net, you can have different methods that cast to proper type too.
if cint( getVal( rs("blah"), "" ) )<> 0 then
'do something
end if
function getVal( v, replacementVal )
if v is nothing then
getVal = replacementVal
else
getVal = v
end if
end function

I always used Select Case statements to short circuit logic in VB. Something like..
Select Case True
Case isNull(Rs("myField"))
myField = 0
Case (Rs("myField") <> 0)
myField = Rs("myField")
Case Else
myField = -1
End Select
My syntax may be off, been a while. If the first case pops, everything else is ignored.

If you write it as two inline IF statements, you can achieve short-circuiting:
if not isNull(Rs("myField")) then if Rs("myField") <> 0 then ...
But your then action must appear on the same line as well. If you need multiple statements after then, you can separate them with : or move your code to a subroutine that you can call. For example:
if not isNull(Rs("myField")) then if Rs("myField") <> 0 then x = 1 : y = 2
Or
if not isNull(Rs("myField")) then if Rs("myField") <> 0 then DoSomething(Rs("myField"))

Or perhaps I got the wrong end of the question. Did you mean something like iIf() in VB? This works for me:
myField = returnIf(isNothing(rs("myField")), 0, rs("myField"))
where returnIf() is a function like so:
function returnIf(uExpression, uTrue, uFalse)
if (uExpression = true) then returnIf = uTrue else returnIf = uFalse : end if
end function

Yeah it's not the best solution but what we use is something like this
function ReplaceNull(s)
if IsNull(s) or s = "" then
ReplaceNull = " "
else
ReplaceNull = s
end if
end function

Would that there were, my friend -- TernaryOp is your only hope.

Two options come to mind:
1) use len() or lenb() to discover if there is any data in the variable:
if not lenb(rs("myField"))=0 then...
2) use a function that returns a boolean:
if not isNothing(rs("myField")) then...
where isNothing() is a function like so:
function isNothing(vInput)
isNothing = false : vInput = trim(vInput)
if vartype(vInput)=0 or isEmpty(vInput) or isNull(vInput) or lenb(vInput)=0 then isNothing = true : end if
end function

You may be able to just use Else to catch nulls, ""s, etc.
If UCase(Rs("myField")) = "THING" then
'Do Things
elseif UCase(Rs("myField")) = "STUFF" then
'Do Other Stuff
else
'Invalid data, such as a NULL, "", etc.
'Throw an error, do nothing, or default action
End If
I've tested this in my code and it's currently working. Might not be right for everyone's situation though.

Related

ASP Session variables: Is "" same as IsEmpty?

In ASP an uninitialized Session variable Is Empty. I know that the correct way to check for a Session value, and remove a value, is the following:
IF NOT IsEmpty(Session("myVar")) THEN
' Go ahead and use Session("myVar")
...
' Now if we're all done with myVar then remove it:
Session.Contents.Remove("myVar")
END IF
I've inherited a codebase where Application and Session variables are typically set = "" after use, and all tests for a value are of the form (Sessions("myVar") = ""). This test appears to work when the Session variable has not been declared ... or maybe it's just working by dumb luck.
Is it safe to use comparison with the empty string to test for a Session variable? I.e., is the following "practically as good" as the correct method shown above?
IF Session("myVar") <> "" THEN
' Go ahead and use Session("myVar")
...
' Now if we're all done with myVar then blank it:
Session("myVar") = ""
END IF
Or should I refactor the codebase so that:
All tests to determine whether a Session variable has been set are of the form IsEmpty(Session("myVar"))
All session variables are Removed and not set = ""?
Empty is a strange beast: it is simultaneously equal to both "" and 0. Seriously, try it:
dim x, y, z
x = Empty
y = ""
z = 0
Response.Write (x = y) AND (x = z)
It'll write out "True".
This means that testing for Not IsEmpty(myvar) is equivalent to testing myvar <> "", but IsEmpty(myvar) is not equivalent to myvar = "". Whether that mostly-theoretical difference bothers you or not is something only you can answer, but personally, I wouldn't waste time on refactoring.
If you do decide to refactor, I would suggest forgetting about IsEmpty and IsNull and whatnot, and just using the & "" "hack":
If Session("myvar") & "" <> "" Then
This'll transparently handle Nulls and Empties without you needing to write a whole bunch of code.
No, it could be not safe. Perhaps you need to use functions: IsNull, IsEmpty and VarType
IsNull -- returns True if expression is Null, that is, it contains no
valid data; otherwise, IsNull returns False. If expression consists of
more than one variable, Null in any constituent variable causes True
to be returned for the entire expression.
VarType -- Returns a value indicating the subtype of a variable.
IsEmpty -- returns True if the variable is uninitialized, or is
explicitly set to Empty; otherwise, it returns False. False is always
returned if expression contains more than one variable.
Please take a look at What is the '<>' asp operator?

DbNull.Value and isDBNull for datacolumn

I have a DataRow which contain data from database. I want to check each data column for Null value in an IF condition.
I found two ways to check NULL value.
If IsDBNull(drType("ISShort")) Then
StartDate.Visible = True
Else
StartDate.Visible = False
End If
and
If Not drType("ISShort").ToString Is DBNull.Value Then
StartDate.Visible = True
Else
StartDate.Visible = False
End If
Both works fine for me but I don't know which one is better to use ?
I prefer DataRow.IsNull which returns a bool, is readable and efficient:
StartDate.Visible = drType.IsNull("ISShort")
related: Which of IsDBNull and IsNull should be used?
Note that your second approach doesn't work. If you convert it to String with ToString it can't be DBNull.Value. That compiles only with option-strict set to off which i strongly advise against.
Second case makes no sense as it does unnecessary ToString().
Note, there is another way you can use DbNull
If DbNull.Value.Equals(row.Item(fieldName)) Then
...
you can also use myDataRow.IsNull(fieldName) which is faster according to Which of IsDBNull and IsNull should be used?

How to implement a Binary Search Tree in Julia?

I am trying to implement BST in Julia, but I encountered problem when I call insert function. When I try to create new node, the structure stays unchanged.
My code:
type Node
key::Int64
left
right
end
function insert(key::Int64, node)
if node == 0
node = Node(key, 0, 0)
elseif key < node.key
insert(key, node.left)
elseif key > node.key
insert(key, node.right)
end
end
root = Node(0,0,0)
insert(1,root)
insert(2,root)
I also tried to change zero to nothing. Next version which I tried is with defined datatypes in Node, but when I try to call insert with nothing value(similar to C Null) it gave me error.
Thank for answer.
The code has a number of issues.
One is that it is not type stable, left and right could contain anything.
The other is that setting the local variable node inside the insert function will not affect change anything.
A stylistic issue, functions that modify their arguments generally have a ! as the last character in the name, such as insert!, push! setindex!.
I think the following should work:
type BST
key::Int
left::Nullable{BST}
right::Nullable{BST}
end
BST(key::Int) = BST(key, Nullable{BST}(), Nullable{BST}())
BST() = BST(0)
function Base.push!(node::BST, key)
if key < node.key
if node.left.isnull
node.left = BST(key)
else
push!(node.left.value, key)
end
elseif key > node.key
if node.right.isnull
node.right = BST(key)
else
push!(node.right.value, key)
end
end
end
root = BST()
push!(root, 1)
push!(root, 2)
This version overloads the Julia push! function, and uses the Nullable type so that it can distinguish between a leaf node and where it needs to continue searching to find where to insert the key. This is a recursive definition, and is not optimized, it would be much faster to do it with loops instead of recursive.

Ada actual for "S" must be a variable

So here is a piece of my body file. I am getting the error "words.adb:75:42: actual for "S" must be a variable".
procedure Remove_Character(S : in out Ustring; C : in Character; Successful : out Boolean) is
begin
for I in 1..length(S) loop
if Element(S, I) = C then
Delete(S, I, I);
Successful := true;
return;
end if;
end loop;
Successful := false;
end Remove_Character;
function Is_Subset(Subset : Ustring; S : Ustring) return Boolean is
Could_Remove : Boolean;
begin
for I in 1..length(Subset) loop
Remove_Character(S , Element(Subset, I), Could_Remove);
if Could_Remove = false then
return false;
end if;
end loop;
return True;
end Is_Subset;
I understand where my error is coming from. Remove_Character uses S : in out Ustring while function Is_Subset uses S : in Ustring.
My question is how do I change the variable from Remove_Character into only an in Ustring?
Sorry if this is a tad jumbled, I'm fairly new to both programming and the site.
You can't, at least not directly.
I don't know what a UString is, but I presume the Delete procedure modifies it. If you changed the declaration of S in Remove_Character to S: in Ustring, you'd presumably get an error on the call to Delete.
The simplest approach I can think of would be to make a copy of S in Is_Subset:
Copy_Of_S: UString := S;
and then pass the (modifiable) copy to Remove_Character.
By "simplest", I mean it makes the smallest change to your existing code. But you should probably consider reorganizing it. Determining whether one UString is a subset of another by modifying one of the strings doesn't seem like the best approach; I'm sure there's a more efficient way to do it.
A minor and irrelevant point: this:
if Could_Remove = false then
is better written as:
if not Could_Remove then

Why won't this work as an IIF function, but will as an IF Statement?

The following works:
If 1=1
rdoYes.checked = True
Else
rdoNo.checked = True
End If
However, the following doesn't work:
IIF(1=1, rdoYes.checked = True, rdoNo.checked = True)
Why is this?
Thanks!
It does "work"; it just doesn't do what you want.
IIf in VB.NET is a function (don't use it, ever, by the way), which takes these parameters:
A Boolean condition to check
An Object to return if the condition is True
A different Object to return if the condition is False
In your usage, your condition is 1 = 1; then your two other parameters are rdoYes.Checked = True and rdoNo.Checked = True, both Boolean expressions from the VB compiler's perspective (so, really, they're equivalent to the simpler rdoYes.Checked and rdoNo.Checked).
Remember that in VB.NET, the = sign is only an assignment if it is on its own line. This is how the compiler distinguishes between statements such as x = 5 and If x = 5 Then.
This is not directly related to your question, but you should also be aware that IIf is deprecated and you should almost always favor If instead:
' Let us just suppose it made sense to write this: '
' Notice the If instead of IIf. '
Dim result = If(1 = 1, rdoYes.Checked, rdoNo.Checked)
The IIF() function will return something based on what you enter for the first parameter. Since VB.Net doesn't differ between = as in assignment and = as in comparison (== in many other languages), the second statement is ambiguous.
You can do this with using late binding (delegates in VB.Net):
(Function(c) InlineAssignHelper(c.Checked, true)).Invoke(IIf(1 = 1, chkYes, chkNo))
Private Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
target = value
Return value
End Function
Because IIf takes expressions and returns a result of one of them, and rdoYes.checked = True is not an expression and cannot be returned.
iif doesn't do what you think it does -- the important part is the return from it, so you might be able to do:
iif(1=1, rdoYes, rdoNo).checked = True
(I'm not sure that's valid VB ... it's been more than a decade since I've had to code in it)

Resources