Binding operator used in multi-variable initialization is working only when variables are also declared in the same line - binding

In the following example:
my $i1 = 1;
my $i2 = 2;
my ($v1, $v2);
($v1, $v2) := ($i1, $i2);
say $v1;
say $v2;
the code throws with a compilation Error:
===SORRY!=== Error while compiling ...
Cannot use bind operator with this left-hand side
at ...:8
------> ($v1, $v2) := ($i1, $i2)<HERE>;
When I put declaration and binding in one line, then it runs successfully:
my $i1 = 1;
my $i2 = 2;
my ($v1, $v2) := ($i1, $i2);
say $v1; # 1
say $v2; # 2
$i1 = 11;
$i2 = 22;
say $v1; # 1
say $v2; # 2
Nevertheless the last successful example shows that the variables $v1, $v2 are NOT bound to the variables $i1, $i2, but rather they've got their respective values assigned.
It seems like there is NO actual binding going on but a plain assignment!
Does anyone have an explanation for the mechanics behind this behavior and why is it, that we must also "declare" the variables in the same line, in order for the code to run?

In the first case, it's simply saying that you can't bind that list after creation.
When you bind a list to another, you're not binding every variable, you're binding its container; := binds its left hand side to its right hand side, making them effectively the same thing; if they are not the same thing to start with, you can't do that later.
So if you want to bind a container to another, you will effectively have to declare and bind it, by itself, to whatever you want it bound.
That applies also to the second case. It makes the list ($v1, $v2) the same thing as the right hand side. This should have probably thrown an error, but it will simply not bind every individual container.

It isn't about being declared on the same line.
It is about binding in a declaration, vs binding to a list.
Binding and assignment in a declaration produces different code to regular binding or assignment.
my \abc = 'def';
abc = 5; # ERROR: Cannot modify an immutable Str
\abc = 5; # ERROR: Cannot modify an immutable Capture
for ^3 {
state $i = 0;
say ++$i; # 1␤2␤3␤
}
for ^3 {
state $i;
$i = 0;
say ++$i; # 1␤1␤1␤
}
In particular I don't think your code does what you think it does.
Either that or your expectations are way off.
my $i1 = 1;
my $i2 = 2;
my ($v1, $v2) := ($i1, $i2);
say $v1; # 1
say $v2; # 2
$i2 = 3;
say $v2; # 2
# $v2 = 3; # ERROR: Cannot assign to a readonly variable or a value
It doesn't bind the variables to the other variables, it binds to the current values inside of them.
If that is truly what you wanted you can bind to a Signature object.
my $i1 = 1;
my $i2 = 2;
my ($v1, $v2);
:($v1, $v2) := ($i1, $i2); # <--
say $v1; # 1
say $v2; # 2
$i2 = 3;
say $v2; # 2
# $v2 = 3; # ERROR: Cannot assign to a readonly variable or a value
The whole reason that binding exists is to bind a variable to another variable.
sub var-name ( $a is rw ){ # <-- Bind $a to the incoming variable
$a.VAR.name;
}
my $foo;
say var-name $foo; # $foo
In the above example $a is bound to $foo.
Anything you do to $foo also happens to $a and vice-versa.
You can also do that manually with the binding operator :=.
my ($a,$b,$c);
{
my $v := $a;
say $v.VAR.name; # $a
$v := $b;
say $v.VAR.name; # $b
$v := $c;
say $v.VAR.name; # $c
}
When you bind something it takes the left thing and points it to the thing at the right.
my ($a,$b,$c,$v);
$v := ($a,$b,$c);
The $v variable is now bound to the list containing the variables $a, $b, $c.
Note that the list is not the values inside of the variables, but the actual variables themselves.
say $v[0].VAR.name; # $a
say var-name $v[1]; # $b
say $v.^name; # List
$v[2] = 7;
say $c; # 7
When you try binding a List to another List, you are trying to overwrite the List on the left. Not the variables inside the List.
Even if you managed to do that it would be pointless. About the only thing it would do is to have the left list get garbage collected a little bit sooner.
When you see my $a, there is a few things happening.
A pointer is created and it is added under the name of $a in the namespace.
(close enough anyway)
A Scalar object is created. Its attribute name is set to $a.
That pointer starts pointing to the Scalar.
Almost of the behaviours of a variable are actually behaviours of that Scalar container.
Except one.
When you use the binding operator := you are taking that pointer and pointing it to a new thing.
$a := $b;
# pseudo code
$a.POINTER = $b.POINTER;
A List is not a pointer. (It can be pointed to though.)
(Note that the declaration is also involved in the initial assignment into the Scalar.)
With assignment = the variables or values get a chance to choose what happens.
If you assign to an Array each of the Scalar containers get assigned to each of the values on the right.
my #a;
#a = 0,1,2,3;
my $v := #a[4];
$v = 4;
say #a.raku; # [0, 1, 2, 3, 4]
sub assign ( Positional $dest is raw, Positional $source is raw ){
#for $source.keys -> $index {
# my $v := $dest[$index];
# $v = $source[$index];
#}
$dest.STORE($source)
}
#a = ();
assign #a, (5,6,7,8);
say #a.raku; # [5, 6, 7, 8]
When you use assignment = you are basically calling the STORE method on the left thing. It gets to decide what happens. (It is actually a little bit more complex than that.)
In the case of an Array or List, it goes through the elements assigning each one in turn. (Assuming that element is actually a Scalar container.)
my ($a,$b);
($a,$b) = 1,2;
($a,$b).STORE( (1,2) );
my $list = ($a,$b);
$list.STORE( (1,2) );
When you bind you are just plain overwriting the thing on the left.

Related

Convert a Set of to Integer

As a newbie in Delphi I run into a problem with an external API.
This external API expects a parameter with one or two value, I think called bitwise parameter.
In Delphi this is done by a set of
The basic is an Enumeration.
TCreateImageTask = (
citCreate = 1,
citVerify
);
This I have put into a set of:
TCreateImageTasks = set of TCreateImageTask
In a function I fill this set with:
function TfrmMain.GetImageTask: TCreateImageTasks;
begin
Result:=[];
if chkCreate.checked then Include(Result, citCreate);
if chkVerify.checked then Include(Result, citVerify);
end;
Now I have to give this Tasks to a external DLL, written in C++
The DLL expects a __int8 value. It may contain one or two TCreateImageTasks. In C++ done by:
__int8 dwOperation = 0;
if (this->IsDlgButtonChecked(IDC_CHECK_CREATE))
{
dwOperation = BS_IMGTASK_CREATE;
}
if (this->IsDlgButtonChecked(IDC_CHECK_VERIFY))
{
dwOperation |= BS_IMGTASK_VERIFY;
}
int32 res = ::CreateImage(cCreateImageParams, dwOperation);
So I have to convert my set of to an integer. I do by
function TfrmMain.SetToInt(const aSet;const Size:integer):integer;
begin
Result := 0;
Move(aSet, Result, Size);
end;
I call with
current task := GetImageTask;
myvar := SetToInt(currentTask, SizeOf(currentTask));
The problem I have now, that myvar is 6 when 2 values are inside the set, 2 if only create is inside the set and 4 if only verify is inside the set. That do not look right to me and the external DLL do not know this values.
Where is my fault?
I guess it works when you remove the = 1 in the declaration of TCreateImageTask?
The = 1 shifts the ordinal values by 1 giving the results you see, but is probably not what is needed. For that we need to know the values for BS_IMGTASK_CREATE and BS_IMGTASK_VERIFY.
My psychic powers tell me that BS_IMGTASK_CREATE = 1 and BS_IMGTASK_VERIFY = 2. Given that these are bit masks they correspond to the values 2^0 and 2^1. This matches the ordinal values 0 and 1.
Thus you should declare
TCreateImageTask = (citCreate, citVerify);
to map citCreate to 0 and citVerify to 1.
It's all about something called Bitwise Operation!
Converting a SET to LONGWORD is widely used in Delphi implementation of Windows API.
This would be what you are looking for:
How to save/load Set of Types?
This was already answered here too:
Bitwise flags in Delphi

Modifying method parameters

Is it possible to annotate Dafny method parameters as mutable, without them being objects?
My goal is to be able to verify
method testMethod(a:int, b:int) returns (res :int) {
res :=0;
a := (a - b);
assert a < (a-b);
}
Ignoring the fact this is obviously an absurd assertion, Dafny complains about the LHS not being a mutable variable, while I'd like to avoid introducing temporary variables.
All in-parameters in Dafny are immutable (including in-parameters of reference types, though with an appropriate modifies clause a method can make modifications in the heap by dereferencing such a parameter). So, you need to use a local variable to store the expression a - b in your example. For example:
method testMethod(a:int, b:int) returns (res:int) {
res := 0;
var myLocalA := a - b;
assert myLocalA < myLocalA - b;
}
If you are bothered by having to introduce a new name for the local variable, Dafny actually allows you to give a local variable the same name as an in-parameter. If you find that to be in your style, you can write:
method testMethod(a:int, b:int) returns (res:int) {
res := 0;
var a := a - b;
assert a < a - b;
}
Note that the right-hand side of the assignment to the local variable a mentions the in-parameter a (because the local variable a is not quite yet in scope at that time).
If you do this a lot, you can also start your method off with a statement
var a := a;
This looks ridiculous and may be confusing until you realize what's going on, namely that this statement introduces a local variable a and assigns its initial value the value of the in-parameter a.
The reason for not automatically allowing in-parameters to be used as local variables (which is allowed by many other languages, including C and Java) is that, in my experience, some people then get confused about the meaning of in-parameters in postconditions. An in-parameter mentioned in a postcondition refers to the value of the in-parameter passed in by the caller, and this is made clear by making in-parameters immutable inside the method body.
Rustan

Should for loop counters be local

Right now, I've been making my for loops like this
local i
for i = 1, 10 do
--stuff
end
Since I thought you should try to keep things local for better performance and reduce risk from errors.
However, I've noticed that it is common to simply use.
for i = 1, 10 do
--stuff
end
Is using local preferred, or is omitting it pretty harmless?
(EDIT) There's no difference between the code samples you gave. However, be aware that the variable you defined with local i is not the same variable that is used within your for i = 1, 10 do loop. When the loop exits, the original value of i remains unchanged (that is, i == nil).
siffiejoe points out that loop control/counter variables are never accessible outside of the loop, even if the same variable name was defined in advance. Any references to the variable within the loop will use the loop value. Any references outside of the loop will use the original, or non-loop value.
For this reason, it's safe to reuse an existing variable name in a for statement without corrupting the original. If you want to access the counter variable after the loop, you can define an extra variable beforehand and update it at within the loop as follows (siffiejoe's example):
local j
for i = 1, 10 do
j = i
--[[ stuff ]]
end
print(j) -- j stores the last value of i before the loop exits
Documentation: Numeric for
Short answer: don't add local i before the for loop, because it's useless and confusing.
The for loop starts a new block, the control variable (i here) is already local to this block. Adding the local i is similar to:
local i
do
local i = 0
-- do something
end
Note that the i inside the block is a totally new variable, which shadows the i outside. When the block is over, the i outside the block gets its life back, but has no knowledge of what happened inside the block because the two variables have no relationship except having the same name.
The for loop control-structure in Lua have some particularities, it's not exactly the equivalent of a C for loop.
One of these particularities is that its index variable is controlled by the loop. The index var is itself local and modifying it inside the loop has in fact no effect. Example:
for i=1,5 do
io.write(("i: %d; "):format(i))
i = i + 10 -- this has no effect, as 'for' is in control of the index var.
end
Result:
i: 1; i: 2; i: 3; i: 4; i: 5;

How to refactor string containing variable names into booleans?

I have an SPSS variable containing lines like:
|2|3|4|5|6|7|8|10|11|12|13|14|15|16|18|20|21|22|23|24|25|26|27|28|29|
Every line starts with pipe, and ends with one. I need to refactor it into boolean variables as the following:
var var1 var2 var3 var4 var5
|2|4|5| 0 1 0 1 1
I have tried to do it with a loop like:
loop # = 1 to 72.
compute var# = SUBSTR(var,2#,1).
end loop.
exe.
My code won't work with 2 or more digits long numbers and also it won't place the values into their respective variables, so I've tried nest the char.substr(var,char.rindex(var,'|') + 1) into another loop with no luck because it still won't allow me to recognize the variable number.
How can I do it?
This looks like a nice job for the DO REPEAT command. However the type conversion is somewhat tricky:
DO REPEAT var#i=var1 TO var72
/i=1 TO 72.
COMPUTE var#i = CHAR.INDEX(var,CONCAT("|",LTRIM(STRING(i,F2.0)),"|"))>0).
END REPEAT.
Explanation: Let's go from the inside to the outside:
STRING(value,F2.0) converts the numeric values into a string of two digits (with a leading white space where the number consist of just one digit), e.g. 2 -> " 2".
LTRIM() removes the leading whitespaces, e.g. " 2" -> "2".
CONCAT() concatenates strings. In the above code it adds the "|" before and after the number, e.g. "2" -> "|2|"
CHAR.INDEX(stringvar,searchstring) returns the position at which the searchstring was found. It returns 0 if the searchstring wasn't found.
CHAR.INDEX(stringvar,searchstring)>0 returns a boolean value indicating if the searchstring was found or not.
It's easier to do the manipulations in Python than native SPSS syntax.
You can use SPSSINC TRANS extension for this purpose.
/* Example data*/.
data list free / TextStr (a99).
begin data.
"|2|3|4|5|6|7|8|10|11|12|13|14|15|16|18|20|21|22|23|24|25|26|27|28|29|"
end data.
/* defining function to achieve task */.
begin program.
def runTask(x):
numbers=map(int,filter(None,[i.strip() for i in x.lstrip('|').split("|")]))
answer=[1 if i in numbers else 0 for i in xrange(1,max(numbers)+1)]
return answer
end program.
/* Run job*/.
spssinc trans result = V1 to V30 type=0 /formula "runTask(TextStr)".
exe.

Casting a value in Lua table, not a link

I have simplified my code so you can have a better understanding:
x = {}
x["foo"]=1
a = {}
a[1]=x
x["foo"]=2
a[2]=x
print(a[1]["foo"])
print(a[2]["foo"])
The result is:
2
2
Or I was expecting:
1
2
I understant that a[1] is directing at the adress of the table x["foo"]. Then, when I change the value of this table, the variable a[1] points to the new value.
How can I tell Lua that I want to assign the VALUE and not link to and adress?
And just another thing: if x is a "simple" variable, not an array, the value is passed:
y = {}
x = 1
a = {}
a[1] = x
x = 2
a[2] = x
print(a[1])
print(a[2])
returns
1
2
The Lua manual, last but one paragraph of §2.1, says:
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.

Resources