Lazarus

Programming => General => Topic started by: Roald Andresen on May 24, 2020, 09:39:54 pm

Title: Basic quistion about FreePascal
Post by: Roald Andresen on May 24, 2020, 09:39:54 pm
It's been a while since I did any Pascal programming - 1996, I think.  Sadly, there hasn't been any demand for it on the job market.  Now, retired, I get back to my favorite programming language, and I make elementary mistakes.  :o
My simple question is:
There are some standard functions in FreePascal, such as e.g. sin and cos.  I am working with a class for complex numbers and want to define a sin and a cos function for this class.  Since these functions are not defined within any unit (but in mathh.inc), the compiler protests because it cannot see the difference between standard sin/cos and my complex sin/cos functions (i.e. inside the implementation of the complex class, since complex numbers use standard sin/cos functions).  If sin/cos etc. had been in a unit, I could prefix with the unit name. 
My workaround has been to name my function sinus/cosine, but this makes the use of the class less elegant. 
Can this be solved any other way?
Title: Re: Basic quistion about FreePascal
Post by: Kays on May 24, 2020, 10:12:17 pm
The standard functions sin and cos are declared in the system unit (https://wiki.freepascal.org/System_unit). You can unambiguously refer to them via their fully-qualified identifiers, e. g. system.sin (https://www.freepascal.org/docs-html/rtl/system/sin.html).

You’re welcome.
Title: Re: Basic quistion about FreePascal
Post by: MarkMLl on May 24, 2020, 10:21:19 pm
The standard functions sin and cos are declared in the system unit (https://wiki.freepascal.org/System_unit). You can unambiguously refer to them via their fully-qualified identifiers, e. g. system.sin (https://www.freepascal.org/docs-html/rtl/system/sin.html).

You’re welcome.

Not what he's asking: how can an unqualified name be forced to refer to Sin() and Cos() that he's defined, rather than the System unit?

Roald: try defining a complex type as a record rather than a class, then having Sin() etc. functions taking complex as their parameter type.

Code: [Select]
type
  complex= record
...
                   end;

function Sin(c: complex): something;
...

Not tested. You can see I'm rusty at this, I can't remember what the return type should be :-)

MarkMLl
Title: Re: Basic quistion about FreePascal
Post by: marcov on May 24, 2020, 10:44:10 pm
Type ucomplex in your uses clauses. Then put your cursor on it, and press ctrl + enter
Title: Re: Basic quistion about FreePascal
Post by: howardpc on May 24, 2020, 10:44:52 pm
@Roald
Are you aware of the FPC UComplex unit which defines a complex record type, and provides csin() and ccos() routines?
Title: Re: Basic quistion about FreePascal
Post by: Roald Andresen on May 24, 2020, 11:10:32 pm
@Roald
Are you aware of the FPC UComplex unit which defines a complex record type, and provides csin() and ccos() routines?

No, I wasn't aware of that.  Really annoying - but still, thanks.  Anyhow, I am mainly doing this complex class as a self-refresh exercise.  Regard my example as simply that, an example of a general feature question.
Title: Re: Basic quistion about FreePascal
Post by: Roald Andresen on May 24, 2020, 11:17:45 pm
The standard functions sin and cos are declared in the system unit (https://wiki.freepascal.org/System_unit). You can unambiguously refer to them via their fully-qualified identifiers, e. g. system.sin (https://www.freepascal.org/docs-html/rtl/system/sin.html).

You’re welcome.
Yepp.  Just as I expected, a simple solution that I had forgotten.
Thanks.
Title: Re: Basic quistion about FreePascal
Post by: Roald Andresen on May 24, 2020, 11:19:54 pm
The standard functions sin and cos are declared in the system unit (https://wiki.freepascal.org/System_unit). You can unambiguously refer to them via their fully-qualified identifiers, e. g. system.sin (https://www.freepascal.org/docs-html/rtl/system/sin.html).

You’re welcome.

Not what he's asking: how can an unqualified name be forced to refer to Sin() and Cos() that he's defined, rather than the System unit?

Roald: try defining a complex type as a record rather than a class, then having Sin() etc. functions taking complex as their parameter type.

Code: [Select]
type
  complex= record
...
                   end;

function Sin(c: complex): something;
...

Not tested. You can see I'm rusty at this, I can't remember what the return type should be :-)

MarkMLl
Kay got it right.  Thank you anyway, I can see how my question can be misunderstood.
Title: Re: Basic quistion about FreePascal
Post by: glorfin on May 25, 2020, 03:24:47 pm
I think, if you define the type as record, you can further define functions with a keyword overload to force the compiler to look in other units.
This will be useful also for the users of your unit, because they will be able to use simultaneously functions with your complex and real parameters.
https://freepascal.org/docs-html/ref/refse93.html
Title: Re: Basic quistion about FreePascal
Post by: lucamar on May 25, 2020, 04:31:53 pm
I think, if you define the type as record, you can further define functions with a keyword overload to force the compiler to look in other units.

You can do that no matter how the type is declared; it's as simple as declaring/defining:
Code: Pascal  [Select][+][-]
  1. function sin(AComplex: TComplex): Sometype; overload;

In fact you could even do something silly like:
Code: Pascal  [Select][+][-]
  1. function sin(Value: String): TEndingPlace; overload;
  2. begin
  3.   if SinInCapitalTen(Value) then
  4.     Result := epHell
  5.   else
  6.     Result := epPurgatory;
  7. end;
:D
Title: Re: Basic quistion about FreePascal
Post by: marcov on May 25, 2020, 04:34:39 pm
(but it will only work if all others are also marked overload;)
Title: Re: Basic quistion about FreePascal
Post by: lucamar on May 25, 2020, 05:13:24 pm
(but it will only work if all others are also marked overload;)

Well, I tested with a simple "string parameter" overload of Sin() and it worked a'right, but then sin() is not really a "normal" function ...

Anyway, AFAICT the overload modifier serves (among other things) to tell the compiler to keep searching elsewhere if  there is not a declaration matching the call types in the current unit. Or as the Ref. Guide says it:
Quote
Now the compiler will continue searching in other units if it doesn't find a matching version of an overloaded function in one unit, and if the overload keyword is present.
Though, granted, it's not very clear where the modifier must be present, whether in the current unit's overloads or in all of them.
Title: Re: Basic quistion about FreePascal
Post by: marcov on May 25, 2020, 05:36:33 pm
(but it will only work if all others are also marked overload;)

Well, I tested with a simple "string parameter" overload of Sin() and it worked a'right, but then sin() is not really a "normal" function ...

Could you call both variants ? otherwise it is a simple matter of scope, not overloading.
Title: Re: Basic quistion about FreePascal
Post by: lucamar on May 25, 2020, 08:50:53 pm
Could you call both variants ? otherwise it is a simple matter of scope, not overloading.

Of course. Otherwise it would have been a meaningless test :)

The overload accepted a string and returned an integer so this worked:
Code: Pascal  [Select][+][-]
  1. ShowMessage('Overload: ' + IntToStr(Sin('Woah, it works!'))
  2.           + LineEnding
  3.           + 'Normal: ' + FloatToStr(Sin(0.5))
  4.           );
Title: Re: Basic quistion about FreePascal
Post by: glorfin on May 26, 2020, 05:32:14 pm
(but it will only work if all others are also marked overload;)
If only one unit has the "overload" directive, sequence in "uses" section is important. Compiler starts search from units which were mentioned last and if it finds a header with mismatching parameters and "overload", it continues a search. Otherwise not.
Test: I created these 2 units:
Code: Pascal  [Select][+][-]
  1. unit noOver;
  2. interface
  3. procedure MyProc(V:double);
  4. implementation
  5. procedure MyProc(V:double);
  6. begin
  7.   writeln('This is procedure from "noOver" unit which does not have "overload" directive');
  8. end;
  9. end.
  10.  
and
Code: Pascal  [Select][+][-]
  1. unit overl;
  2. interface
  3. procedure MyProc(MyParam:string); overload;
  4. implementation
  5. procedure MyProc(MyParam:string); overload;
  6. begin
  7.   writeln('This is procedure from "Overl" unit which has the "overload" directive');
  8. end;
  9. end.
  10.  
Now, the program:
Code: Pascal  [Select][+][-]
  1. program overloaders;
  2. uses noOver, overl;
  3. begin
  4.   MyProc(2.0);
  5.   MyProc('This is a string');
  6.   readln;
  7. end.
  8.  
works fine, while
Code: Pascal  [Select][+][-]
  1. program overloaders;
  2. uses overl, noOver;
  3. begin
  4.   MyProc(2.0);
  5.   MyProc('This is a string');
  6.   readln;
  7. end.
  8.  
leads to:
overloaders.lpr(6,28) Error: Incompatible type for arg no. 1: Got "Constant String", expected "Double".

Obviously, "System" is searched last, so, one can overload everything from it.
Title: Re: Basic quistion about FreePascal
Post by: lucamar on May 26, 2020, 06:09:07 pm
(but it will only work if all others are also marked overload;)
If only one unit has the "overload" directive, sequence in "uses" section is important. Compiler starts search from units which were mentioned last and if it finds a header with mismatching parameters and "overload", it continues a search. Otherwise not.

Indeed, as soon as it finds an overloaded version without the "overload" modifier it stops searching for more and considers that the "last" version, which can be easily ascertained with a simple test with at least three units, an overload per unit and only one of them having the overload modifier:

Code: Pascal  [Select][+][-]
  1. { In the first unit ...}
  2. function DoSomething(Value: Double): String;
  3. begin
  4.   Result := 'As Double: ' + FloatToStr(Value);
  5. end;
  6.  
  7. { In the second unit ...}
  8. function DoSomething(Value: Integer): String;
  9. begin
  10.   Result := 'As Integer: ' + IntToStr(Value);
  11. end;
  12.  
  13. { In the third one ...}
  14. function DoSomething(Value: String): String; overload;
  15. begin
  16.   Result := 'As String: ' + AnsiProperCase(Value, StdWordDelims);
  17. end;

For example, writing:
Code: [Select]
uses first, second, third; you can't call DoSomething(367.25); writing
Code: [Select]
uses second, first, third; and calling DoSomething(321) will convert the integer and use the "Double" overload.

So Marco was quite right and all the overloads (except the very first) should be declared with the overload modifier, as the docs (if somewhat cryptically) say. ;)
TinyPortal © 2005-2018