Why does the expression: If (A:=!A) evaluate differently each time a hotkey is pressed? - switch-statement

In an Autohotkey script, once a user presses the CapsLock key, a SplashText should pop up indicating that it is ON, or out when it is OFF, the problem here is not about the code that gets it to work but how much simpler it can get.
There are different ways that do it, some need about 25 lines, some use SetTimer and GetKeyState internal functions and several loops to get it to run, some just about five and no loops.
Simplest:
#SingleInstance Force
SetCapsLockState, Off
~CapsLock::
If (Tog:=!Tog)
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
else
SplashTextOff
return
How does: If (Tog:=!Tog) get this code running so easily? Tog is just a variable not initiated, and each time the CapsLock is pressed it is continuously changing its value from 1 to 0
It seems to be acting as a Flag in the code? what am I missing in this line:
If (Tog:=!Tog)
What makes it evaluate different each time?
This is one below is another approach with A = 0 working as a switch, I made this one and it doesn't quite get as simple as I'd like it to be but it does the job.
Longer code:
#SingleInstance Force
SetCapsLockState, Off
~CapsLock::
If (A = 0)
{
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
A=1
}else
{
SplashTextOff
A=0
}
return
Longest code:
This last one gets the same result but checks the actual physical state of the key It wouldn't rely on SetCapsLockState, Off at the top of the script to make sure a switch will do the rest of the work in just one line as the simpler one.
#SingleInstance Force
#Persistent
SetTimer, StateCapsLockON_Timer, 100
Return
~CapsLock::
StateCapsLockON_Timer
If GetKeyState("CapsLock", "T")
{
SetTimer, StateCapsLockOFF_Timer, 100
SplashTextOn ,350 ,35 , Wanted !, [CapsLock] Activated.
SetTimer, StateCapsLockON_Timer, Off
}
Return
StateCapsLockOFF_Timer:
If !GetKeyState("CapsLock", "T")
{
SetTimer, StateCapsLockOFF_Timer, Off
SplashTextOff
SetTimer, StateCapsLockON_Timer, On
}
Return
Any good ideas about the way If (Tog:=!Tog) works in the simplest of these three examples?

I got this now, check logical-not on this link:
https://lexikos.github.io/v2/docs/Variables.htm
If the operand (In this case Tog) is blank or 0, the result of applying logical-not (or !Tog) is 1, which means "true". Otherwise, the result is 0 (false)
if (Tog = 0)
Tog = 1
would bring the same result as:
If Tog:=!Tog
Because an operation was taking place before the If even checked the changed value, if wasn't just comparing data, the operation was happening before the if since the values inside the parenthesis were not just being read but were also being changed and the variable being reassigned.
(expression) Any sub-expression enclosed in parentheses. For example, (3 + 2) * 2 forces 3 + 2 to be evaluated first.

The key difference is the usage of the assignment operator := as opposed to the comparing operator =. Since, as you've seen, you can evaluate expressions in an if-statement, you can actually include both operators in the same if-statement. Here's an example:
f1::
If (( test := 3+2 ) = 5 )
MsgBox
Return
Here "test" is first being assigned the sum of 3+2, then compared to 5. So, the key is that if-statements allow assignments to take place and that assignments take place first, that is, before anything is compared and evaluated to be true or false.
If there is no comparing operator (= , <, >, <=, >=), as is the case in your toggle, it just evaluates whether the variable itself is true or false. If the variable is blank, 0, or false, it evaluates to false; everything else is true, even the string "false".
Now for the fun bit. We can actually reduce your code to one line if we use Progress with the "zh0" option.
~CapsLock::Progress , % ( Tog := !Tog ) ? "zh0 w350 h35" : "Off" ,, [CapsLock] Activated. , Wanted !
Unfortunately, this isn't possible with SplashText since these are actually two separate commands. But the upside is that Progress actually has a lot more options available, so you can change the font size and color, etc.

Related

“P6opaque, Str” vs simple “Str” types in Perl 6

This is a follow-up to my previous question.
I am finally able to reproduce the error here:
my #recentList = prompt("Get recentList: e.g. 1 2 3: ").words || (2,4,6);
say "the list is: ", #recentList;
for #recentList -> $x {
say "one element is: ", $x;
say "element type is: ", $x.WHAT;
say "test (1,2,3).tail(\"2\") : ", (1,2,3).tail("2");
say ( (10.rand.Int xx 10) xx 15 ).map: { #($_.tail($x)); };
}
And the results are ok as long as I use the default list by just hitting return at the prompt and not entering anything. But if I enter a number, it gives this error:
Get recentList: e.g. 1 2 3: 2
the list is: [2]
one element is: 2
element type is: (Str)
test (1,2,3).tail("2") : (2 3)
This type cannot unbox to a native integer: P6opaque, Str
in block at intType.p6 line 9
in block <unit> at intType.p6 line 5
If tail("2") works, why does tail($x) fail? Also, in my original code, tail($x.Int) wouldn't correct the problem, but it did here.
This is at best a nanswer. It is a thus-far failed attempt to figure out this problem. I may have just wandered off into the weeds. But I'll publish what I have. If nothing else, maybe it can serve as a reminder that the first three steps below are sensible ones; thereafter I'm gambling on my ability to work my way forward by spelunking source code when I would probably make much faster and more reliable progress by directly debugging the compiler as discussed in the third step.
OK, the first step was an MRE. What you've provided was an E that was fully R and sufficiently M. :)
Step #2 was increasing the M (golfing). I got it down to:
Any.tail('0'); # OK
Any.tail('1'); # BOOM
Note that it can be actual values:
1.tail('1'); # BOOM
(1..2).tail('1'); # BOOM
But some values work:
(1,2).tail('1'); # OK
Step #3 probably should be to follow the instructions in Playing with the code of Rakudo Perl 6 to track the compiler's execution, eg by sticking says in its source code and recompiling it.
You may also want to try out App::MoarVM::Debug. (I haven't.)
Using these approaches you'll have the power to track with absolute precision what the compiler does for any code you throw at it. I recommend you do this even though I didn't. Maybe you can figure out where I've gone wrong.
In the following I trace this problem by just directly spelunking the Rakudo compiler's source code.
A search for "method tail" in the Rakudo sources yielded 4 matches. For my golf the matching method is a match in core/AnyIterableMethods.pm6.
The tail parameter $n clearly isn't a Callable so the pertinent line that continues our spelunking is Rakudo::Iterator.LastNValues(self.iterator,$n,'tail').
A search for this leads to this method in core/Iterator.pm6.
This in turn calls this .new routine.
These three lines:
nqp::if(
n <= 0, # must be HLL comparison
Rakudo::Iterator.Empty, # negative is just nothing
explain why '0' works. The <= operator coerces its operands to numeric before doing the numeric comparison. So '0' coerces to 0, the condition is True, the result is Rakudo::Iterator.Empty, and the Any.tail('0') yields () and doesn't complain.
The code that immediately follows the above three lines is the else branch of the nqp::if. It closes with nqp::create(self)!SET-SELF(iterator,n,f).
That in turn calls the !SET-SELF routine, which has the line:
($!lastn := nqp::setelems(nqp::list, $!size = size)),
Which attempts to assign size, which in our BOOM case is '1', to $!size. But $!size is declared as:
has int $!size;
Bingo.
Or is it? I don't know if I really have correctly tracked the problem down. I'm only spelunking the code in the github repo, not actually running an instrumented version of the compiler and tracing its execution, as discussed as the sensible step #3 for trying to figure out the problem you've encountered.
Worse, when I'm running a compiler it's an old one whereas the code I'm spelunking is the master...
Why does this work?
(*,*).tail('1') # OK
The code path for this will presumably be this method. The parameter $n isn't a Callable so the code path will run thru the path that uses the $n in the lines:
nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
The $n == Inf shouldn't be a problem. The == will coerce its operands to numerics and that should take care of $n being '1'.
The nqp::elems($!reified) - $n.Int shouldn't be a problem either.
The nqp ops doc shows that nqp::elems always returns an int. So this boils down to an int - Int which should work.
Hmm.
A blame of these lines shows that the .Int in the last line was only added 3 months ago.
So, clutching at straws, what happens if one tries:
(my int $foo = 1) - '1' # OK
Nope, that's not the problem.
It seems the trail has grown cold or rather I've wandered off the actual execution path.
I'll publish what I've got. Maybe someone else can pick it up from here or I'll have another go in a day or three...

Pythonic way of creating if statement for nested if statements

I'm kind of newbie as programmer, but I wish to master Python and I'm developing open source application. This application has function to gather some information. This function takes 1 parameter. This parameter can be 0, 1 or 2. 0 = False, 1 = True, 2 = Multi. Also I have an if statement that does 2 actions. 1st - (when False) gathers single type value, 2nd - (when True) gathers multiple type values and when parameter is 2 (multi) then it will gather single type (1st) and multiple types (2nd). My if statement looks like this:
if False:
get_single_type = code.of.action
generators.generate_data(False, get_single_type)
elif True:
get_multiple_type = code.of.action
generators.generate_data(True, get_multiple_type)
else:
get_single_type = code.of.action
generators.generate_data(False, get_single_type)
get_multiple_type = code.of.action
generators.generate_data(True, get_multiple_type)
Is there maybe better way of avoiding this kind of coding, like in last else statement when I call both single and multiple.
Thank you in advance.
One thing I learned from Python is that although it lacks the Switch operator, you can use dictionary in a similar fashion to get things done since everything is an object:
def get_single():
# define your single function
get_single_type = code.of.action
generators.generate_data(False, get_single_type)
def get_multi():
# define your multi function
get_multiple_type = code.of.action
generators.generate_data(True, get_multiple_type)
actions = {
0: [get_single],
1: [get_multi],
2: [get_single, get_multi]
}
parameter = 0 # replace this line with however you are capturing the parameter
for action in actions[parameter]:
action()
This way you avoid c+p your code everywhere and have it referenced from the function, and your "actions" dictionary define the function to be used based on the parameter given.
In this case since you have multiple functions you want to call, I kept all dictionary items as a list so the structure is consistent and it can be iterated through to perform any number of actions.
Ensure you use leave out the () in the dictionary so that the functions aren't instantiated when the dictionary is defined. And remember to add () when you are actually calling the function from the dictionary to instantiate it.
This is something you will often encounter and it is pretty much always bad practice to be repeating code. Anyway, the way to do this is use two if-statements. This way, even if the first case passes, the second case can still pass. Oh, and assuming your variable that can be 0, 1 or 2 is called x, then we could either use or and two checks:
if x == 0 or x == 2:
but, personally, I prefer using in on a tuple:
if x in (0, 2):
get_single_type = code.of.action
generators.generate_data(False, get_single_type)
if x in (1, 2):
get_multiple_type = code.of.action
generators.generate_data(True, get_multiple_type)

IF ELSE vs Select Case

I wish to know how this would impact my coding when handling large volumes of data, and how I would construct my logic arguments
Two questions:
1) What are the main differences between IF-ELSE and Select CASE? Does select case operate by evaluating all cases at the same time?
If I have a situation where, by nature of its construction, need to fulfill two or more cases at the same time, for e.g.
int = 5
Select case int
Case >0
Case 5
Case <0
Where I would need to "trigger" both Cases "1" and "2" for action, do I use CASE over IF ELSE?
2) Now for the other case, if I have a variable that will trigger more one case but I would like to restrict to only one case by priority, say I would only like Case "1" for action and exclude the rest, am I right to say that IF-ELSE would triumph in this regard?
EDIT - I realized that my question was phrased poorly. I did some edits to the code
Some clarification on Select Case before actually answering your question:
as you suggested, you can combine several values in one Case switch in VBA, e.g.: Case Is>40, 20, 10, 2 To 3, for more information see documentation on MSDN
It'll execute at most one Case, it'll exit after finding a match (e.g. in the example execute Case >0 then exit without even evaluating Case 5)
It'll only evaluate your variable / expression once and use this same value for all comparisons in contrary to nested if which evaluates multiple time
if you want to execute "both" for a value you can nest if within case:
Case Is > 0
<Common code>
If i = 5 Then
<code only for case 5>
End If
Advantage of Select Case
It's more efficient when your decision is about multiple values of a single variant / expression
it also can be very useful when your expression is e.g. result of a time consuming function, in this case you really can save time compared to if
Advantage of If
Basically it's the good option in all the cases which are not described for Select Case e.g.:
you have only two options to choose from (it's the same time with both if and select, but if is easier to read)
you have multiple expressions to consider during decision and you can't easily convert them to a single value
Similarly to Select Case you can also use elseif to prepare multiple comparisons, it'll also stops at first fullfilled criteria, but here your expression will be evaluated every time until finding the match and of course you can use more complex criteria.
If-Else and Switch statement are good in different cases.
For example, If-Else has logic conditions like:
if (n < 5 && a > 5) { } // && is a logical AND
and nested constructions like
if (n < 5) {
if (n < 0)
{
}
else
{
}
} else { }
You cannot do this in switch statement.
However, switch is better, more elegant and faster in some situations:
switch (a)
{
case 1:
case 2:
case 3:
// ...
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 10:
break;
default:
break;
}
would look very bad in if-else format:
if (a == 1 || a == 2 || a == 3)
{
}
else
if (a == 4)
{
}
else
// ...
I'm not sure about your case but in most languages switch statement is more performant.
Simply said, use switch statement every time it is possible and there are more than two cases. If there are only two cases or it is impossible to use switch - use if.

Why is Matlab is not reading an empty cell while running an if statement?

I am using the loop below to isolate instances where data was recorded versus those with no data. The data set is very large (varying from 1000-6000 depending on the column) and of mixed data types, so the only practical solution I can think of is using loops.
I can't get the if or while statement to accurately read a blank space. It runs without any errors if I use a for loop, but it never enters the first half of the if-meaning I end up copying, not separating my data. The varying sizes of data make a for loop undesirable.
while (isempty(andover_all{j,1})==1)
if andover_all{h,33}=='';
current_data{k,4}= formated_date{j};
k=k+1;
else
current_data{i,1}=formated_date{j};
current_data{i,2}=andover_data{33}(j);
i=i+1;
end
h=h+1;
end
Andover_all is an array of strings, current_data and andover_data are cell arrays with mixed data types. I have tried using isempty, [], cellfun(#isempty,andover_data), and a function eq.m that allows me to compare cell elements-none of them work. I also don't want to remove empty cells from the data, just skip over them.
Please let me know if you have any ideas
The empties are indeed something to get used to. It's like working with inf or NaN; what should things like NaN==NaN or 1/0==inf return? There's special rules for these guys. Simple ones, but you have to get to know them. To make all the special rules for these guys less of a burden, more intuitive and more readable, MATLAB has special functions for them: isinf (to detect inf), isnan (to detect NaN) and isfinite (to detect either inf or NaN).
The empties also have special behavior and special rules that require some getting used to. If you think about it, it all makes sense in the end: What should []==[] return? or 1==''?
Empty, of course. And even if []==false is empty, [] is false when evaluated by an if. Easy right? :)
Unfortunately, there is no equivalent of isinf or isnan to detect empties of a specific type (there is no isemptycell or isemptychar etc.) There is an equivalent of isfinite for empties (which is isempty), which catches either '', {}, or [].
But sometimes it is desirable to have checks for specific empties, as in your case. The empties preserve their class. This means, {} is really a cell, and [] really an array of doubles.
Therefore, to detect empty cells:
>> a = {};
>> iscell(a) && isempty(a)
ans =
1
to detect empty strings:
>> a = '';
>> ischar(a) && isempty(a)
ans =
1
and to detect empty arrays:
>> a = [];
>> isnumeric(a) && isempty(a)
ans =
1

Smalltalk - Compare two strings for equality

I am trying to compare two strings in Smalltalk, but I seem to be doing something wrong.
I keep getting this error:
Unhandled Exception: Non-boolean receiver. Proceed for truth.
stringOne := 'hello'.
stringTwo := 'hello'.
myNumber := 10.
[stringOne = stringTwo ] ifTrue:[
myNumber := 20].
Any idea what I'm doing wrong?
Try
stringOne = stringTwo
ifTrue: [myNumber := 20]`
I don't think you need square brackets in the first line
Found great explanation. Whole thing is here
In Smalltalk, booleans (ie, True or False) are objects: specifically, they're instantiations of the abstract base class Boolean, or rather of its two subclasses True and False. So every boolean has type True or False, and no actual member data. Bool has two virtual functions, ifTrue: and ifFalse:, which take as their argument a block of code. Both True and False override these functions; True's version of ifTrue: calls the code it's passed, and False's version does nothing (and vice-versa for ifFalse:). Here's an example:
a < b
ifTrue: [^'a is less than b']
ifFalse: [^'a is greater than or equal to b']
Those things in square brackets are essentially anonymous functions, by the way. Except they're objects, because everything is an object in Smalltalk. Now, what's happening there is that we call a's "<" method, with argument b; this returns a boolean. We call its ifTrue: and ifFalse: methods, passing as arguments the code we want executed in either case. The effect is the same as that of the Ruby code
if a < b then
puts "a is less than b"
else
puts "a is greater than or equal to b"
end
As others have said, it will work the way you want if you get rid of the first set of square brackets.
But to explain the problem you were running into better:
[stringOne = stringTwo ] ifTrue:[myNumber := 20]
is passing the message ifTrue: to a block, and blocks do not understand that method, only boolean objects do.
If you first evaluate the block, it will evaluate to a true object, which will then know how to respond:
[stringOne = stringTwo] value ifTrue:[myNumber := 20]
Or what you should really do, as others have pointed out:
stringOne = stringTwo ifTrue:[myNumber := 20]
both of which evaluates stringOne = stringTwo to true before sending ifTrue:[...] to it.
[stringOne = stringTwo] is a block, not a boolean. When the block is invoked, perhaps it will result in a boolean. But you are not invoking the block here. Instead, you are merely causing the block to be the receiver of ifTrue.
Instead, try:
(stringOne = stringTwo) ifTrue: [
myNumber := 20 ].
Should you be blocking the comparison? I would have thought that:
( stringOne = stringTwo ) ifTrue: [ myNumber := 20 ]
would be enough.
but I seem to be doing something wrong
Given that you are using VisualWorks your install should include a doc folder.
Look at the AppDevGuide.pdf - it has a lot of information about programming with VisualWorks and more to the point it has a lot of introductory information about Smalltalk programming.
Look through the Contents table at the beginning, until Chapter 7 "Control Structures", click "Branching" or "Conditional Tests" and you'll be taken to the appropriate section in the pdf that tells you all about Smalltalk if-then-else and gives examples that would have helped you see what you were doing wrong.
I would like to add the following 50Cent:
as blocks are actually lambdas which can be passed around, another good example would be the following method:
do:aBlock ifCondition:aCondition
... some more code ...
aCondition value ifTrue: aBlock.
... some more code ...
aBlock value
...
so the argument to ifTrue:/ifFalse: can actually come from someone else. This kind of passed-in conditions is often useful in "..ifAbsent:" or "..onError:" kind of methods.
(originally meant as a comment, but I could not get the code example to be unformatted)

Resources