My general understanding of a basic while loop (in other languages) is the while loop will break out itself when the variable is no longer true. This does not seem to be happening in Pine Script v5.
Example:
(_RSI is less than _Min_RSI) and (_VOL is greater than _Min_VOL and less than _Max_VOL)
_switch = 0
while _switch > -1
_switch := ( (_RSI >= _Min_RSI and _RSI <= _Max_RSI) ? 1 : -1 )
// While loop should break out automatically after this line if _switch equal to -1
_switch := ( (_VOL >= _Min_VOL and _VOL <= _Max_VOL) ? 1 : -1 )
break
When _RSI is less than _Min_RSI, _switch is correctly set to -1. But, the while loop does NOT break out automatically.......
Instead, it continues to the _VOL line. In essence the overall output is an OR whereas I'm expecting AND.
Above is a sample. The actual code has 50+ checks, for (each of) 10 time-frames. Originally I was using 50 if statements, but thought the while loop would help performance.
Seems the only workaround is to evaluate (and break out after) each line, which kinda defeats the purpose of using a while loop in the first place.
What am I doing wrong? Or does the while loop simply work differently in PS vs other languages?
Thanks
Answer from TradingView Support.
Correct, as we said in the previous post when the 'while' expression
is checked, it goes into the 'while' scope and executes the code
block, if the expression is changed from inside the local block it
will only be re-checked on the next iteration of the script, but it
will not break automatically in the middle of the local scope. If you
want to stop the loop in the middle - use the 'break' keyword after
re-assigning the value of the expression.
Clear.
Related
I'm writing a program for a Schneider PLC using structured text, and I'm trying to do it using object oriented programming.
Being a newbie in PLC programming, I wrote a simple test program such a this:
okFlag:=myObject.aMethod();
IF okFlag THEN
// it's ok, go on
ELSE
// error handling
END_IF
aMethod must perform some operations, wait for the result (there is a "time-out" check to avoid deadlocks) and return TRUE or FALSE
This is what I expected during program execution
1) when the okFlag:=myObject.aMethod(); is reached, the code inside aMethod is executed until a result is returned. When I say "executed" I mean that in the next scan cycle the execution of aMethodcontinues from the point it had reached before.
2) the result of method calling is checked and the main flow of the program is executed
and this is what happens:
1) aMethod is executed but the program flow continues. That is, when it reaches the end of aMethod a value it's returned, even if the events that aMethod should wait for are still executing.
2) on the next cycle, aMethod is called again and restarts from the beginning
This is the first solution I found:
VAR_STATIC
imBusy: BOOL
END_VAR
METHOD aMethod: INT;
IF NOT(imBusy) THEN
imBusy:=FALSE;
aMethod:=-1; // result of method while in progress
ELSE
aMethod:=-1;
<rest of code. If everything is ok, the result is 0, otherwise is 1>
END_IF
imBusy:=aMethod<0;
and the main program:
CASE (myObject.aMethod()) OF
0: // it's ok, go on
1: // error handling
ELSE
// still executing...
END_CASE
and this seems to work, but I don't know if it's the right approach.
There are some libraries from Schneider which use methods that return boolean and seem to work as I expected in my program. That is: when the cycle reaches the call to method for the first time the program flow is "deviated" somehow so that in the next cycle it enters again the method until it's finished. It's there a way to have this behaviour ?
generally OOP isn't the approach that people would take when using IEC61131 languages. Your best bet is probably to implement your code as a state machine. I've used this approach in the past as a way of simplifying a complex sequence so that it is easier for plant maintainers to interpret.
Typically what I would recommend if you are going to take this approach is to try to segregate your state machine itself from your working code; you can implement a state machine of X steps, and then have your working code reference the statemachine step.
A simple example might look like:
stepNo := 0;
IF (start AND stepNo = 0) THEN
StepNo = 1;
END_IF;
(* there's a shortcut unity operation for resetting this array to zeroes which is faster, but I can't remember it off the top of my head... *)
ActiveStepArray := BlankStepArray;
IF stepNo > 0 THEN
IF StepComplete[stepNo] THEN
stepNo := stepNo +1;
END_IF;
ActiveStepArray[stepNo] := true;
END_IF;
Then in other code sections you can put...
IF ActiveStep[1] THEN
(* Do something *)
StepComplete[1] := true;
END_IF;
IF ActiveStep[2] THEN
(* Do Something *)
StepComplete[2] := true;
END_IF;
(* etc *)
The nice thing about this approach is that you can actually put all of the state machine code (including jumps, resets etc) into a DFB, test it and then shelve it, and then just use the active step, step complete, and any other inputs you require.
Your code is still always going to execute an entire section of logic, but if you really want to avoid that then you'll have to use a lot of IF statements, which will impede readability.
Hope that helps.
Why not use SFC it makes your live easier in many cases, since it is state machine language itself. Do subprogram, wait condition do another .. rince and repeat. :)
Don't hang just for ST, the other IEC languages are better in some other tasks and keep thing as clear as possible. There should be not so much "this is my cake" mentality on the industrial PLC programming circles as it is on the many other programming fields, since application timeline can be 40 years and you left the firm 20 years ago to better job and programs are almost always location/customer or atleast hardware specific.
http://www.automation.com/pdf_articles/IEC_Programming_Thayer_L.pdf
I'm really new to programming Objective-C and programming in general, so forgive me if this is a super obvious question:
I'm wondering if Objective-C runs code line by line. What I mean by that is if it processes one line before moving onto another, or if it just runs the next line regardless of whether the previous line is finished or not.
For example,
int difference = number1 - number2;
if (difference < 0) {
difference = difference + 10;
}
result = difference;
Say that number1 = 3 and number2 = 7. When I run this code, will it go line by line and run the if block before line 5 and give me result = 6, or will it start running the if block and line 5 at the same time and give me result = -4?
Thanks in advance!
EDIT: Changed modulo to addition because of Obj-C quirk.
As far as your thinking goes you may as well assume that it runs line by line.
In fact the compiler may put the code into a more efficient order (i.e. making sure that divisions aren't too close together, as this could make things slow). However even when the compiler does re-order things it makes sure that a result is calculated before it is needed. When you build the code in a fully optimised fashion (release mode) if you debug it you can see that the code has actually been re-ordered (the debugger jumps when you wouldn't expect it to). However as far as thinking about your code goes it's safe to assume that it runs it in the order you write it.
If you are new to programming, all programming languages you will meet at the beginning of your learning will execute statements sequentially. It means that the next one happens only after the previous one ends. However, languages like Objective C are not line-oriented and what matters are not lines but statements, like assignment ending with semicolon! or if statement.
What does whenever sqlerror exit 9 mean?
And does the number 9 represent anything? I was thinking maybe it's a sqlerror code but I couldn't find a sqlerror code with a number 9.
Typically exiting 0 means success and non-zero means an error. The number of the exit code refers to where the error occurred, and is programmer-defined. Perhaps your program would exit 1 if login failed, 2 if a query returned no rows where at least one was expected, etc. A wrapper program can call this one, then use the return code to see if it ran successfully or not. If not, you know where in the code it failed by the number. Used as you are dealing with, they are called magic numbers. Who knows what they mean as apparently the original developer never at least defined them in a comment. Now you know why magic numbers should be avoided. Instead, define return codes as constants with a meaningful name at the top of your program, then refer to them by that name when used. Whoever maintains the code after you will sing your praises instead of cursing your existence! In Oracle PL/SQL for instance, I'd do something like this:
...
-- Define return codes.
ERR_NOLOGIN CONSTANT INTEGER := 1;
ERR_NOROWS CONSTANT INTEGER := 2;
ERR_TOO_MANY_ROWS CONSTANT INTEGER := 3;
...
-- Then in your error handing:
WHENEVER ERROR EXIT ERR_NOLOGIN; -- No magic number makes for
-- easier to read code.
...
Okay, so I'm trying to have the program do three steps...
1: choose a number between (m,n) which are parameters being passed in (Set to variable "repeat")
2: choose a random number between 0 and the variable "repeat" from step one. (Set to variable "o")
3: subract "o" from "repeat" and set that result to variable "p"
thus I get a number (lets say 100)
then a random number from 0-100 (lets say 40)
and then I get the difference of 100-40 (60...)
I then want the program to run a for loop "o" (40) times and another for loop "p" (60) times...
the code for the for loops section looks like this (keep in mind there is more code before this... It just doesn't really pertain to this question:
def randomStars(pic,m,n):
repeat=random.randint(200,300)
o=random.randint(0,repeat)
p=repeat-o
for i in o:
star(pic,x,y)
for j in p:
largeStar(pic,x,y)
show(pic)
What's happening is I'm getting an error message on the line:
for i in o:
that says "iteration over non-sequence
inappropriate argument type
I've also added print statements after the 3 variables are set and they are working...
ex.1 repeat=230; o=103; p=127
ex.2 repeat=221; o=72; p=149
and then I immediately try to get the for loop to run "o"number of times and I get the above error message... I don't see how it is a non-sequence. But perhaps I'm simply not understanding the definition of a sequence
o and p are integers. For for loops you need something that is iterable. I thing you can change it to:
for i in range(o):
This is range() documentation for Python 2.x
I am trying to write this code:
for (i = 0; i <= CONST - 1'b1; i = i + 1'b1)
begin : loop_inst
if (i < 3)
begin
if (changed[i] & !done_q[i])
begin
writedata[3-i] = en[i];
writedata[2-i:0] = readdata[2-i:0];
writedata[15:4-i] = readdata[15:4-i];
end
end
else
...
Basically, the location of the bit I am trying to write to (en) changes depending on which address I am talking to, depending on i. This code is not synthesizable because i is not a constant.
Is there any other workaround to this? The only workaround I know is writing out those three statements CONST times. I am hoping I DON'T have to do that in the end. Is there any other solution?
It looks like you're trying to copy readdata to writedata all the time, but fill in the LSBs with en if certain special case conditions are met. I'm also going to assume that the for loop you have is in an always block, and that you're intending to build combo logic.
The for loop as you've it written doesn't make much sense to me from a hardware perspective. A for loop is used for building arrays of logic, and as you've
written it you'll have at least 3 logic cones trying to set values on the entire writedata bus. (If it generates anything at all, it'll be some weird priority structure).
That said, it's probably the range selects that your compiler is complaining about, ie the writedata[2-i:0] rather than the writedata[3-i] = en[i]; (anything with : in the part select). If you want to do something along those lines, you can use 'indexed part selects' ( +: or -:) but there are better solutions in this case.
I'd rewrite it as follows - assuming I've assumed correctly :)
always #( /*whatever*/ ) begin
// default assignment
writedata = readdata;
// overwrite some bits in writedata for special cases
for(i=0; i<3; i++) begin
if( changed[i] & !done_q[i] )
writedata[3-i] = en[i];
end
end
In this code, I'm setting writedata to readdata, and then tweaking the resulting value of writedata if the special cases are in play. The for loop is building 3 logic cones, one for each of the bits in writedata[3:1]. I'd double-check if the bit mapping is what you intend -ie, mapping en[2:0] on to writedata[1:3].