I'm attempting to create a class in Pascal, I am a bit confused about the declaration and syntax. the main thing is an error I'm getting "Forward declaration not solved Tetromino.Rotate(LongInt)", I read that I need to declare my procedure in the implementation section but I'm not sure where I'm meant to be putting that. also if you notice anything else wrong with my class declaration please tell me.
program Tetris;
{$MODE OBJFPC}
uses crt, sysutils;
type
Tetromino = class
private
TempFace : array [0..15] of char;
public
Face : array[0..15] of char;
//constructor create(); (idk what this is but read somewhere that you need it)
procedure Rotate(rotation : integer);
end;
var
a,b,c,d,e,f,g : tetromino;
begin
ReadKey();
end.
In a program module there is no need for division into interface and implementation. Therefore the error description (to implement the procedure in the implementation section) is a little bit misleading. Still, it indicates that the implementation of the Rotate() procedure is missing.
So, the error is that you have declared a procedure in the Tetromino class, but the implementation of that procedure is missing. You need to implement it somewhere between the class declaration and the begin .. end block of the program.
In a unit module, which has named sections: interface and implementation, you declare classes in the interface section (if those classes are to be accessible from other modules) and implement them in the implementation section.
In the following I outline what you need to do in your program, including the constructor for Tetromino
program Tetris;
{$MODE OBJFPC}
uses crt, sysutils;
type
Tetromino = class
private
TempFace : array [0..15] of char;
public
Face : array[0..15] of char;
constructor create(); (idk what this is but read somewhere that you need it)
procedure Rotate(rotation : integer);
end;
var
a,b,c,d,e,f,g : tetromino;
constructor Tetromino.create;
begin
// constructor (automatically) aquires a block of memory
// to hold members of the class
// to do: initialize member fields of the instance
end;
procedure Tetromino.Rotate(rotation: Integer);
begin
// implementation of the Rotate() method
end;
begin
ReadKey();
end.
Related
I'd like to use a method of a class without assigning its creation to a variable. For example:
type
TMyObject = class
public
procedure DoSomething;
end;
implementation
procedure MyObjDoesSomething;
begin
TMyObject.Create.DoSomething;
end;
{ TMyObject }
procedure TMyObject.DoSomething;
begin
// ...
end;
As you can see, in MyObjDoesSomething I didn't assign TMyObject.Create to a TMyObject variable.
Does this have some kind of impact on memory usage, or even something else I did't think of?
Yes, there is a big impact: A nice memory leak!
You call the constructor of an object but never free the created object. Each time you'll call your MyObjDoesSomething, you'll leak an object instance.
To solve that problem, you could make a class method of DoSomething like this:
type
TMyObject = class
public
class procedure DoSomething;
end;
Then you can call DoSomething without creating an object like this:
procedure MyObjDoesSomething;
begin
TMyObject.DoSomething;
end;
Being a class method, DoSomething implementation cannot use object instance variables (fields).
If you Create an object to allocate memory for it, you must call Free() on the object when you are done using it to release that memory, otherwise the memory is leaked, which will impact memory over time if you create these objects multiple times.
If you don't want to use an explicit variable to refer to the object (why?), you can use a with block, eg:
procedure MyObjDoesSomething;
begin
with TMyObject.Create do
try
DoSomething;
finally
Free;
end;
end;
Another option is to make the class implement an interface, and then you can let the compiler's reference counting of interfaces handle freeing the object for you. This has a little bit more overhead than above, but you don't have to worry as much about handling the memory manually, eg:
type
IMyObject = interface
['{896FF4FA-A974-4A8B-9EA5-414C138635E4}']
procedure DoSomething;
end;
TMyObject = class(TInterfacedObject, IMyObject)
public
procedure DoSomething;
end;
implementation
procedure MyObjDoesSomething;
begin
(TMyObject.Create as IMyObject).DoSomething;
end;
{ TMyObject }
procedure TMyObject.DoSomething;
begin
// ...
end;
But really, just use a variable instead. It costs you nothing to use:
procedure MyObjDoesSomething;
var
Obj;
begin
Obj := TMyObject.Create;
try
Obj.DoSomething;
finally
Obj.Free;
end;
end;
I have a Form. When the user clicks the TESTBUTON an array is generated (here with a loop) and an array is filled. (that works).
Now the user will be able to change some parameters an hit the button again.
Than I want to clear / free / destroy the old array an create it new.
I found a lot of examlpes for that but they not work (because I do not know where exatly to place the different procedures).
So I made this samplescript with all the sections.
Can someone move my procedures to the rigth place or send me an example that shows the correct implementation.
unit frmmywindow;
interface
uses
type
TArrayA = record
Field1:integer;
Field2:integer;
Field3:integer;
Field4:integer;
String5:string;
//other fields, strings, integers..
end;
private
{ private declarations }
public
{ public declarations }
destructor Destroy; override;
end;
var
var ArrayA : array of TarrayA;
implementation
destructor TArrayA.Destroy;
begin
ArrayA.Free;
inherited;
end;
procedure TArrayA.Free;
begin
if Assigned(self) then Destroy;
end;
procedure TForm1.btnTest(Sender: TObject);
var
x: integer;
reccount: integer;
begin
ArrayA.free:
ArrayA.create;
reccount := 1000;
for x := 1 to reccount do
begin
setLength(ArrayA,x+1);
ArrayA[x].field1 := 2000 - x;
ArrayA[x].field2 := x;
ArrayA[x].field3 := x;
ArrayA[x].field4 := x;
ArrayA[x].string5 := 'str' + inttostr(x);
end;
end;
Your code has a number of issues.
The main issue is that TArrayA is a record (normally I would link to the DocWiki documentation for structured types, but it seems to be down right now). Records are not classes, they don't have a destructor and you should not call Free on them. Records are so called value types. They don't even have a proper constructor, even if the syntax suggests they do. Record "constructors" are mere initializers.
Another issue is that you should never code Free yourself, not even for classes. Free is inherited from the root for all class instances, TObject. For classes, if you want to give it a destructor, override the inherited destructor:
destructor Destroy; override;
So the answer is: you don't use nor define them at all, for records.
How you should declare, define and use them for classes is described in the documentation.
As I already commented, you should get better acquainted with the language. I suggest you read the Delphi or Object Pascal Language Guide (name differs, depending on version), which is part of the documentation that is installed with Delphi.
Why doesn't this code result in a compiler error? I would have expected error for example 'ambiguous call to "CallMe"'. Is this a bug in the compiler or in the language? This can worked around by using the unit name and a dot in front of the function call but this not shield user code and library code against name collisions. You think that your code did something but it did something else and that's bad.
uses
Unit2, Unit3;
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(CallMe(5)));
end;
unit Unit2;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CallMe(A: Integer) : Integer;
implementation
function CallMe(A: Integer) : Integer;
begin
Result := A * 2;
end;
end.
unit Unit3;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
function CallMe(A: Integer) : Integer;
implementation
function CallMe(A: Integer) : Integer;
begin
Result := A * -1;
end;
end.
From documentation:
If two units declare a variable, constant, type, procedure, or function with the same name, the compiler uses the one from the unit listed last in the uses clause. (To access the identifier from the other unit, you would have to add a qualifier: UnitName.Identifier.)
As said it is by design, the compiler loads symbols from units using a stack based approach, and parses through the stack from last loaded to first loaded to search for a symbol. Preprocessor state is directly merged into the global state though.
Cross unit overloading is an exception though. If you mark both functions with overload; directive, you get an error (bla was the name of the function in the test)
[dcc32 Error] test.dpr: E2251 Ambiguous overloaded call to 'bla'
Unit1.pas(8): Related method: procedure bla;
Unit2.pas(8): Related method: procedure bla;
if you have two different signatures, it will select the best matching one.
cross overloading is a newer feature, but I don't remember exactly when. My guess is D2006.
Say I have two files, characters.pas and ogre.pas. An ogre is a character, but I'm trying to separate the two files for cleanliness sake. In characters.pas I have
unit Characters;
{$mode objfpc}{$H+}
interface
type
TCharacter = class(TOBject)
private
// ...
public
// ...
published
// ...
end;
implementation
// Method bodies
end.
In ogre.pas I have
unit Ogre;
{$mode objfpc}{$H+}
interface
type
TOgre = class(TCharacter)
public
constructor create; override;
end;
implementation
constructor TOgre.create();
begin
// Banana banana banana
end;
end.
Adding a uses block anywhere in either of the .pas files throws an error, which leads me to believe that all classes that rely on inheritance must be in the same file as their parents. Am I missing something?
Yes you miss something: the use section. You have to declare that unit Ogre uses unit Characters:
unit Ogre;
{$mode objfpc}{$H+}
interface
uses
Characters;
type
TOgre = class(TCharacter)
public
constructor create; override;
end;
implementation
constructor TOgre.create();
begin
// Banana banana banana
end;
end.
read more:
unit example #FPC
the use of a second form #FPC wiki
Also note that if you want some fields to be visible from a TCharacter to a TOgre but still not accessible from the main program then you'll have to set their visibility to protected
Im relatively new to Pascal and, though i have a fair understanding of the language, there's still some stuff i cant figure out how to implement. I've ran into this problem and, after trying for like hours on my own and looking for similar cases on the internet, i have not found anything. I hope this question is a fair one because, honestly, i dont know how to figure this out.
Here's the thing.
I have an application which dynamically creates TextBoxes (TextEdits in this case) and adds them to a panel for displaying. Thing is, i need to execute some procedures on the newly created elements. I added a new procedure in my app (this is for explaining purposes only):
procedure Demo_Procedure(i: integer, a: String);
Then i proceeded to "develop" my procedure underneath the "implementation" part of the Form.
procedure Demo_Procedure(i: integer, a: String);
begin
ShowMessage(a, ' ' ,i);
end;
Now, for my dynamically created elements im trying to set the "OnKeyDow" event to run my new procedure (this is what i dont A- know if its possible to do or B- how to do it)
NewlyButton.OnClick:= Demo_Procedure(5, 'Hi');
Im getting different errors depending on how i call up my procedure. For example:
If i do it like this: Demo_Procedures(5, 'Hi'), it says:
Error: Incompatible types: got "untyped" expected "procedure variable type of procedure(TObject,var Word,TShiftState) of object;Register>"
Now, researching around i found out that some people that put an '#' before calling the method, the only difference is that this time instead of saying "untyped" it says that it got "procedure variable type of procedure(AnsiString,LongInt) of object" and that it was expecting the same as before (procedure(TObject,var> Word,Tshift...etc)
Can anyone help me out here? I really am lost so any help would be greatly appreciated. Thanks in advance :)
There are errors in your code:
procedure Demo_Procedure(i: integer, a: String); // Wrong
procedure Demo_Procedure(i: integer; a: String); // Right, use semicolon as parameters delimiter
ShowMessage(a, ' ' ,i); // Wrong, ShowMessage takes only one string parameter
ShowMessage(Format('%s %d', [a, i])); // Right, %s means string value and %d means decimal value, see help about Format function
Events is a procedural variables so they have its own types. For example, OnKeyDown event have a type
TKeyEvent = procedure(Sender: TObject; var Key: Word; Shift: TShiftState) of Object;
where of Object means that your event handler must be a class method.
So, you can not assign to the event any procedure but only class method with parameters provided in the type declaration.
Here is the simple code:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
private
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
e: TEdit;
begin
e := TEdit.Create(Self); // Create new TEdit control
e.Parent := Self; // Place control onto the form
e.Left := 10; // Set control coordinates
e.Top := 10;
e.OnKeyDown := #EditKeyDown; // Assign event handler
end;
procedure TForm1.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
ShowMessage(Format('Key code is %d', [Key]));
end;
end.