Im trying to use a Else statement on my code, but i cant figure out the correct sintaxe. Wheres the error on that? If i comment the 'Else' line code compiles just fine.
Procedure im_dumb;
begin
If (1 > 2) Then
begin
AddToDebugJournal('if');
end;
else
begin
AddToDebugJournal('else');
end;
end.
Program New;
begin
im_dumb;
end.
Don't add a semicolon before the "else". This is Pascal's way of mitigating dangling else.
In pascal's logic, the semi-colon separates "statements", whereas it terminates them in C.
The syntax for the if-then-else construct is
if expression then instruction [ else instruction ]
so no semi-colon should ever appear before an else.
Refer to your favorite syntax railroad diagram http://pascal-central.com/images/pascalposter.jpg
Related
I'm doing some homework and there's this problem where I have to make a program that tells me how many prime numbers there are between two numbers given by the user. For some reason, when I test the program with F8 I can see the program bounces back and forth between "for" and "if", for no apparent reason. And yes, I HAVE to use this language.
I have tried restanting the IDE, hoping it'ts just some bug (like it often happens on Android Studio). I don't know what else to try, this is the first time I use Lazarus and PASCAL.
program PrimoEntre;
var
a, b, i, q: Integer;
begin
write('Ingrese el primer valor: ');
readln(a);
write('Ingrese el segundo valor: ');
readln(b);
for i:=a to b do //It starts bouncing back and forth from here...
begin
q:=2;
if((b>=2)AND(b<=10)) then //...to here.
begin
while((q>=2) and (q<=b)) do
begin
if(a<>b) then
begin
if((a MOD b)=0) then
begin;
//i ES NO PRIMO
if(q=b) then
begin
writeln('No existen numeros primos entre ', a, ' y ', b, '.');
end;
q:=(q+1);
end;
end
else
begin
if(q=b) then
begin
//i ES PRIMO
writeln(i, ' es primo.');;
q:=1
end;
end;
end;
end
else
begin
while((q>=2) and (b<=10)) do
begin
if(a<>b) then
begin
if((a MOD b)=0) then
begin
//i ES NO PRIMO
if(q=b) then
begin
writeln('No existen numeros primos entre ', a, ' y ', b, '.');
end;
q:=(q+1);
end;
end
else
begin
if(q=b) then
begin
//i ES PRIMO
writeln(i, ' es primo.');
q:=1
end
end;
end;
end;
end;
readln();
end.
I expect the output to be one of the following:
-The console writing every time it finds a prime number between a and b.
-The console saying there isn't any prime number between a and b.
Instead, there's no result. The program just gets stuck and I have to terminate it manually.
You say you are trying to find prime numbers in the range a...b. The problem is that
you are doing this in a quite unnecessarily complicated way and the main reason
your program is jumping all over the place is that you are making it do so because
you are making the value of your q variable jump all over the place.
What I think you should do it to slow down and think what you are trying to do:
You want to iterate the integers in the range a to b. Your for loop does
this fine, with the value of i being what you are testing for primality. I'm going
to refer to this as your outer for loop.
Where you go wrong is to needlessly execute a while loop to test for primality.
Once you have established the i value you are testing, what you want to do is to
test whether there is any factor of i which is other than 1 or i. To do that, you
can use a simple, inner for loop which iterates a value j (so-called to avoid
confusion with your q) to determine whether i is divisible by j with zero remainder using
a mod test:
if it is, there is no point in continuing with the inner, j loop.
The next thing to consider is what should be the upper limit of the
loop for j := ... to ... should be. It is pointless to consider values
of j which are higher than the square root of i for the obvious reason
that if i has an intger factor greater than that, it must also have one
which is lower.
If the j loop completes without finding a factor, i is prime.
Try coding the inner, j loop, and you will see how the result is vastly
simpler (and more predictable) than your existing code, and with very few
opportunities for coding error, and vastly simpler to debug because execution
just "falls" through it for each value of i.
Btw, I completely agree with #TomBrunberg about structured coding as a general proposition, but I think that the two nested for loops you need here don't really need separating into different procedures/functions, though you might try
that once you've got the code working properly.
The causes of your error are a mix between the fact that the problem is highly depending on your input and that you are not treating some cases in else causes.
As an example, I ran your program with a=20 and b=30. The program ran into the for loop, which is correct. However, the (b>2) and (b<=10) condition is false, which made the compiler go to the else branch. However, the first thing it met there was while (q>=2) and (b<=10) which is, from the start, false. There it bounces back as you said in your question.
With a=2 and b=9, your program has a total different behavior.
How to fix it? I guess you first have to clarify what you want. Then, I think, the fix will be obvious.
Your program lacks structure because the whole program is crammed in the main procedure.
As a consequence of the previous, it has too many 'indentation levels' or 'logical chains' to be readable and manageable. With indentation levels or logical chains I mean e.g. your:
'for<condition> - if<condition> - while<condition> - if<condition> - if<condition> - if<condition> - writeln().
Because of the long chains of conditions, it is hard to evaluate what a change will effect, and you might find yourself deeper and deeper in trouble, when you try to fix something.
I suggest you ditch what you have now, and divide your program into procedures / functions according to main operations: for example GetUserEntry(var a, b: integer), function IsPrime(x: integer): boolean, procedure ShowResult() and the main program (GetUserEntry, for a to b if IsPrime then add to outstring, ShowResult(outstring)).
Finally, format your code to be readable using proper indentation.
This is a simple sql statement used to print 2 different questions based on the choice entered. I notice that both statements are run even though the else or if condition is not true. The output printed is correct but I don't require the substitution variable to prompt user for entry if the statement is not true.
SET SERVEROUTPUT ON;
DECLARE
choice number(2) := '&Please_Enter_Choice';
question varchar2(50);
BEGIN
if choice = 1 then
question := '&Whats_your_name?';
else
if choice = 2 then
question := '&How_old_are_you?';
end if;
end if;
DBMS_OUTPUT.PUT_LINE(question);
END;
Substitution variables like &Please_Enter_Choice are replaced in a preprocessing step that takes p!ace (on the client) before the actual code is run (on the server). Please also keep in mind that support for these variables is a feature of the frontend tool (e.g. sql*plus), while the database does not even know they ever existed. Conclusion: you cannot make interactive PL/SQL scripts like that.
I'll post a trivial example, which actually works, just to get an approximate picture of what I'm trying to achieve:
Here is the 'inner' function which takes the data from some table, called test_tab:
create or replace function test_inner RETURN num_typ PIPELINED
IS
BEGIN
FOR cur in (
SELECT x FROM test_tab
)
LOOP
PIPE ROW(cur.x);
END LOOP;
END;
/
Here is the 'outer' function which uses the result of inner function and transforms them appropriately:
create or replace function test_outer RETURN num_typ PIPELINED
IS
BEGIN
FOR x IN (
SELECT * FROM table(test_inner())
)
LOOP
PIPE ROW(x.column_value * 2);
END LOOP;
END;
/
And here is how I use it:
begin
execute immediate 'insert into test_tab(x) values(1)';
execute immediate 'insert into test_tab(x) values(2)';
execute immediate 'insert into test_tab(x) values(3)';
FOR x IN (
select * from table(test_outer())
) LOOP
DBMS_OUTPUT.put_line(x.column_value);
END LOOP;
end;
/
The problem is that test_inner function seems to be ignored by Oracle. When it is called separately, it 'sees' the data inserted prior to its execution. But when it's called as a part of test_outer it doesn't return any data, or maybe doesn't get called at all.
Like I said, the above example will work. But my case is a little bit more complex, so I can't post it entirely.
The test case you have posted does not reproduce the problem you claim to be seeing. So it is not a test case.
#AlexPoole has provided you with some other ideas. Basically there is nothing further we can do unless you can post a better test case, given that you cannot post the entire things (and we don't want to go through hundreds of lines of somebody else's shonky code - I for one get enough of that debugging my own stuff).
Producing a poor test case has not been a waste of time. At least you can rule out certain things: it's nothing to do with one pipelined function calling another. So it's clearly something in your specific implementation. Perhaps not in the internal function logic, but how they are called, the data they work with or some other part of the infrastructure.
All you can do is analyse the individual parts. Start with the core component, and build out, adding other components until you find the bit which breaks. Yes this is a tedious chore. But from your comments it sounds like you're quite a way through this process already.
I'm marking this CW as it isn't an answer to the question, just an extended comment.
Your both pipelined functions in fact are syntactic wrong: you are missing RETURN
See docs
I have been working with a lot of legacy plsql code off late. I see debug statements like below all over the code.The 'if' check was added to avoid the overhead of procedure call when debug mode is OFF.
IF (Debug mode is on) THEN
Debug_pkg.logmsg(l_module_name,'Unexpected error : '|| SQLERRM, FND_LOG.LEVEL_WARNING);
END IF;
Is there a way to write debug statement in one line? In C, we have macros that can be useful to avoid procedural overhead. Can I do something similar in plsql code?
Edit:
Adding a little more details since my question might have confused some. What I am trying to avoid is writing 3 lines to print one debug statement. Can I write debug statement in one line using macros?
Reason why I am trying to do this,
When such statements are added all over the place it gives rise to clutter and reduces readability. When it should have been just one line, I see 3 lines for each debug statement.
Second edit:
Added my answer below.
Depending on the version of Oracle you're using, it is possible to use conditional compilation in PL/SQL. Something like
$IF $$debug_mode
$THEN
Debug_pkg.logmsg(l_module_name,'Unexpected error : '|| SQLERRM, FND_LOG.LEVEL_WARNING);
$END
where $debug_mode is set in the session's PLSQL_CCFLAGS setting or
$IF package_name.debug_mode = 1
$THEN
Debug_pkg.logmsg(l_module_name,'Unexpected error : '|| SQLERRM, FND_LOG.LEVEL_WARNING);
$END
where package_name.debug_mode is a package-level variable that indicates whether the code should be compiled in debug mode.
Again, depending on the version of Oracle you're using, you may be able to put the debug mode check in debug_pkg.logmsg and rely on the compiler either to automatically determine that it would be beneficial to inline the call (eliminating the procedure call overhead) or to instruct the compiler to inline the call with the INLINE pragma. Here is an article that discusses inlining in PL/SQL in more detail.
Thanks for the link http://www.oracle-developer.net/display.php?id=502 from Justin Cave. I ended up doing this for now,
PROCEDURE debug_msg(txt VARCHAR2)
IS
BEGIN
IF (debug mode is on) THEN
debug_pkg.logmsg('Module', txt , LEVEL_WARNING);
END IF;
END;
To inline the above procedure, you need to do this.
PRAGMA INLINE(debug_msg, 'YES');
However inline is just a request to the compiler, it may or may not be inlined. Also, the procedure being inlined needs to be defined in the same package.
I am working with Delphi. Does it make any difference in performance if we write if condition in different ways? For example:
if (condition) then
someVar := someVal
else
someVar := someOtherVal;
Or we can write:
if (condition) then begin
someVar := someVal;
end else begin
someVar := someOtherVal;
end;
I prefer the second option just because it looks better than the first one.
No, there is no difference in performance, the code created will be identical.
An aspect that might be more important than that the second option looks nicer, is that it is better for maintainence. If you need to add another statement in the else block, you will not accidentally forget to add the begin and end, which would put the statement outside the if and always be executed.
This will not make a difference in performance.
begin and end tell the compiler where a block of code starts and finishes, but no computation needs to be done there.
Begin and End do not slow down your code, as others have already said. I am writing another answer to encourage you even more explicitly to ALWAYS use begin and end whenever you could use them.
It is good to be liberal with using Begin and End, and not worry about them slowing you down (because they don't).
If you go the other way, and leave out begin and end wherever you can, you get into a different type of trouble.
This has happened to me lots. You can get in trouble when you insert a line into a place where no begin and end statement exist. You then end up scratching your head wondering what you did that broke your code. Begin-end-everywhere, even where not needed, is standard operating procedure for a lot of Delphi coders.
The only thing you should keep in mind about if-elseif-else is to keep the common cases up in your code before edge cases, so that the least possible conditions are evaluated.