Error: undefined local variable or method 'var' for top-level - crystal-lang

I am new to the crystal programming language.
Whenever I run this code:
var = ARGV.find { |x| x.split(".").size == 4 } || "0.0.0.0"
ARGV.delete(var)
Addr = var.split(".").map { |x| x.to_i { 0 } }.join(".")
p Addr
With crystal, I get an Error:
Showing last frame. Use --error-trace for full trace.
In q.cr:4:8
4 | Addr = var.split(".").map { |x| x.to_i { 0 } }.join(".")
^--
Error: undefined local variable or method 'var' for top-level
But whenever I omit the last line p Addr, or replace var with Var, the code seems to work fine.
Crystal Version:
Crystal 0.31.1 (2019-10-21)
LLVM: 9.0.0
Default target: x86_64-pc-linux-gnu
What's the problem in my code?

This is a little gotcha that we hopefully will get better error messages for in the future.
So the first piece to this puzzle is to understand that var is a local variable because it starts with a lowercase letter and Addr is a constant because it starts with an upper case letter.
For reasons constant initializers, so the code after the = sign in an constant assignment, are run lazily the first time the constant is accessed. Because of this they exist in their own scope and cannot reference the local variable defined in the top level scope.
So there's three ways out of this for your example. First making Addr a local variable too by calling it addr. Second promoting var to a constant by calling it Var. Or third putting your entire code into the constant initializer:
Addr = begin
ip = ARGV.find { |arg| arg.count('.') == 3 } || "0.0.0.0"
ARGV.delete(ip)
ip.split('.').map { |part| part.to_i { 0 } }.join('.')
end
Which of the three is best depends largely on taste and the structure of your program.

Related

Google app script IF condition not matching 0, empty and null

I have issues with Google app script IF condition.
Problem i am facing its not returning value TRUE rather going to next/ Else statements.
Code i am having:
const numberOfRowsToUpdate = deliveryDate.length;
// For each item making the for loop to work
for (i=0 ; i < numberOfRowsToUpdate;i++) {
debugger;
var dp = depositAmount[i];
if(dp!==""|| dp!==0 || dp !==null || dp!==isblank())
{ .... <statements>
}
}
I want to check whether particular cell of the array is empty / zero / returning null value.
thanks in advance for the help.
SUGGESTION
I have used a similar script I'm using for a spreadsheet in which I need to search through every row for some data, but obviously adpating it to your case, and since I don't have your full code (and still can't comment asking for more info due to my recent joining in SO), I had to simplify it, in hope it will work for you.
What I did was use your incrementing i index from the for loop and use it to scan every row, while adjusting it to fit your array index, because we can't have i = 0 as a row index, and it would skip the first value on the array if left as i = 1).
SCRIPT
function test(){
const n = 6;
var depositAmount = [7,2,0,2,0,8];
// For each item making the for loop to work
var ss = SpreadsheetApp.getActive();
Logger.log(ss.getName());
for (var i=1 ; i <= n ;i++) {
debugger;
ss.getRange("A"+i).setValue(1);
var dp = depositAmount[i-1];
Logger.log(dp)
if(dp != "" || dp != 0 /*|| dp != null || dp != isblank()*/)
{
ss.getRange("B"+i).setValue(dp);
}
else
{
ss.getRange("C"+i).setValue("VOID")
Logger.log(i-1+"th index of array is "+ss.getRange("C"+i).getValue());
}
}
};
RESULTS
After running it with the four original conditions you used, i didn't get the expected result, as you must have, leading to this:
.
While studying your original code, I stumbled upon this question about the differences between == and ===, as well as != and !==.
So before I used this in our favor, I tried the old trial and error method, using only one condition at a time, and then stacking them up. Not only I managed to find out the !== operator didn't work properly for this case, but also the comparison with null and the isblank() function (at least in my case, because i haven't defined it, and I'm not sure it is a built-in function) also don't work with either operator.
Therefore, using the != operator helps you better than the strict !==.
The result of the final script is that:
.
NOTES
I also tried using a null value within the array ([7,2,0,2,,8]), but it would always break away from the loop, never scanning the whole array, and I don't know how to circle that.
Here is the Execution Log for this script:
EDIT
While fooling around, I found this question and the answer by Etienne de Villers might be even faster to apply, or at least more useful for your purposes.

Array of implicitly unwrapped optionals iterates forever in Xcode 8 beta 4

My code (fragment below) causes the Simulator to Hang.
What am I doing wrong?
To reproduce the problem, cut and paste into the Simulator.
class INK
{
var test = 1
}
var array = [INK!](repeating: nil, count: 1)
for idx in 0..<array.count
{
array[idx] = INK()
}
var idx2 = 0
for ink_item in array
{
idx2 += 1
print("idx2=\(idx2)")
}
This is a known bug, see SR-1635. Since an IUO is no longer a distinct type, it shouldn't really be possible to have an array of them in the first place.
This is confirmed by the fact that the following code fails to compile:
// compiler error: Implicitly unwrapped optionals are only allowed at top level.
// and as function results
var array: [Ink!] = []
(note I renamed your class name to Ink to conform to Swift naming conventions)
Depending on your situation, you may want to consider using a lazy property instead:
lazy var array : [Ink] = {
var array = [Ink]()
// populate array
return array
}()
Or making the array itself an implicitly unwrapped optional (and defer both the allocation and initialisation of the array):
var array : [Ink]!
Although note that IUOs should always be a last resort due to their inherent unsafety.

Regex appears to return pos >1 but length 0

The following code is returning an error on Mid, saying the third argument is -2 - so it thinks the length is 0. We're totally stumped as to how this could happen. The code looks for values between curly braces and strips them out. Can you think of a way to break this?
Str can be anything - we don't know, it's not supplied by us - so that's the var you want to break.
str = "Here's a string with {EmailAddy} and maybe some {otherVariables}";
start = 1;
pos = 0;
length = 0;
tokens = ArrayNew(1);
while(true) {
x = REFind("\{\w*\}", str, start, true);
pos = x.pos[1];
length = x.len[1];
if (pos == 0) {
break;
} else {
// get the token, trimming the curly brackets
token = mid(str, pos+1, length-2);
arrayAppend(tokens, token);
start = pos + length;
}
}
WriteDump(tokens);
You don't need lookbehind:
var Tokens = rematch( "\{\w*(?=\})" , Arguments.Str );
for ( var i = 1 ; i LTE ArrayLen(Tokens) ; i++ )
Tokens[i] = Tokens[i].substring(1);
return Tokens;
And that code should also give you a clue as to the most likely cause of the code breaking, in that you've probably got it in a function in a persisted component, but (without any scoping) everything is going in the component's variables scope, and thus it's not thread-safe and - with multiple calls under load - the variables involved are liable to get corrupted.
This is a general issue you should be looking for throughout the code - generally the first assignment for every variable inside a function should be prefixed with either the var keyword (or explicitly the local. scope) to ensure it it local to that function and not global the the component. (Except of course in the instances when a global variable is what is desired.)
Oh, and if you ever do actually want/need to use lookbehind in CF, I've made cfRegex, a library that wraps Java's more powerful regex engine, providing support for lookbehind (with limited-width), and with a (hopefully) easy to use and consistent set of functions for interacting with it.

CFScript switch statement throws error when passed a string?

Update:
Thanks Ben, I decided to copy the URL to another structure and modify that one with StructUpdate(). Here's the code if anyone's interested (specific to my application, but you can edit the lines with comments to get a useful function).
function rebuildURL(key, value)
{
var URLstring = "";
var VarCount = 0;
var tmpURL = duplicate(URL);
var VarSeparator = "";
structUpdate(tmpURL, arguments.key, arguments.value);
for (key in tmpURL)
{
if (tmpURL[key] neq "" and tmpURL[key] neq "10000" and tmpURL[key] neq "1") `<!--- remove the tmpURL[key] neq "10000" and "1"--->`
{
if (VarCount neq 0)
{
VarSeparator = "&";
}
else
{
VarSeparator = "";
}
URLstring = URLstring & VarSeparator & "#Lcase(key)#" & "=#Lcase(tmpURL[key])#";
VarCount = VarCount + 1;
}
}
structClear(tmpURL); `<!---not sure if this is necessary, but probably can't hurt unless you are processing thousands of links --->`
return(URLstring);
}
Thanks again!
Scott
Hey guys,
I'm writing a custom function to rework the URL for links in my pages, and I'm getting the following error:
Complex object types cannot be converted to simple values.
The expression has requested a variable or an intermediate expression result as a simple value, however, the result cannot be converted to a simple value. Simple values are strings, numbers, boolean values, and date/time values. Queries, arrays, and COM objects are examples of complex values.
The most likely cause of the error is that you are trying to use a complex value as a simple one. For example, you might be trying to use a query variable in a cfif tag.
The error occurred in C:\ColdFusion8\wwwroot\pascalnew\turbos.cfm: line 8
Called from C:\ColdFusion8\wwwroot\pascalnew\turbos.cfm: line 108
Called from C:\ColdFusion8\wwwroot\pascalnew\turbos.cfm: line 93
Called from C:\ColdFusion8\wwwroot\pascalnew\turbos.cfm: line 1
Called from C:\ColdFusion8\wwwroot\pascalnew\turbos.cfm: line 1
6 : URLvar = "#URL#";
7 : switch(param)
8 : {
9 : case 'mfr':
10 : {
Here's my function code:
<cfscript>
function SetURL(param, paramval)
{
URLvar = "#URL#";
switch(param)
{
case 'mfr':
{
IF (URLvar contains "mfr")
{
REReplaceNoCase(URLvar, "mfr=^[^\&]", "mfr=#paramval#", "All");
}
break;
}
}
return(URLvar);
}
</cfscript>
Here's what I was testing it with:
<cfset urlvar = SetUrl("mfr", "edwards")>
<cfdump var="#urlvar#">
How is "mfr" a complex variable??
Thanks,
Scott
When you use CFScript, some versions report the beginning of the block as the line with the error.
When you assign "#URL#" to URLVar, you are creating a pointer to the URL scope. then, you attempt to use the contains operator on it. Contains, however, only compares two simple values.
So, your attempt to reference a complex value as a scalar actually comes here:
IF (URLvar contains "mfr")
{
REReplaceNoCase(URLvar, "mfr=^[^\&]", "mfr=#paramval#", "All");
}
At a guess, you are trying to look at the URL itself, not the URL scope. You can assemble this from parts of the CGI scope, including SERVER_NAME, SCRIPT_NAME, AND QUERY_STRING (or you can look at the individual part you need).
Added: If you want to know if a variable is passed in the url, I think you are overthinking this. Let's say you have a param and a paramval to replace it with. You could do it like this:
function paramReplace(param, paramVal, scope)
{
if(structkeyexists(arguments.scope, arguments.param))
{
arguments.scope[arguments.param] = arguments.paramVal;
}
}
paramReplace("mfr", "fred", URL);
This simply uses structKeyExists to find out if that variable exists in the appropriate scope, then replaces the value if it does. If you need to rebuild your actual query string, you can do so later. This avoids scenarios where you get bad data if your query string contains something like "zone=mfr".
I've not tested this -- it's off the cuff -- so it may need tweaking, but it should get you started.

Why the functions doesn't execute completely?

When I try to debug the following function segment, the execution brakes (jumps out of the function) at line pCellTower->m_pCellTowerInfo = pCellInfo:
RILCELLTOWERINFO* pCellInfo = (RILCELLTOWERINFO*)lpData;
CCellTower *pCellTower = (CCellTower*)cbData;
if(pCellTower != NULL)
{
pCellTower->m_pCellTowerInfo = pCellInfo;
}
(the pointer pCellInfo is not set)
Then I tried to comment the line:
RILCELLTOWERINFO* pCellInfo = (RILCELLTOWERINFO*)lpData;
CCellTower *pCellTower = (CCellTower*)cbData;
if(pCellTower != NULL)
{
//pCellTower->m_pCellTowerInfo = pCellInfo;
}
and this way the function executes normally.
Does anyone know what could be wrong?
The most likely explanation is that pCellTower isn't set either. It could contain random bits, and end up pointing outside the memory allocated to your app. The OS cannot allow your program to write outside the space allocated to it, so it sends the program some kind of message (Windows:exception, Unix/Linux:signal) that the write was rejected.
If you trace backwards where the cbData value originates from, you'll probably find it is an uninitialized, random value.