I have this code in one modules:
PROCEDURE Get (File: IN Ada.Text_IO.File_Type; Item : OUT Rational) IS
N: Integer;
D: Integer;
Dummy: Character;
BEGIN -- Get
LOOP
BEGIN
Ada.Integer_Text_IO.Get(File => File, Item => N);
Ada.Text_IO.Get (File => File, Item => Dummy);
Ada.Integer_Text_IO.Get(File => File, Item => D);
Item := N/D;
if Dummy /= '/' then
........;
end if;
EXIT;
EXCEPTION
when other =>
Ada.Text_IO.Put_Line(" here is exception ");
END;
END LOOP;
END Get;
What is differences with this second code.
The main of my question is if I don't put raise in body of statement of exception what is happen?
PROCEDURE Get (File: IN Ada.Text_IO.File_Type; Item : OUT Rational) IS
N: Integer;
D: Integer;
Dummy: Character;
BEGIN -- Get
LOOP
BEGIN
Ada.Integer_Text_IO.Get(File => File, Item => N);
Ada.Text_IO.Get (File => File, Item => Dummy);
Ada.Integer_Text_IO.Get(File => File, Item => D);
Item := N/D;
if Dummy /= '/' then
........;
end if;
EXIT;
EXCEPTION
when other =>
Ada.Text_IO.Put_Line(" here is exception ");
**raise;**
END;
END LOOP;
END Get;
The main of my question is if I don't put raise in body of statement of exception what is happen???
Thank you very much.
The only difference between both code modules is that the exception (if any is raised during execution of Get) is reraised, i.e. the exception is propagated to the caller of Get.
Whether this is the desired behaviour depends on your needs, i.e. does the caller of Get need to know that an exception occurred?
In your example several kinds of exceptions may occur, e.g.
not reading the correct/expected input (the file to read from does not start with a number)
trying to read from a file that has not been opened
reading D as 0 (thus resulting in a division by 0)
All of these are handled in the same manner by printing "here is exception". The first implementation of Get then silently returns control to the caller (who will not know that anything strange happened). The second implementation, however, will inform the caller by reraising the exception.
For more information see the Ada LRM ยง11.3 (Raise Statements).
Related
I write a function that print all contents of file like that
let rec print_file channel =
try
begin
print_endline (input_line channel);
print_file channel
end
with End_of_file -> ()
And because of print_file is last operation I was thinking that it will be optimized to regular loop. but when I had runned my program on really big file, I had got stack overflow.
So I has tried to wrap input_line function to input_line_opt that don't raise exception and little change code of print_file.
let input_line_opt channel =
try Some (input_line channel)
with End_of_file -> None
let rec print_file channel =
let line = input_line_opt channel in
match line with
Some line -> (print_endline line; print_file channel)
| None -> ()
And now it works like regular tail recursive function and don't overflow my stack.
What difference between this two function?
In the first example, try ... with is an operation that occurs after the recursive call to print_file. So the function is not tail recursive.
You can imagine that try sets up some data on the stack, and with removes the data from the stack. Since you remove the data after the recursive call, the stack gets deeper and deeper.
This was a consistent problem in earlier revisions of OCaml. It was tricky to write tail-recursive code for processing a file. In recent revisions you can use an exception clause of match to get a tail position for the recursive call:
let rec print_file channel =
match input_line channel with
| line -> print_endline line; print_file channel
| exception End_of_file -> ()
Recursion towers of Hanoi program in ADA.
So far I think I have most of it down, my problem is being in my solve function.
I think I have the algorithm fine, but I am not sure how to implement it into the function, all examples I see of using this are using the function inside itself such as:
Example
My errors are:
hanoi.adb:23:09: cannot use function "solve" in a procedure call
hanoi.adb:27:09: cannot use function "solve" in a procedure call
hanoi.adb:59:15: missing ")"
Here is my code so far.
with ada.text_io, ada.command_line;
use ada.text_io, ada.command_line;
procedure hanoi is
Argument_Error : EXCEPTION;
max_disks, min_disks : integer := 3;
moves : integer := 0;
verbose_bool : boolean;
function solve (N: in integer; from, to, using: in character) return integer is
begin
if N = 1 then
if verbose_bool = true then
put("Move disk " & integer'image(N) & " from " & character'image(from) & " to " & character'image(to));
end if;
else
solve(N - 1, 'A', 'B', 'C');
if verbose_bool = true then
put("Move disk " & integer'image(N) & " from " & character'image(from) & " to " & character'image(to));
end if;
solve(N - 1, 'B', 'C', 'A');
end if;
moves := (2 ** min_disks) - 1;
return moves;
end solve;
begin
while min_disks /= max_disks loop
IF Argument_Count > 1 THEN
if Argument_Count = 1 then
min_disks := integer'value("Argument(1)");
elsif Argument_Count = 2 then
min_disks := integer'value("Argument(1)");
max_disks := integer'value("Argument(2)");
elsif Argument_Count = 3 then
min_disks := integer'value("Argument(1)");
max_disks := integer'value("Argument(2)");
if argument(3) = "v" or argument(3) = "V" then
verbose_bool := true; -- if argument is V or v it is true
end if;
END IF;
END IF;
IF Argument_Count > 3 THEN
RAISE argument_error;
END IF;
if (max_disks > 0) then
solve (N: integer; from, to, using : character);
END IF;
min_disks := min_disks + 1;
end loop;
EXCEPTION
WHEN Name_Error =>
Put_Line("Please re-enter your arguments, check to see if you entered integers and characters. Max of 3 arguments.");
WHEN OTHERS =>
Put_Line("Please try to not break the program again, thank you.");
end hanoi;
Functions return values, procedures do not, and you've defined Solve as a function.
Ada requires that you do something with a function's returned value, which you're not doing here. (You can't ignore the returned result as is done in other programming languages.)
As the error message states, your syntax is that of making a procedure call, i.e. invoking a procedure, but you've supplied the name of a function.
If the value being returned from a function is meaningful, then act on it in accordance with its purpose. If it is not providing any meaningful functionality, eliminate it and define Solve as a procedure.
As an aside, you may want to re-factor your display code into a nested subprogram. In the outline below, procedure Print can access the parameters of procedure Solve.
procedure Solve (N: in Integer; From, To, Using: in Character) is
procedure Print is
begin
if Verbose then
...
end if;
end Print;
begin
if N = 1 then
Print;
else
Solve (N - 1, 'A', 'B', 'C');
Print;
Solve (N - 1, 'B', 'C', 'A');
end if;
end Solve;
In addition to Marc's comment about the call to Solve's not being a proper Ada function reference, the syntax you have is that of a specification and not that of a invocation of Solve. You had it right in Solve's body just not in the initial invocation:
if (max_disks > 0) then
solve (N: integer; from, to, using : character);
END IF;
Msg 245, Level 16, State 1, Line 89
Conversion failed when converting the varchar value 'There was an error creating the System.DirectoryServices assembly. ' to data type int.
This error is caused by the statement below:
begin try print ' - Preparing to create System.DirectoryServices assembly with UNSAFE_ACCESS permission'
create assembly [System.DirectoryServices] from 'c:\Windows\Microsoft.NET\Framework\v2.0.50727\System.DirectoryServices.dll'
with permission_set = unsafe
print ' - System.DirectoryServices assembly created'
end try
begin catch
print 'There was an error creating the System.DirectoryServices assembly. '+Error_number()+Error_Severity()
end catch
This is coming from your concatenation of number to string in the catch block. This is not allowed without casting as it tries to convert the string to number rather than vice versa and as your string literal is not numeric this attempt is doomed to fail!
You can use RAISERROR with severity 0 to print the message with the values substituted in or the alternative is to concatenate the string yourself using explicit casts.
begin catch
declare #num int = Error_number()
declare #sev int = Error_Severity()
raiserror('There was an error creating the System.DirectoryServices assembly. %d %d ',0,1, #num,#sev)
end catch
I have a very good DirectMySQL unit, which is ready to be used and i want it to be a TDataset descendant so i can use it with QuickReport, i just want MySQL Query with DirectMySQL which descendant from TDataset.
Everything was ok until i tried to access a big table with 10.000 rows and more. It was unstable, the error was unpredictable and not always shown but it likely happened after you played with other tables.
It happened in GetFieldData(Field: TField; Buffer: Pointer): boolean; which used to get the field value from MySQL rows.
Here's the code,
function TMySQLQuery.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
var
I, CT: Integer;
Row: TMySQL_Row;
TBuf: PChar;
FD: PMySQL_FieldDef;
begin
UpdateCursorPos; ------------> This code is after i got the error but no result
Resync([]); ------------> This code is after i got the error but no result
Result := false;
Row := oRecordset.CurrentRow;
I := Field.FieldNo-1;
FD := oRecordset.FieldDef(I);
if Not Assigned(FD) then
FD := oRecordset.FieldDef(I);
TBuf := PP(Row)[i];
Try
CT := MySQLWriteFieldData(fd.field_type, fd.length, fd.decimals, TBuf, PChar(Buffer));
Result := Buffer <> nil;
Finally
Row := nil; ------------> This code is after i got the error but no result
FD := nil; ------------> This code is after i got the error but no result
TBuf := nil; ------------> This code is after i got the error but no result
Buffer := nil; ------------> This code is after i got the error but no result
End;
end;
{
These codes below are to translate the data type
from MySQL Data type to a TDataset data type
and move mysql row (TBuf) to TDataset buffer to display.
And error always comes up from this function
when moving mysql row to buffer.
}
function TMySQLQuery.MySQLWriteFieldData(AType: byte;
ASize: Integer; ADec: cardinal; Source, Dest: PChar): Integer;
var
VI: Integer;
VF: Double;
VD: TDateTime;
begin
Result := MySQLDataSize(AType, ASize, ADec);
case AType of
FIELD_TYPE_TINY, FIELD_TYPE_SHORT, FIELD_TYPE_LONG, FIELD_TYPE_LONGLONG,
FIELD_TYPE_INT24:
begin
if Source <> '' then
VI := StrToInt(Source)
else
VI := 0;
Move(VI, Dest^, Result);
end;
FIELD_TYPE_DECIMAL, FIELD_TYPE_NEWDECIMAL:
begin
if source <> '' then
VF := internalStrToCurr(Source)
else
VF := 0;
Move(VF, Dest^, Result);
end;
FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
begin
if Source <> '' then
VF := InternalStrToFloat(Source)
else
VF := 0;
Move(VF, Dest^, Result);
end;
FIELD_TYPE_TIMESTAMP:
begin
if Source <> '' then
VD := InternalStrToTimeStamp(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_DATETIME:
begin
if Source <> '' then
VD := InternalStrToDateTime(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_DATE:
begin
if Source <> '' then
VD := InternalStrToDate(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_TIME:
begin
if Source <> '' then
VD := InternalStrToTime(Source)
else
VD := 0;
Move(VD, Dest^, Result);
end;
FIELD_TYPE_STRING, FIELD_TYPE_VAR_STRING,
FIELD_TYPE_ENUM, FIELD_TYPE_SET:
begin
if Source = nil then
Dest^ := #0
else
Move(Source^, Dest^, Result);
end;
Else
Result := 0;
Raise EMySQLError.Create( 'Write field data - Unknown type field' );
end;
end;
My guess for now is it's memory related problem.
I am stacked. Anyone could help?
I also need TDataset documentation which list availlable descendant function and how to use it, or how to descendant from TDataset. anyone have them? I am lack of this kind of doumentation.
GetFieldData cannot have UpdateCursorPos and Resync calls. Otherwise you may get unpredicatable errors.
FD := oRecordset.FieldDef(I) ... FD := oRecordset.FieldDef(I); - looks strange. Second assigment is not needed.
finally ... end with local variables reset is not needed.
I have no idea what returns MySQLDataSize. For example, MySQLDataSize may return size in Delphi data type representation units, or may return length of data returned by MySQL. But depending on that MySQLWriteFieldData may be correct or may be not.
I dont know how DirectMySQL works. If it uses raw TCP/IP to talk to MySQL, then the problem may be there. For example, it incorrectly handles a sequence of packets.
And finally - what are the errors you are getting ? What is your Delphi version ? What is your MySQL client and server versions ?
And so on ....
IOW, that will be really hard to say, what is wrong. To do so, I for example, will need to get all sources, sit at Delphi IDE debugger and analyze many details of what is going on - sorry, no time :)
It's solved now by adding #0 at the end of the line... Thanks so much to all who replied to my problem.
It is possible to pass 2d array to a function as a paramter ?
I initialized an array like this :
tab={}
for i=1, 10 do
tab[i]={}
for z=1, 10 do
tab[i][z]= 0
end
end
and i have function like this :
function foo(data)
...
x = data[i][z] -- here i got error
...
end
The gave the error message attempt to index field '?' (a nil value)
All variables are declared and initialized.
Your code should work if it is initialized properly.
For example, the below code sample will output 3:
function foo(data)
local i, z = 1, 2
print(data[i][z])
end
local tab={}
for i=1, 10 do
tab[i]={}
for z=1, 10 do
tab[i][z]= i + z
end
end
foo(tab)
Maybe you can share the rest of your code? The following runs with no error:
tab={}
for i=1, 10 do
tab[i]={}
for z=1, 10 do
tab[i][z]= 0
end
end
function foo(data)
print(data[3][2])
end
foo(tab)
The gave the error message attempt to index field '?' (a nil value)
I got such errors while changing metatable of some variable.