having difficulty to understand this while loop? - tcl

I have difficulty understanding this while loop:

The Condition
The condition:
while {1 == [string equal $result Completed]} {
could be written more shortly as:
while {$result eq "Completed"} {
That is, it means "do the body while $result is equal to the literal string Completed.
The Body
The body of the loop calls $mode run (what exactly that does isn't described here). Then it gets the result by calling $mode getRunResult and extracts the first word of the list, and assigns it to the variable result. The final step of the loop is to use switch to print a message whenever $result is either Error or SolverFailure (it also has clauses for Completed and StopCritera, but that's empty so nothing happens).
The Overall Effect
The loop calls $mode run until the first word of the result of $mode getRunResult after that run is not Completed.
$mode is a handle returned by pw::Application begin ExtrusionSolver $block, and $mode end is called after the loop terminates, presumably to clean things up.

Related

How to understand tcl's return

I wanted to get the number of parameters of a proc from tcl and didn't want it to be printed in tclsh, so I used return
When I execute the following statement in the c environment
string tclCmd = "info args " + tclProcName + ";return";
Tcl_Eval(interp, tclCmd.c_str());
string res = Tcl_GetStringResult(interp);
The result of the execution is not printed in tclsh, but at the same time it is not possible to get the correct value
So I tried to write it like this:
string tclCmd = "info args " + tclProcName;
Tcl_Eval(interp, tclCmd.c_str());
string res = Tcl_GetStringResult(interp);
Tcl_Eval(interp, "return");
This works, but I don't understand why it doesn't print out immediately when Tcl_Eval is executed, and the return statement is still valid afterwards
The return command is not helpful at all there. It triggers an exception condition that comes out of Tcl_Eval as a return code of TCL_RETURN instead of TCL_OK (that is converted by the outer structure of a procedure, if that is relevant). Instead, you should call Tcl_ResetResult(interp); after you have finished with the return value (or have taken another reference to it) to put things back to how they were before your command implementation was invoked.

Can't read: variable is array

I am trying to pull back all the data from my sql statement but I am only able to pull back the first row data in the first put statement. So what I am trying to do is do a for loop through the $data variable. The for loop won't run because it says that the variable is an array.
orasql crsr $sql
orafetch $crsr -datarray data -indexbyname
puts $data(customer)
foreach value $data {
puts $data(customer)
}
The problem is when you do foreach value $data; since the data variable is an array, you can't read it as a simple value. To print the keys and values in the array, do this:
foreach {key value} [array get data] {
puts "$key => $value"
}
The array get command takes the name of an array variable and gets a list of keys and values from it, which can be iterated over with a two-variable foreach. (The parray command does a somewhat more sophisticated version of this; you could use parray data in place of that loop above, but then you'd have no real other route into processing the row.)
You usually ought to know the names of the columns you're getting back from an SQL query so that you don't need to loop over it like that. Also, the order of columns doesn't really matter, but neither does the order of entries in the array. (The order of rows in the result set of the query matters, but orafetch only gets one at a time.)

How to remove duplicate results from a cts:uris when distinct values does not work

I have the following code that returns an array of array of results I try to use distinct-values to remove duplicates and it does nothing I have tried also removing using looping functions by comparing values with no success.
I have tried converting to "xs anyAtomicType" and using distinct values
I have tried putting in json array and extracting the sub-array
I have tried tokenizing, xdmp quote, string-before/after and many others
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
I get back duplicated result in form of:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
I am expecting:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
Is it possible that you have simply invoked this function 3 times and didn't realize it?
You have declared $dir to be a single xs:string. If your $dir happened to be a sequence of strings of the same directory, or if you otherwise invoked the function 3 times with the directory variable.
It can easily happen with function mapping enabled (default behavior). https://docs.marklogic.com/guide/xquery/enhanced#id_55459
There are a couple of things that you can do as a diagnostic:
1.) Remove the explicit type on the $dir parameter in the function:
declare function local:verify-user-uri($dir)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
do you get an error executing cts:uris() that looks like this:
[1.0-ml] XDMP-ARGTYPE: )err:XPT0004) cts:uris(("/users/", "/users/", "/users/"), ()) -- arg1 is not of type xs:string?
2.) try disabling function mapping by adding the following to the prolog:
declare option xdmp:mapping "false";
and see if you then get an invalid coercion error like:
[1.0-ml] XDMP-AS (err:XPTY0004) $dir as xs:string -- Invalid coersion ("/users/", "/users/", "/users/") as xs:string
3.) You could also add something to the end of the sequence of values returned from the function to indicate how many times it has executed:
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds, "#"
};
And see how many times you see "#" in the result. If more than one, you are invoking the function multiple times.
Next to the good suggestions from Mads, I notice a couple of other things about your code:
It doesn't make sense to iterate over $each as it contains one uri only. Keep in mind that a FLWOR statement ends with a return, which tells what should be the result per item
Beware that the first arg to cts:uris only marks a start, not an end. If you feed in /aaa/, you also get back /bbb/ etc, though not vice versa.
To be honest, I think you are looking for cts:uri-match() instead, which would reduce your function to a one-liner:
declare function local:verify-user-uri($dir as xs:string) {
cts:uri-match($dir || "*/profile.xml")
};
HTH!
PS: I do recommend always disabling function mapping as Mads recommends. It can prevent a lot of confusion.

Should this Perl 6 CATCH block be able to change variables in the lexical scope?

I'm playing with resumable exceptions. In this example, I try to numify something that doesn't numify. I catch that and attempt to give the $value variable an appropirate value then resume execution:
try {
my $m = 'Hello';
my $value;
$value = +$m;
put "Outside value is 「{$value.^name}」";
CATCH {
when X::Str::Numeric {
put "「$m」 isn't a number!";
put "Inside value is 「{$value.^name}」";
$value = 0;
put "Inside value is now 「$value.」";
.resume;
}
default {
put "Unhandled type 「{.^name}」";
}
}
put "End of the block";
}
put "Got to the end.";
The CATCH block can see the lexical scope it is in, a resuming picks up where it left off. I expected that I'd be able to change $value and have the rest of the block use that value, but outside of the CATCH the value becomes a Failure:
「Hello」 isn't a number!
Inside value is 「Any」
Inside value is now 「0.」
Outside value is 「Failure」
End of the block
Got to the end.
What's up?
Inside of a try block, use fatal takes effect, to cause lazy exceptions returned from method or sub calls to throw immediately. Outside the lexical scope of a try block, note that:
my $value = +$m;
Would result in a Failure being assigned to $value. The try turns it into something more like:
my $value = force-failure(+$m);
Which you could imagine being defined as something like:
sub force-failure(Mu \f) { f.sink if f ~~ Failure; f }
(I'm hand-waving because the compiler spits out the code to do this inline and with a few optimizations).
In the case under consideration, the .sink triggers the exception to the thrown. The CATCH block runs. The .resume indicates that we do not wish to unwind the call stack as would normally happen with a CATCH block, so execution continues inside of force-failure, which then returns f - the Failure. This all happens prior to the assignment in the mainline code to $value; the Failure is therefore assigned, overwriting the value given by the CATCH block.
Unfortunately, you can't escape this with //= because that does the test before running the RHS (which is what we usually want it to do). However, it is possible to do:
my $numified = +$m;
my $value //= $numified;
Of course, this is all a bit of a contrived example, since the normal idiom would be to not have a try block at all, and to write it as:
my $value = +$m // 0;
Thus taking advantage of the Failure. In general, resumable exceptions need a good amount of care, because in many cases code will not be written expecting a resumption to take place. It turns out that the code generated for fatalizing a Failure is one such piece.

Function containing a process is returning a garbled value

Spent my whole morning trying to find where my return value was getting garbled. Now that I've finally found where, I still have no idea why. Function looks like this:
function Run-RemoteCommand {
param(...) # params are $Remote (host) $Command $Credentials $Quiet (optional switch)
if($Quiet) {
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo.UseShellExecute=$false
$Process.StartInfo.Domain=$Credentials.GetNetworkCredential().Domain
$Process.StartInfo.UserName=$Credentials.GetNetworkCredential().UserName
$Process.StartInfo.Password=$Credentials.Password
$Process.StartInfo.WindowStyle="Hidden"
$Process.StartInfo.FileName=$PSExec
$Process.StartInfo.Arguments=#("/acceptEULA",$Remote,"-s",$Command)
$Process.Start()
$Process.WaitForExit()
$result = $Process.ExitCode
return $result
} else {
...
}
}
What's odd is that I can step through this in a debugger and watch everything work fine. The command runs, $result is filled with the return code, but the calling function receives True appended to the return code (eg True0 on success). I even tried overriding the return value and just saying
return "false"
The calling function receives "Truefalse." All I can tell is that it's tied to $Process running. If I comment out $Process.Start(), the return code functions normally. Someone please save my sanity.
$Process.Start() returns a boolean value which is True if it succeeds. Remember that functions in PowerShell behave differently than standard programming languages. PowerShell functions "return" or more technically correct "output" any command output that isn't captured by a variable or redirected to a file or Out-Null. In this case change the Start line to:
[void]$Process.Start()
or
$Process.Start() | Out-Null
Check out this blog post for a deeper explanation.