In my program I have a need to get percent often in code. For now i have this function to solve it
function percent(whole, part: double):double;
begin
percent:= whole * part / 100;
end;
I was wondering is there any way I could make new operator so I can write only something like: a:=100%20, and get wanted result. It would also should be able to be used as: c:=b/a; or : c:=c/a;
You can define operators in pascal, but only on record type. It is called operator overloading and you can read up here. What you do is define your own record type data, and then overload standard operators such as = < > % etc to do what you want them to do. Here is a simple example:
Interface
Type
TMyFloatType = record
value: Extended;
class operator Implicit(n: Extended): TMyFloatType;
class operator Explicit(n: Extended): TMyFloatType;
class operator Equal(a, b: TMyFloatType): Boolean;
class operator GreaterThan(a, b: TMyFloatType): Boolean;
end;
Implementation
class operator TMyFloatType.Implicit(n: Extended): TMyFloatType;
begin
result.value := n;
end;
class operator TMyFloatType.Explicit(n: Extended): TMyFloatType;
begin
result.value := n;
end;
class operator TMyFloatType.Equal(a, b: TMyFloatType): Boolean;
begin
result := (a.value = b.value);
end;
class operator TMyFloatType.GreaterThan(a, b: TMyFloatType): Boolean;
begin
result := (a.value > b.value);
end;
You can then use that like regular variables:
procedure Test;
var
a, b: TMyFloatType;
Begin
// first assign some values to a and b
a := 3.14;
b := 2.7;
if a > b then
Begin
// Do something
End;
End;
Operators that you can overload do include math operators too, like + - / * mod div etc.
Now, having said that, I do believe it wouldn't be very convenient to actually implement this to avoid a simple function, but hey, your choice.
Point here is that you can overload an operator to do your bidding. I believe to do a calculation like percentage := a % 20; you need to overload the Modulus operator.
There's no way to do this. You can only use the function
I would just use a function. By the way, your function
function percent(whole, part: double):double;
begin
percent:= whole * part / 100;
end;
is incorrect. It should be
percent := 100.0 * part / whole;
Related
I really would like to see how it's done, the compiler keeps assuming I have integer indexes and returns errors.
How to pass the following array:
countc: Array['a'..'z'] of Integer;
to a function?
In traditional Pascal, before you can pass something like your array to a function, you have to declare a type that your array is an instance of, like this
type
TSimpleArray = Array['A'..'Z', '0'..'9'] of integer;
var
ASimpleArray : TSimpleArray;
In other words, you can't specify the array's bounds in the definition of the function/procedure.
Once you've defined your array type like the above, you can declare a function (or procedure) that has a parameter of the defined type, like this:
function ArrayFunction(SimpleArray : TSimpleArray) : Integer;
var
C1,
C2 : Char;
begin
ArrayFunction := 0;
for C1 := 'A' to 'Z' do
for C2 := '0' to '9' do
ArrayFunction := ArrayFunction + SimpleArray[C1, C2];
end;
which obviously totals the contents of the array.
More modern Pascals like Delphi and FPC's ObjectPascals also support other ways of declaring an array-type parameter, but they have to be zero-based (which precludes the use of char indexes). Delphi and FPC also support the use of `Result' as an alias for the function name, as in
function ArrayFunction(SimpleArray : TSimpleArray) : Integer;
[...]
begin
Result := 0;
which saves time and effort if you rename a function or copy/paste it to define another function.
I'm kinda a Delphi-newbie and I don't get how the Sort method of a TList of Records is called in order to sort the records by ascending integer value.
I have a record like the following:
type
TMyRecord = record
str1: string;
str2: string;
intVal: integer;
end;
And a generic list of such records:
TListMyRecord = TList<TMyRecord>;
Have tried to find a code-example in the help files and found this one:
MyList.Sort(#CompareNames);
Which I can't use, since it uses classes. So I tried to write my own compare function with a little different parameters:
function CompareIntVal(i1, i2: TMyRecord): Integer;
begin
Result := i1.intVal - i2.intVal;
end;
But the compiler always throws a 'not enough parameters' - error when I call it with open.Sort(CompareIntVal);, which seems obvious; so I tried to stay closer to the help file:
function SortKB(Item1, Item2: Pointer): Integer;
begin
Result:=PMyRecord(Item1)^.intVal - PMyRecord(Item2)^.intVal;
end;
with PMyRecord as PMyRecord = ^TMyRecord;
I have tried different ways of calling a function, always getting some error...
The Sort overload you should be using is this one:
procedure Sort(const AComparer: IComparer<TMyRecord>);
Now, you can create an IComparer<TMyRecord> by calling TComparer<TMyRecord>.Construct. Like this:
var
Comparison: TComparison<TMyRecord>;
....
Comparison :=
function(const Left, Right: TMyRecord): Integer
begin
Result := Left.intVal-Right.intVal;
end;
List.Sort(TComparer<TMyRecord>.Construct(Comparison));
I've written the Comparison function as an anonymous method, but you could also use a plain old style non-OOP function, or a method of an object.
One potential problem with your comparison function is that you may suffer from integer overflow. So you could instead use the default integer comparer.
Comparison :=
function(const Left, Right: TMyRecord): Integer
begin
Result := TComparer<Integer>.Default.Compare(Left.intVal, Right.intVal);
end;
It might be expensive to call TComparer<Integer>.Default repeatedly so you could store it away in a global variable:
var
IntegerComparer: IComparer<Integer>;
....
initialization
IntegerComparer := TComparer<Integer>.Default;
Another option to consider is to pass in the comparer when you create the list. If you only ever sort the list using this ordering then that's more convenient.
List := TList<TMyRecord>.Create(TComparer<TMyRecord>.Construct(Comparison));
And then you can sort the list with
List.Sort;
The concise answer:
uses
.. System.Generics.Defaults // Contains TComparer
myList.Sort(
TComparer<TMyRecord>.Construct(
function(const Left, Right: TMyRecord): Integer
begin
Result := Left.intVal - Right.intVal;
end
)
);
I want to share my solution (based on the input I have gathered here).
It's a standard setup. A filedata class that holds data of a single file in a generic TObjectList. The list has the two private attributes fCurrentSortedColumn and fCurrentSortAscending to control the sort order. The AsString-method is the path and filename combined.
function TFileList.SortByColumn(aColumn: TSortByColums): boolean;
var
Comparison: TComparison<TFileData>;
begin
result := false;
Comparison := nil;
case aColumn of
sbcUnsorted : ;
sbcPathAndName: begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
sbcSize : begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<int64>.Default.Compare(Left.Size,Right.Size);
if Result = 0 then
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
sbcDate : begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<TDateTime>.Default.Compare(Left.Date,Right.Date);
if Result = 0 then
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
sbcState : begin
Comparison := function(const Left, Right: TFileData): integer
begin
Result := TComparer<TFileDataTestResults>.Default.Compare(Left.FileDataResult,Right.FileDataResult);
if Result = 0 then
Result := TComparer<string>.Default.Compare(Left.AsString,Right.AsString);
end;
end;
end;
if assigned(Comparison) then
begin
Sort(TComparer<TFileData>.Construct(Comparison));
// Control the sort order
if fCurrentSortedColumn = aColumn then
fCurrentSortAscending := not fCurrentSortAscending
else begin
fCurrentSortedColumn := aColumn;
fCurrentSortAscending := true;
end;
if not fCurrentSortAscending then
Reverse;
result := true;
end;
end;
I found a much simpler modified sort function to alphabetize a TList of records or nonstandard list of items.
Example
PList = ^TContact;
TContact = record //Record for database of user contact records
firstname1 : string[20];
lastname1 : string[20];
phonemobile : Integer; //Fields in the database for contact info
phonehome : Integer;
street1 : string;
street2 : string;
type
TListSortCompare = function (Item1,
Item2: TContact): Integer;
var
Form1: TForm1;
Contact : PList; //declare record database for contacts
arecord : TContact;
Contacts : TList; //List for the Array of Contacts
function CompareNames(i1, i2: TContact): Integer;
begin
Result := CompareText(i1.lastname1, i2.lastname1) ;
end;
and the function to call to sort your list
Contacts.Sort(#CompareNames);
I was trying to use same printing procedure for two types of arrays(1st arry length was 10, 2nd array length was 15).
I could not find any solution over internet. Did any one have any solution for this problem.
this is the Two arrays
program pp1;
const
m=10;
n=15;
type
matrix1=array[1..m] of integer;
matrix2=array[1..n] of integer;
var
m1:matrix1;
m2:matrix2;
this is the method which it tried. in method 'x' mens the length of the array.
procedure writeMatrix(var data: array of integer ;x:integer);
var
j:integer;
begin
for j:=1 to x do
begin
write(data[j]:3);
end;
end;
my main method
begin
writeMatrix(m1,10);
writeMatrix(m2,10);
end.
How can i use the same this writeMatrix method to print both of the arrays.. Is there any stranded way to do it.
As I said in my comment before, your implementation is fine, but you have to put something in your matrix before printing it, or you will get a bunch of zeroes in the screen (in the best).
Try this:
program pp1;
const
m=10;
n=15;
type
matrix1=array[1..m] of integer;
matrix2=array[1..n] of integer;
var
m1:matrix1;
m2:matrix2;
procedure fillMatrix(var data:array of integer; x:integer);
var
j:integer;
begin
for j:= 1 to x do begin
data[j]:=j;
end;
end;
procedure writeMatrix(var data: array of integer; x:integer);
var
j:integer;
begin
for j:=1 to x do
begin
write(data[j]:3);
end;
end;
begin
fillMatrix(m1,10);
fillMatrix(m2,10);
writeMatrix(m1,10);
writeMatrix(m2,10);
readln;
readln;
end.
Hint: consider avoid using global variables, m1 and m2 in this case should be declared in the main program.
How can i use the same this writeMatrix method to print both of the arrays.. Is there any stranded way to do it.
Yes, there is a standard way to this. It is called conformant-array parameters. It is standardized in (level 1) of the ISO standard 7185 (Standard “Unextended” Pascal). It looks like this:
procedure print(protected matrix: array[
columnMinimum..columnMaximum: integer;
rowMinimum..rowMaximum: integer
] of integer);
const
totalWidth = 6;
var
x: type of columnMinimum;
y: type of rowMinimum;
begin
for y := rowMinimum to rowMaximum do
begin
for x := columnMinimum to columnMaximum do
begin
write(matrix[x, y]:totalWidth);
end;
writeLn;
end;
end;
It’s as if there were additional const values, but they are dynamic depending on the passed matrix. This code furthermore uses type inquiries (type of …) and the protected modifier, both defined in ISO 10206 (Extended Pascal) which builds on top of ISO 7185. In EP you could and would also consider schemata to pass such data as parameters.
in our last class we defined a couple of functions and procedures in our unit file.
procedure WriteNap(const elo: string; const n: TNap; const uto: string);
begin
Write(elo, Nap2Str(n), uto);
end;
function PredNap(const n: TNap): TNap;
begin
case n of
hetfo: PredNap := vasarnap;
NemNap: PredNap := n;
else
PredNap := Pred(n)
end;
end;
function SuccNap(const n: TNap): TNap;
begin
case n of
NemNap: SuccNap := n;
else
SuccNap := Succ(n)
end;
end;
I have to get rid of the word 'Nap' so that i can just use Pred, Write, Succ in the main program instead of PredNap etc... i tried to create another unit file which uses this unit and contains functions like Succ Pred... didnt really work out..
thanks in advance :)
Declare in somewhere in your file:
var Pred = Function (Const n:TNap):TNap;
And before you do anything in the body of your program, write:
Pred := #PredNap;
What this code does is, it creates a new function pointer with the same signature as your PredNap() and then assign the address of PredNap() to this pointer. So, whenever you call Pred() the actual function that gets called is PredNap(). Hope this helps.
For a function to return a value in Pascal the assignment FunctionName := SomeVal; is used. I assume it doesn't stop the function execution in that exact place as return in C does. Is there something similar to C return in Pascal? (I'm using FreePascal compiler)
You can use the Exit procedure.
function Foo (Value : integer) : Integer;
begin
Exit(Value*2);
DoSomethingElse(); // This will never execute
end;
The return code of the end of every program is stored in the EAX register. So you can use Assembly inline on Pascal to return wherever you want to end the program running using!
asm
mov eax,%ERROLEVEL%
end;
I think you can use either the function name itself, "result", or Exit(), but I've only used the result identifier, so don't know if the others will work for you:
function Foo(a, b: Integer): Integer;
begin
result := a + b;
end;
Hope that helps ^^
In canonical pascal (without keyword Exit) you can emulate return via goto:
function Foo (Value : integer) : boolean;
label return;
begin
if Value < 0 then
begin
Foo := false;
goto return;
end;
Calc();
Foo := true;
return:
end;