Lazarus

Programming => General => Topic started by: MarkMLl on May 31, 2022, 12:42:16 pm

Title: Separating definition and implementation parts
Post by: MarkMLl on May 31, 2022, 12:42:16 pm
I would prefer not to get into an argument over this: I am not trying to enforce a particular point of view or request that anything be changed, but am asking for technical information.

The Object Pascal language as implemented by FPC and (I believe) Delphi puts both the definition and the implementation and the implementation of a unit in the same file.

Various jurisdictions are slowly sorting out their handling of software copyright and licensing, and appear to be making the common-sense distinction that an interface is a statement of fact (hence might not be copyrightable) while an implementation includes the detailed description of an algorithm or "method" which can definitely be copyrighted and possibly patented.

There is a long tradition of a copyright or license applying to the totality of a published work. I don't think there is a tested tradition of different sections or chapters of a published work being covered by different legal protection.

I am concerned that a copyright message in a source file might be jeopardised if the file is examined and a significant portion of it is discovered to be a statement of fact, hence uncopyrightable, hence there is no legitimate owner to enforce a license.

An obvious example of this is C header files, which typically contain a factual description of an API but might also contain macros which are neither descriptive nor obvious since they compute (provide a method for) bit manipulation where the bit significance is an internal implementation detail:

Code: C  [Select][+][-]
  1. struct hidraw_devinfo {
  2.         __u32 bustype;
  3.         __s16 vendor;
  4.         __s16 product;
  5. };
  6.  
  7. /* ioctl interface */
  8. #define HIDIOCGRDESCSIZE        _IOR('H', 0x01, int)
  9. #define HIDIOCGRDESC            _IOR('H', 0x02, struct hidraw_report_descriptor)
  10. #define HIDIOCGRAWINFO          _IOR('H', 0x03, struct hidraw_devinfo)
  11. #define HIDIOCGRAWNAME(len)     _IOC(_IOC_READ, 'H', 0x04, len)
  12. #define HIDIOCGRAWPHYS(len)     _IOC(_IOC_READ, 'H', 0x05, len)
  13. /* The first byte of SFEATURE and GFEATURE is the report number */
  14. #define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
  15. #define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
  16.  
  17. #define HIDRAW_FIRST_MINOR 0
  18. #define HIDRAW_MAX_DEVICES 64
  19.  

In the distant past, I've borrowed an idea from the old TopSpeed Pascal compiler and put interface specifications into .itf files which I've then included at the top of the corresponding implementation unit.

What are the technical implications of doing this, from the POV of FPC and Lazarus? Will it reduce FPC's compilation efficiency (to an extent greater than implied by the increased number of files) or invariably result in a layout where Lazarus has debugging issues?

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: SymbolicFrank on May 31, 2022, 01:15:30 pm
I cannot remember where, but some RTTI files include the same declarations for many different types. That's a short .inc file (~10 lines) that's included many times in the same unit. I wouldn't bother about details like that and just split it up exactly how you want it.

For compilation efficiency, an SSD is the main improvement. Next is probably the amount of cores and then RAM. Everything else is pretty much irrelevant, I think.
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on May 31, 2022, 01:19:26 pm
What are the technical implications of doing this, from the POV of FPC and Lazarus? Will it reduce FPC's compilation efficiency (to an extent greater than implied by the increased number of files) or invariably result in a layout where Lazarus has debugging issues?

There might be problems with the compiler detecting whether a unit needs to be recompiled, because if I remember correctly it only checks the timestamp of the unit file itself against that of the PPU and does not check any of the referenced include files (or include files that are included by include files).

I cannot remember where, but some RTTI files include the same declarations for many different types. That's a short .inc file (~10 lines) that's included many times in the same unit. I wouldn't bother about details like that and just split it up exactly how you want it.

The RTL is however prebuilt from the PoV of the user.
Title: Re: Separating definition and implementation parts
Post by: Martin_fr on May 31, 2022, 01:19:41 pm
Just some ideas that came to my mind while reading your post.

1)
Afaik, if you put some "source" into an include file and use {$I...} then the compiler will not see if content of the include file is modified (as it compares the date of the ppu and the pas/pp file.
So you may get errors when re-compiling.

2)
In some sense the "definition" (i.e. content of the "interface" section) is repeated in the implementation section. Each function/method... starts with the same header....
(I am aware that not all is function headers, and not all may be repeated / then again, non repeated definitions might be easy to move to a diff unit.. / or not / not the point of the below anyway)

That probably means "definition" needs to be more precisely. I.e. maybe "the public interface" ?

Then a layer might need to clarify, if any repeat of such info will lead into the same potential issue.
Or if a repeat is then just using the already otherwise licensed information, and usage of info that has a license of it's own, is then not affected by the license of the file in which it is repeated?

Depending upon which, the "definition" could be in a separate file:
- as documentation, with/without the code snippets
- as abstract or "type foo = interface" source code.
In either case, the repeat of those headers (in the actual unit that also will have the implementation) is then no different to the repeat of the headers between "interface" and "implementation" section, or is it?


I hope, the 2nd part will not start any discussions. Unless a person with legal background wants to opine, there should be little to add. (Well, if someone has info where such an knowledge based information is to be had, a link might be added)

It's just a sort of rhetorical question, that needs no answer. It is well understood that answers would cover the entire range from "nonsense" to "interesting") with all kind of potentially uninformed reasons given.
Title: Re: Separating definition and implementation parts
Post by: marcov on May 31, 2022, 01:21:46 pm
What are the technical implications of doing this, from the POV of FPC and Lazarus? Will it reduce FPC's compilation efficiency (to an extent greater than implied by the increased number of files) or invariably result in a layout where Lazarus has debugging issues?

The number of files read rises, and the file searching also becomes more complicated. (multiple extensions). I think both are manageable, but while file reading performance on spinning rust will suffer a bit of course (more files is more chance that a seek is needed), it might not matter that much on a SSD.

For file enumeration, there afaik are already search caches (to avoid to frequent enumerating files in search directories), so file searching just requires extending that.

Probably on e will need some extra crcs and timestamps  (what if def is not changed, but implementation isn't, that case doesn't exist now?)

However the biggest problem is that the unit handling and the automated recompiling isn't the easiest part of the compiler. Import cycles, cross-unit inline, generics, many things complicate it. The usual academic compiler with a clean dialect vs a production compiler with a established dialect and feature set.

I don't really see the copyright being that important, the few big corporates that fight out their legal  wars (like Oracle-Google over Java) will have complete departments on it, and can handle specifying separate clauses for interface and implementation even in one file.

So why bother?
Title: Re: Separating definition and implementation parts
Post by: SymbolicFrank on May 31, 2022, 01:31:18 pm
Yes, I agree. If it comes to a dispute, it only matters who has the most money. Being in the right is not all that important.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on May 31, 2022, 02:14:08 pm
Thanks everybody for the thoughts so far. Sven and others commented on the situation where a changed include (i.e. interface) file doesn't force recompilation of the implementation: yes, I think that's a showstopper. I know that I'm not the only one whose seen problems in this overall area: a directive change which doesn't force recompilation... I've just not seen it in an easily-reproducible form.

The number of files read rises, and the file searching also becomes more complicated. (multiple extensions). I think both are manageable, but while file reading performance on spinning rust will suffer a bit of course (more files is more chance that a seek is needed), it might not matter that much on a SSD.

...on the other hand, I did emphasise that I wasn't asking for anything to be changed so I don't think that extensions and search paths really come into it.

Quote
For file enumeration, there afaik are already search caches (to avoid to frequent enumerating files in search directories), so file searching just requires extending that.

Probably on e will need some extra crcs and timestamps  (what if def is not changed, but implementation isn't, that case doesn't exist now?)

However the biggest problem is that the unit handling and the automated recompiling isn't the easiest part of the compiler. Import cycles, cross-unit inline, generics, many things complicate it. The usual academic compiler with a clean dialect vs a production compiler with a established dialect and feature set.

It would be nice if the include-rebuild problem could be pinned down and fixed. I suspect that one thing that would help would be putting the uses clause in the unit rather than the include file since it has an impact on both... but at this point things would be getting decidedly messy since the interface file could no longer be read in isolation :-/

Quote
I don't really see the copyright being that important, the few big corporates that fight out their legal  wars (like Oracle-Google over Java) will have complete departments on it, and can handle specifying separate clauses for interface and implementation even in one file.

So why bother?

Well, when various people at Bell Labs thrashed out C (hence the potential for a mix of declarations and implementation in header files) in the early 70s they probably didn't appreciate just how big business software would end up being. and they definitely didn't anticipate Oracle vs Google in the Supreme Court.

I think the fact that that case /did/ merit the consideration of the USA's senior judicial body... which I think is taken seriously by just about everybody else, even if they prefer not to admit it... should be taken as an indication that in another 50 years decisions we are making now might end up getting similar scrutiny. Hypothetically we might, for example, have a situation at some point in the future where somebody (SCO Redux?) challenges the legality of the GPL or some variant of the Creative Commons license since it is routinely applied to files which cannot be licensed since they contain nothing copyrightable: /I/ think it's bad legal reasoning, but some court might decide that the GPL etc. is /always/ invalid because it is /sometimes/ used inappropriately.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on May 31, 2022, 02:24:20 pm
Yes, I agree. If it comes to a dispute, it only matters who has the most money. Being in the right is not all that important.

Actually, that's not always the case:

https://www.nytimes.com/2010/02/09/us/09bar.html

I must say that that's a sufficiently convincing story of somebody who- eventually- started getting things right that it brings tears to my eyes.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on May 31, 2022, 04:55:05 pm
Yeah, sorry, I reacted to a general interface-implementation difference, not on the include trick specifically.

Note that contrary to Delphi,  FPC iirc does have some .inc checking (one level only), which you can see during .ppu loading with -va.

Code: [Select]
[0.030] (FPINTRES) PPU Source: fpintres.pp not available
[0.030] (FPINTRES) PPU Source: winres.inc not available

But as Sven says it is not recursive, so if you move the general interface into an include, it won't do that check on incs in the interface (OTOH, delphi never checks any includes afaik, so if delphi programmers can, you might be able to do without it too).

While I think it is a good FPC feature to check, it is only a first order thingy.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on May 31, 2022, 05:24:18 pm
Yeah, sorry, I reacted to a general interface-implementation difference, not on the include trick specifically.

Don't worry, I was expecting reactions which is why I phrased my original question very cautiously :-)

I'm also very much in mind of this from a couple of weeks ago:

In the C world C files can be build in parallel, because they don't depend on each other (declarations and such are in separate header files that are simply included by each). This is not the case for FPC, because units have dependencies between each other and the compiler simply can't continue compiling a unit until all dependencies of that unit are solved.

However thinking about your

Quote
Note that contrary to Delphi,  FPC iirc does have some .inc checking (one level only), which you can see during .ppu loading with -va.

Code: [Select]
[0.030] (FPINTRES) PPU Source: fpintres.pp not available
[0.030] (FPINTRES) PPU Source: winres.inc not available

But as Sven says it is not recursive, so if you move the general interface into an include, it won't do that check on incs in the interface (OTOH, delphi never checks any includes afaik, so if delphi programmers can, you might be able to do without it too).

While I think it is a good FPC feature to check, it is only a first order thingy.

OK, that's interesting... if we assumed that a .itf describing an interface and included in a unit file had a uses clause but did not have any $includes, should that be reliable? Would the "only one level deep" prevent units appearing in the uses clause from checking their .itf files, i.e. does the depth get reset for each unit or is it entirely relative to the main program (i.e. top-level sourcefile)?

I'm definitely not asking for help with this but the earlier problem I've come across is illustrated at https://forum.lazarus.freepascal.org/index.php/topic,52849.msg392854.html#msg392854 : it appears there's a $unitpath involved but I saw enough to make me suspect that the conditional was masking the version/age checks. I need to put more time into that and if I can get to a "reliable problem" state I'll raise it formally.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on June 01, 2022, 09:12:24 am
OK, that's interesting... if we assumed that a .itf describing an interface and included in a unit file had a uses clause but did not have any $includes, should that be reliable? Would the "only one level deep" prevent units appearing in the uses clause from checking their .itf files, i.e. does the depth get reset for each unit or is it entirely relative to the main program (i.e. top-level sourcefile)?

It's completely irrelevant where the uses clause is located. When checking whether something changed the compiler goes purely by date: it first opens the PPU and tries to find the source file for it. If it's found it checks whether the source file is newer than what is stored in the PPU, if so the unit is recompiled. Then it does the same for the include files (with varying degrees of working correctly). If the compiler does not recompile the unit it will take the used units from the PPU otherwise it's recompiling the unit (together with its includes) anyway (it's either an all or nothing).

So if you have the uses-clause in an include the only difference would be whether the change detection would pick it up or not (ideally it should, but currently it might not), but the same applies to any change, cause at that point the compiler doesn't care about content.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 01, 2022, 10:44:06 am
It's completely irrelevant where the uses clause is located. When checking whether something changed the compiler goes purely by date: it first opens the PPU and tries to find the source file for it. If it's found it checks whether the source file is newer than what is stored in the PPU, if so the unit is recompiled. Then it does the same for the include files (with varying degrees of working correctly). If the compiler does not recompile the unit it will take the used units from the PPU otherwise it's recompiling the unit (together with its includes) anyway (it's either an all or nothing).

So if you have the uses-clause in an include the only difference would be whether the change detection would pick it up or not (ideally it should, but currently it might not), but the same applies to any change, cause at that point the compiler doesn't care about content.

I think you're actually saying that in principle it /should/ be completely irrelevant where the uses clause is located relative to a $include, but in practice it /might/ not be (which would be a bug, rather than implementation-defined behaviour etc. :-)

OK, so if I'm reading you correctly the timestamp on included files one level deep will be checked correctly, but that /might/ not work at deeper levels and there's a /risk/ that a uses clause in an included file (one level deep) won't be recursed through (with that risk increasing as the depth increases).

So an included .itf should be fairly reliable if a convention is used that it doesn't itself include anything. The residual risk is that a changed unit in the .itf's uses clause won't be picked up, which will obviously apply more to in-project imports rather than references to the RTL etc.

As I've said, I'm not out to argue the merits either way of this approach. But it does appear that as well as- I believe- helping the copyright/license situation it should allow .itf files (I'm trying to avoid the word "interface" here) to be protected from casual modification.

Comparing it with the Modula-2 family's approach, the significant difference is that an import (via a uses clause) in a .itf automatically applies to the implementation part as well, and it will be an error if repeated even if the versioning matches.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on June 01, 2022, 01:36:37 pm
I think you're actually saying that in principle it /should/ be completely irrelevant where the uses clause is located relative to a $include, but in practice it /might/ not be (which would be a bug, rather than implementation-defined behaviour etc. :-)

Yes, or more like a shortcoming than a bug, though that doesn't change the result. ;)

OK, so if I'm reading you correctly the timestamp on included files one level deep will be checked correctly, but that /might/ not work at deeper levels and there's a /risk/ that a uses clause in an included file (one level deep) won't be recursed through (with that risk increasing as the depth increases).

Yes and no. Yes regarding the timestamps, but the uses-clause is irrelevant here. If the compiler decides to recompile the unit it will always read all the include files of that unit and all indirectly used ones (and if one is missing: error). If the compiler does decide not to recompile the unit the used units will always be retrieved from the PPU. So if the compiler doesn't correctly handle checks for some include file it does not matter what change you make (be it a uses-clause or a white space change) it will simply not trigger the recompilation.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 01, 2022, 02:39:10 pm
Yes, or more like a shortcoming than a bug, though that doesn't change the result. ;)

I can assure you that I'm not criticising, just trying to work things out :-)

Quote
Yes and no. Yes regarding the timestamps, but the uses-clause is irrelevant here. If the compiler decides to recompile the unit it will always read all the include files of that unit and all indirectly used ones (and if one is missing: error). If the compiler does decide not to recompile the unit the used units will always be retrieved from the PPU. So if the compiler doesn't correctly handle checks for some include file it does not matter what change you make (be it a uses-clause or a white space change) it will simply not trigger the recompilation.

The key words there are "if the compiler decides".

Reading things through a dozen times to make sure I'm not living dangerously, I think the key scenario is this:

* Program X uses unit Y which includes file Z, and file Z uses unit T.

* A change to (only) Z will not cause Y or X to be recompiled, since the names and attributes of included files are not stored in a .ppu file.

* A change to T will always cause Y and X to be recompiled (hence Z to be reread), since the names and attributes of used files are stored in a .ppu file.

I'm obviously not criticising, and am very much aware that this sort of thing makes demands of the compiler well beyond what gcc etc. would be able to handle without an external build system.

Hence the risk is that if we have this:

* Program A.pas uses unit B.

* Unit B.pas includes its interface definition from B.itf

* A change to B.itf will always be read if unit B is recompiled.

* But if B.itf, included in B.pas, is changed without B.pas being changed, then unit B will not automatically be recompiled.

Hence my suggestion of included .itf files is not safe, if the contained unit interface definition is changed without change to the unit implementation.

I'd be very happy for you to argue that my suggestion is more robust than I've concluded :-)

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on June 02, 2022, 09:22:04 am
The key words there are "if the compiler decides".

Yes, that's the important part.

* Program X uses unit Y which includes file Z, and file Z uses unit T.

Nitpicking: it's always unit Y that uses unit T, but it's file Z that contains the uses-clause (this is an important point, because the compiler keeps track of used units and symbols and such based on units, not based on files)

* A change to (only) Z will not cause Y or X to be recompiled, since the names and attributes of included files are not stored in a .ppu file.

As long as the system works correctly a change to Z will trigger a recompilation of Y (sidenote: the main program file, or to be precise the file provided on the command line - after all it could be a unit as well - is always compiled), because the compiler does store the included files and their timestamps in the PPU.

Take the following example:

Code: Pascal  [Select][+][-]
  1. // trecompile.pp
  2. program trecompile;
  3.  
  4. uses
  5.   urecompile;
  6.  
  7. begin
  8.  
  9. end.
  10.  
  11. // urecompile.pp
  12. unit urecompile;
  13.  
  14. {$mode objfpc}{$H+}
  15.  
  16. interface
  17.  
  18. {$I irecompile.inc}
  19.  
  20. implementation
  21.  
  22. end.
  23.  
  24. // irecompile.inc
  25. uses
  26.   {$I irecompile2.inc}
  27.   Classes;
  28.  
  29. // irecompile2.inc
  30. {SysUtils,}

If you now compile trecompile.pp you will see the following output:

Code: [Select]
PS D:\fpc\git> fpc -FEtestoutput .\fpctests\trecompile.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling .\fpctests\trecompile.pp
Compiling .\fpctests\urecompile.pp
Linking testoutput\trecompile.exe
24 lines compiled, 0.1 sec, 148000 bytes code, 6548 bytes data

If you compile it again without any changes the output will be as following:

Code: [Select]
PS D:\fpc\git> fpc -FEtestoutput .\fpctests\trecompile.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling .\fpctests\trecompile.pp
Linking testoutput\trecompile.exe
8 lines compiled, 0.1 sec, 148000 bytes code, 6548 bytes data

As you can see the line Compiling .\fpctests\urecompile.pp is missing, because the compiler determined that urecompile.pp is up to date.

You can also use ppudump urecompile.ppu and you will see the following (among other information):

Code: [Select]
Interface section
------------------
Module Name: urecompile

Source file 1 : urecompile.pp 2022/06/02 08:58:06
Source file 2 : irecompile.inc 2022/06/02 08:59:52
Source file 3 : irecompile2.inc 2022/06/02 09:00:20
Uses unit: System (Crc: D86E0595, IntfcCrc: 01C77D16, IndCrc: BDD566AD)
Uses unit: objpas (Crc: 869382B2, IntfcCrc: 28EE26C5, IndCrc: AB9908A2)
Uses unit: Classes (Crc: 5FF4CBD7, IntfcCrc: DBC85DDC, IndCrc: 2CAFF89A)
DerefMapsize: 1
DerefMap[0] = SYSTEM
Derefdata length: 27

If you now change irecompile2.inc (by removing the swirly brackets) you will see this:

Code: [Select]
PS D:\fpc\git> fpc -FEtestoutput .\fpctests\trecompile.pp
Free Pascal Compiler version 3.2.2 [2022/01/02] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling .\fpctests\trecompile.pp
Compiling .\fpctests\urecompile.pp
Linking testoutput\trecompile.exe
24 lines compiled, 0.1 sec, 148000 bytes code, 6548 bytes data

So here the compiler decided to recompile urecompile.pp, because it successfully detected the changed file.

So in this specific example everything is as it should be. 8)

* A change to T will always cause Y and X to be recompiled (hence Z to be reread), since the names and attributes of used files are stored in a .ppu file.

Here you didn't pay attention to Pascal 101: a unit is only recompiled if something significant of a used unit changed. Mainly this means information from the unit's interface, but sometimes this is also the case if the code of some function declared with inline changed (this is still the source of quite some headaches in the compiler and ideally the compiler should also trigger this if a generic implementation is changed...).

So if you change something in the implementation of T then Y likely won't be recompiled (and X will always be as mentioned above), but if you change something in the interface section of T it is very likely that Y will be recompiled. I say likely, because if you only change a typo in a comment and that change doesn't lead to a change of the file position for the remainder of the code (meaning for example that you didn't insert or remove a line) then the relevant content of the unit (from the compiler's PoV) is still considered the same and thus the compiler doesn't see the need to recompile Y.

To come back to your problem: as you see it should work correctly. However we know from past experience that something there is fishy when multiple include files are used, but we've not yet been able to pinpoint the problem. Or maybe it was indeed solved already. That's the problem: we don't have a reproducible case and thus don't know whether the problem has been solved or not.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 02, 2022, 10:24:12 am
Thanks very much for the detailed answer, and my apologies for causing you extra work.

the compiler does store the included files and their timestamps in the PPU.

/Aha/, that's something I didn't adequately appreciate.

That's actually an argument that you could probably use when tiresome people (such as, on occasion, myself) opine that there could usefully be an accessible preprocessor stage: it would need some way of annotating the .ppu later produced by the compiler.

Quote
I say likely, because if you only change a typo in a comment and that change doesn't lead to a change of the file position for the remainder of the code (meaning for example that you didn't insert or remove a line) then the relevant content of the unit (from the compiler's PoV) is still considered the same and thus the compiler doesn't see the need to recompile Y.

Interesting. Something I'm tinkering with at the moment uses the Linux FAM API, and I noticed an interesting situation where a changed file (containing test data) was always detected if touched etc. but wasn't detected reliably if simply /saved/ by Lazarus. Leaving aside for the moment the potential that the IDE has for not really saving something that hasn't had a significant change (e.g. all changes have been undone), that turned out to mainly be because Lazarus was using the "unix doctrine" of renaming the original and creating a new file.

Quote
To come back to your problem: as you see it should work correctly. However we know from past experience that something there is fishy when multiple include files are used, but we've not yet been able to pinpoint the problem. Or maybe it was indeed solved already. That's the problem: we don't have a reproducible case and thus don't know whether the problem has been solved or not.

Bearing that in mind, I think I'll try having separate .itf files when I've next got something I'm building as a library, and will also revisit the project I mentioned a few posts ago where stuff wasn't getting recompiled. I'll report back presently if I can pin a reliable test case down.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on June 02, 2022, 02:01:40 pm
That's actually an argument that you could probably use when tiresome people (such as, on occasion, myself) opine that there could usefully be an accessible preprocessor stage: it would need some way of annotating the .ppu later produced by the compiler.

You don't need to look at some accessible preprocessor stage: if you define different defines at the command line for different runs of the compiler a compiled unit won't be recompiled (that's why Lazarus triggers a complete build if you changed some project settings).

Quote
To come back to your problem: as you see it should work correctly. However we know from past experience that something there is fishy when multiple include files are used, but we've not yet been able to pinpoint the problem. Or maybe it was indeed solved already. That's the problem: we don't have a reproducible case and thus don't know whether the problem has been solved or not.

Bearing that in mind, I think I'll try having separate .itf files when I've next got something I'm building as a library, and will also revisit the project I mentioned a few posts ago where stuff wasn't getting recompiled. I'll report back presently if I can pin a reliable test case down.

A reproducible test case would be very welcome.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 02, 2022, 02:26:40 pm
You don't need to look at some accessible preprocessor stage: if you define different defines at the command line for different runs of the compiler a compiled unit won't be recompiled (that's why Lazarus triggers a complete build if you changed some project settings).

Yes, the existing conditional directives etc. are beyond reproach... the multiline macro expansion is a joy (even if some argue that being able to interpolate even limited parameters would make it even better).

But what happens if it is /natural/ to embed something in the main Pascal source, which needs preprocessing in order to make it available as a resource etc.? The canonical example of this is embedded SQL.

Please take that to be a rhetorical question, I'm definitely not trying to criticise the status quo (since I said I wanted to avoid doing that on OP).

Quote
A reproducible test case would be very welcome.

I'll see what I can do.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: Kays on June 03, 2022, 09:43:01 am
FYI, regarding ISO 10206 “Extended Pascal” modules there is (or was) the plan to have *.int.* (interface) and *.imp.* (implementation) files (https://wiki.freepascal.org/Extended_Pascal#Modules_.28not_yet_implemented.29) beside single-file-modules (claim was inserted by Keith Bowes in 2017 (https://wiki.freepascal.org/Special:Diff/112987)).
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 03, 2022, 11:08:13 am
FYI, regarding ISO 10206 “Extended Pascal” modules there is (or was) the plan to have *.int.* (interface) and *.imp.* (implementation) files (https://wiki.freepascal.org/Extended_Pascal#Modules_.28not_yet_implemented.29) beside single-file-modules (claim was inserted by Keith Bowes in 2017 (https://wiki.freepascal.org/Special:Diff/112987)).

Thanks for that detail. I've been trying to be careful with my use of "interface" in the discussion above because of its widely-accepted meaning in the context of OO programming etc. My tentative choice of .itf was because it was the extension adopted by TopSpeed Pascal, and that was originally a sibling of their Modula-2 compiler which Niels Jensen took when he left Borland allegedly after Philippe Kahn bought in an externally-developed C compiler.

On reflection, I think it's worth remarking that filenames with the pattern modulename.imp.{p,pp,pas} etc. are sufficiently "un-DOS" (by extension, "un-Windows", "un-OS/2" and so on) and for that matter "un-unix" that I have to wonder what sort of platform the ISO committee envisaged as being suitable for hosting a Pascal compiler. There's a definite whiff of the Ada ailment creeping in there: a prerequisite of being able to run a compiler is having access to a large multiuser system capable of running a committee-designed workbench.

I'm tempted to start a new thread to discuss how many of the features in https://wiki.freepascal.org/Extended_Pascal have been (or might realistically at some point be) implemented. However TBH I feel that ISO-standard Pascal (and for that matter ISO-standard Modula-2) have even less industrial and historical significance than Ada.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on June 03, 2022, 01:41:54 pm
FYI, regarding ISO 10206 “Extended Pascal” modules there is (or was) the plan to have *.int.* (interface) and *.imp.* (implementation) files (https://wiki.freepascal.org/Extended_Pascal#Modules_.28not_yet_implemented.29) beside single-file-modules (claim was inserted by Keith Bowes in 2017 (https://wiki.freepascal.org/Special:Diff/112987)).

What do you mean by planned? Planned by the ISO committee, but not implemented in the final draft?
Title: Re: Separating definition and implementation parts
Post by: BeniBela on June 03, 2022, 06:31:12 pm

Quote
To come back to your problem: as you see it should work correctly. However we know from past experience that something there is fishy when multiple include files are used, but we've not yet been able to pinpoint the problem. Or maybe it was indeed solved already. That's the problem: we don't have a reproducible case and thus don't know whether the problem has been solved or not.

Bearing that in mind, I think I'll try having separate .itf files when I've next got something I'm building as a library, and will also revisit the project I mentioned a few posts ago where stuff wasn't getting recompiled. I'll report back presently if I can pin a reliable test case down.

A reproducible test case would be very welcome.

There is this: https://gitlab.com/freepascal.org/fpc/source/-/issues/37478
Title: Re: Separating definition and implementation parts
Post by: mercurhyo on June 05, 2022, 06:19:49 pm
My 2 cents here.

As Pr. Niklaus With, Father of the Pascal language had a "vision" He then created a successor language named Modula 2. Meaning IT IS a pascalish dialect. And Modula 2 introduced structured modular programming. Each module had 2 files, as I read along on this publication. Formally 1 file as interface (.def) and 1 file as implementation (.mod)

AT these OLD times it was so damn AMAZING that I gave up for 3 years working with turbinopasquale LOL I even saw in the industry some robots totally programmed with modula 2.

However ... due to fashion's mass effect, I came back to pascal and worked with "popular" (this world is heavy) delpinabitius .

You can never know the weight of fashion and the keys of locked minds.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 05, 2022, 07:42:08 pm
As Pr. Niklaus With, Father of the Pascal language had a "vision" He then created a successor language named Modula 2. Meaning IT IS a pascalish dialect. And Modula 2 introduced structured modular programming. Each module had 2 files, as I read along on this publication. Formally 1 file as interface (.def) and 1 file as implementation (.mod)

Yes, there are several ex-users here- and it has been alluded to if not named directly elsewhere in the thread. You've actually forgotten Modula, but I've been able to find very little relating to its structure... it might actually have been closer to Brinch Hansen's Edison.

As far as Modula-2 being a Pascalish language is concerned: one has to be extremely careful there since there was a fundamental difference between Pascal's "this conditional applies to a single statement" and Modula-2's "this conditional applies to everything up to an explicit else or end". Taking into account timeframes, I think it would be most accurate to refer to the former as "ALGOL-60/Pascal" and the latter as "ALGOL-68/Modula-2": almost all other current languages fall into one or the other of those categories.

Modula-2, particularly in conjunction with OS/2, fitted in very nicely with the DLL concept. However its failing in that area was that it wasn't possible to use a single definition module as a template for multiple implementation modules, or to have a definition module implicitly inheriting the exports of a preceding one. That is, of course, where OO techniques come into play, which initially at least attracted Wirth's scorn since he insisted that an object was nothing more than a record: an inexcusable whitewash since he'd spent at least one sabbatical at PARC.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: mercurhyo on June 06, 2022, 09:19:47 am
Nope! "OOP" anywhere = mistake! Pr. Wirth was a visionaire, and OOP is basically what he said. He was around 75-80 years old to explain the "sabatical" thingeys. Hope the brain of anyone here works fine in theses ages.
Yes OOP is useful but no God... by the way, even windows 10/11 is 90% C, not C++ HA!

I'm not mean, I won't say 10% hahahaha

SO!!! I'm stick on my position = ALL THAT IS ABOUT weight of fashion
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 09:29:04 am
Nope! "OOP" anywhere = mistake! Pr. Wirth was a visionaire, and OOP is basically what he saud. He was around 75-80 years old to explain the "sabatical" thingeys. Hope the brain of anyone here works fine in theses ages.
Yes OOP is useful but no God... by the way, even windows 10/11 is 90% C, not C++ HA!

I'm not mean, I won't say 10% hahahaha

SO!!! I'm stick on my position = ALL THAT IS ABOUT weight of fashion

Rubbish.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: mercurhyo on June 06, 2022, 09:35:58 am

Rubbish.

MarkMLl

My pleasure, "milady" hahahahahahaha I LOVED your nonargument, marry me haahahhah
Title: Re: Separating definition and implementation parts
Post by: Kays on June 06, 2022, 11:44:55 am
What do you mean by planned? Planned by the ISO committee, but not implemented in the final draft?
No, the ISO committee isn’t concerned how a computer organizes its data. I posted a link to our Wiki page, so I thought its self-explanatory this was an FPC idea.

[…] What are the technical implications of doing this […]
I think the whole idea of separating the interface and implementation into individual files makes only sense if your compiler allows you to swap alternative implementations (of the same interface) on request. If there is always a 1‑to‑1 relation, 1 interface : 1 implementation, it does (technically) not make any sense to have separate files other than for increasing complexity.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 12:09:53 pm
No, the ISO committee isn’t concerned how a computer organizes its data. I posted a link to our Wiki page, so I thought its self-explanatory this was an FPC idea.

OK, so the operative text is Enhancements to Standard Pascal ... Modularity and separate compilation ... (not yet implemented). Frankly I think the choice of names is a nitwit idea because having multiple dots in a name is so unusual and because TopSpeed had demonstrated that .itf was workable many years earlier.

If that stuff is never going to happen I'm not sure it even belongs in the wiki, since so many people assume that it's official documentation.

Quote
I think the whole idea of separating the interface and implementation into individual files makes only sense if your compiler allows you to swap alternative implementations (of the same interface) on request. If there is always a 1‑to‑1 relation, 1 interface : 1 implementation, it does (technically) not make any sense to have separate files other than for increasing complexity.

I suppose that you could have a stub file that included both the definition and an implementation selected by conditionals, but that's getting /heavy/. My own opinion is that the copyright+license argument is significant, but separating the files also allows definitions to be locked against unauthorised modification

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on June 06, 2022, 12:34:58 pm
No, the ISO committee isn’t concerned how a computer organizes its data. I posted a link to our Wiki page, so I thought its self-explanatory this was an FPC idea.

The Wiki is publically writable, and not in any way authoritative in any form.
Title: Re: Separating definition and implementation parts
Post by: marcov on June 06, 2022, 12:51:13 pm
Modula-2, particularly in conjunction with OS/2, fitted in very nicely with the DLL concept. However its failing in that area was that it wasn't possible to use a single definition module as a template for multiple implementation modules,

or to have a definition module implicitly inheriting the exports of a preceding one. That is, of course, where OO techniques come into play, which initially at least attracted Wirth's scorn since he insisted that an object was nothing more than a record: an inexcusable whitewash since he'd spent at least one sabbatical at PARC.

Doesn't sound to me as anything that would resonate with any of M2's principles.  And is static module inheritance really OO ?  Only two out of Identity, polymorphism, data encapsulation and abstraction.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 12:57:07 pm
No, the ISO committee isn’t concerned how a computer organizes its data. I posted a link to our Wiki page, so I thought its self-explanatory this was an FPC idea.

The Wiki is publically writable, and not in any way authoritative in any form.

Since the wiki is basically annotating a non-public standard, and since "Standard" and "Extended" Pascal arguably did more harm than good to the language, I'm not at all sure that having keeping that page of "aspirational features" is in FPC's interest.

Factual documentation of what FPC actually implements and what "standard" features it omits is obviously useful. A list of suggested extensions to the standards which can't be xrefed to the content of the actual standards isn't.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 01:08:21 pm
Doesn't sound to me as anything that would resonate with any of M2's principles.

Frankly I agree, but I was writing a disk (etc.) display program and having some sort of template definition- e.g. to present the same interface irrespective of whether media access was via PC BIOS calls or direct to an IDE controller- would have been extremely useful. As it was, the bigger problem was that the M2 compiler I was using at the time- can't remember whether it was Logitech or Topspeed- turned out to have an unreasonably-small hardcoded limit of how many modules it could deal with.

Quote
And is static module inheritance really OO ?  Only two out of Identity, polymorphism, data encapsulation and abstraction.

Definitely not. Point I was making was that OO later supplied things that weren't in M2 modularisation, but having some sort of "half-way house" might still have been useful.

I've not, unfortunately, been able to find a copy of Wirth's anti-OO rant. It was reprinted in .Exe in the mid-90s but might actually have been an interview from a few years before, Wirth might already have been arguing from the POV or Oberon rather than that of M2/Pascal but in any event it was uncomfortable reading (there's good reasons why ageing academics are shuffled out with "Emeritus" stickers :-)

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on June 06, 2022, 01:35:35 pm
Also keep in mind that Wirth was into system programming at that time, not application programming.

It is application programming where OO is now ubiquitous
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 02:06:36 pm
Also keep in mind that Wirth was into system programming at that time, not application programming.

It is application programming where OO is now ubiquitous

Compilers are system software and benefit from such things in moderation. Even at the OS level, being able to define device drivers relative to a consistent template is valuable.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: 440bx on June 06, 2022, 02:07:18 pm
It is application programming where OO is now ubiquitous
But, it should be noted that one of the most salient characteristics of OOP comes straight from systems programming which is, polymorphism.  In O/Ss, polymorphism is used to transparently redirect input and ouput by altering function pointers. 

This idea, which admittedly is a powerful mechanism, is being grossly abused and misused in OOP.

Like everything, "good" is relative and, too much "good" ends up being bad.
Title: Re: Separating definition and implementation parts
Post by: marcov on June 06, 2022, 02:25:33 pm
No, the ISO committee isn’t concerned how a computer organizes its data. I posted a link to our Wiki page, so I thought its self-explanatory this was an FPC idea.

The Wiki is publically writable, and not in any way authoritative in any form.

Since the wiki is basically annotating a non-public standard, and since "Standard" and "Extended" Pascal arguably did more harm than good to the language, I'm not at all sure that having keeping that page of "aspirational features" is in FPC's interest.

It suits some developers to have a people writing up long stories in the wiki, rather than saying a firm NO! to an outlandish feature suggestion.

I have no such qualms :-)

Quote
Factual documentation of what FPC actually implements and what "standard" features it omits is obviously useful. A list of suggested extensions to the standards which can't be xrefed to the content of the actual standards isn't.

FPC is a dialectal hodgepodge, but traditionally focussed on Borland/Turbo Pascal dialects (BP7 till 1.0.x, more Delphi oriented with 2.0.x+).   

Personally I think the core goal should be to avoid fragmenting what's left of the Pascal world. So that means Delphi with minor compat modes for BP and ISO Dialects (as long as there are people willing to work on them)
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 02:36:56 pm
(polymorphism), which admittedly is a powerful mechanism, is being grossly abused and misused in OOP.

Only when an entry point is late-bound: OO- as originally defined- is at least as much about inheritance (with an override capability) as it is about polymorphism. And if properly implemented the compiler resolves all function calls that aren't explicitly late-bound, rather than relying on explicit or implicit function pointers which IME are undesirable in a system intended to be robust.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 02:45:15 pm
It suits some developers to have a people writing up long stories in the wiki, rather than saying a firm NO! to an outlandish feature suggestion.

I have no such qualms :-)

The wiki is far too public for "wouldn't it be nice" discussion that people might interpret as factual documentation. Perhaps it should have a "High and low fantasy" category :-)

Quote
FPC is a dialectal hodgepodge, but traditionally focussed on Borland/Turbo Pascal dialects (BP7 till 1.0.x, more Delphi oriented with 2.0.x+).   

Personally I think the core goal should be to avoid fragmenting what's left of the Pascal world. So that means Delphi with minor compat modes for BP and ISO Dialects (as long as there are people willing to work on them)

I agree. I was going to suggest that we should perhaps be looking at whether anybody is actually using e.g. the ISO dialect, but it can be very embarrassing if somebody wants to compile some ancient high-value codebase and we have to tell him that the current compiler no longer supports the stuff he needs (e.g. like old-style objects).

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: Thaddy on June 06, 2022, 03:49:06 pm

I agree. I was going to suggest that we should perhaps be looking at whether anybody is actually using e.g. the ISO dialect, but it can be very embarrassing if somebody wants to compile some ancient high-value codebase and we have to tell him that the current compiler no longer supports the stuff he needs (e.g. like old-style objects).

MarkMLl
Well, I am using it to try to compile some old - very old - code. And it can be fun.
But in general old freaks like me use it, but it is not a "standard" for a long time.
Note I predate most of the FPC developers by almost two decades.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 04:42:01 pm
Well, I am using it to try to compile some old - very old - code. And it can be fun.
But in general old freaks like me use it, but it is not a "standard" for a long time.
Note I predate most of the FPC developers by almost two decades.

I'm using code originally written in '64 actively, although it's been transcribed, and I've done various things with ALGOL of about the same vintage. Apart from that the oldest Pascal code I've dealt with was an APL interpreter for a CDC from the mid 70s... in other words about the same time that I went to university.

But whether I've been selling, supporting or discussing in academia, the impression I've always got is that ISO standardisation of Pascal and Modula-2 was pretty much ignored, and contributed to the popular perception that they were unusable niche languages.

But DaveP's question a few days ago about converting some 1990s Modula-2 to Pascal is a useful reminder that the more dialects we can support (without making the codebase unmaintainable) the better.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on June 06, 2022, 04:55:30 pm
I agree. I was going to suggest that we should perhaps be looking at whether anybody is actually using e.g. the ISO dialect, but

Because? Where is the actual hurt?

Quote

it can be very embarrassing if somebody wants to compile some ancient high-value codebase and we have to tell him that the current compiler no longer supports the stuff he needs (e.g. like old-style objects).

No different when people notice missing features in the Delphi dialect, or don't understand why their D7 code with 40% pure assembler routines doesn't work on 64-bit ARM ?
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 05:35:19 pm
I agree. I was going to suggest that we should perhaps be looking at whether anybody is actually using e.g. the ISO dialect, but

Because? Where is the actual hurt?

The more weird linguistic features piled into the language, the more it risks becoming an unmaintainable pile. As an example, the desirability of supporting Modula-2 style syntax has been raised in the past but the bottom line is that it's not feasible to shoehorn an increasing number of features into the syntax- even if isolated by mode selection.

Quote
Quote

it can be very embarrassing if somebody wants to compile some ancient high-value codebase and we have to tell him that the current compiler no longer supports the stuff he needs (e.g. like old-style objects).

No different when people notice missing features in the Delphi dialect, or don't understand why their D7 code with 40% pure assembler routines doesn't work on 64-bit ARM ?

Actually yes, very different. "Missing features in the Delphi dialect" is arguably a bug, and no sane developer who knows he has embedded assembler would expect it to be portable... irrespective of the example shown by Macs with on-the-fly binary translation. However saying to somebody "no, that mode used to be supported but isn't any more" is simply embarrassing: there's obviously things dropped like GTK v1 and the earlier versions of Win-32 but that can generally be justified by pointing to inadvisability of running an OS sufficiently old that it demands that API not to mention the rarity of hardware that supports those OSes.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on June 06, 2022, 10:56:23 pm
The more weird linguistic features piled into the language, the more it risks becoming an unmaintainable pile. As an example, the desirability of supporting Modula-2 style syntax has been raised in the past but the bottom line is that it's not feasible to shoehorn an increasing number of features into the syntax- even if isolated by mode selection.

True. But I would rather cull objfpc than mode ISO. 

Quote
Quote
No different when people notice missing features in the Delphi dialect, or don't understand why their D7 code with 40% pure assembler routines doesn't work on 64-bit ARM ?

Actually yes, very different. "Missing features in the Delphi dialect" is arguably a bug, and no sane developer who knows he has embedded assembler would expect it to be portable...

Euh, as for the latter, how long have you been answering questions here ?  ;) ;)

Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 06, 2022, 11:26:24 pm
Euh, as for the latter, how long have you been answering questions here ?  ;) ;)

Not nearly as long as I was active on the ML, but... well /yes/ :-)

But I tried to phrase that to indicate that the bigger problem is when the developer doesn't know because he's just using an off-the-shelf library.

There's a big earthmover manufacturer in the UK with yellow products and a three-letter name. In the 1970s they were a Burroughs customer, but their DPM was taken on a few "jollies" by a competitor who assured him that anything B could do they could do better.

He signed the replacement contract on Friday. On Monday the content of his desk was waiting for him at the gatehouse. You see, those computers were optimised to run COBOL with an almost one-to-one correspondence between COBOL and assembler statements... with the result that many application programmers skipped the COBOL and wrote directly in medium-systems assembler.

The joke is that if names are anything to go by, the engineer most likely to have tipped off the customer's senior management was last heard of working for the company behind the Hercules mainframe emulator... which is something that IBM /really/ doesn't like.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on June 07, 2022, 01:50:03 pm
But what happens if it is /natural/ to embed something in the main Pascal source, which needs preprocessing in order to make it available as a resource etc.? The canonical example of this is embedded SQL.

If it would be with the yet to be integrated multiline string then it's just that: a string in an include file or the file itself.
If it would be with the yet to be integrated $IncludeString directive then the included file in question would be handled like an ordinary include file as far as recompilation detection is concerned.
If it would be with the $R directive to include a Windows-like resource then I can't answer whether this would currently work correctly. Ideally the compiler should handle changed resource files as well. What would definitely not work however is if you have a $R something.res (meaning you use a precompiled resource instead of having the compiler generate it by calling fpcres) and you change the original file that was compiled into the resource then FPC would have no way to detect that, cause the res file contains no information about the original files.

I suppose that you could have a stub file that included both the definition and an implementation selected by conditionals, but that's getting /heavy/. My own opinion is that the copyright+license argument is significant, but separating the files also allows definitions to be locked against unauthorised modification

The stub file approach is in fact something that's used quite some time in the RTL ;)

Since the wiki is basically annotating a non-public standard, and since "Standard" and "Extended" Pascal arguably did more harm than good to the language, I'm not at all sure that having keeping that page of "aspirational features" is in FPC's interest.

Extended Pascal was much less used than ISO Pascal, so it can't have done much bad. And sadly it came too late to unfold the good it promised (and if you take the time to read the Extended Pascal standard it has quite some goodies).

And keeping the page about the Extended is definitely in FPC's interest, cause it's about keeping track which features of Extended Pascal are already implemented. And while it's not a priority it is our goal for FPC to also be a full ISO Extended Pascal.

Factual documentation of what FPC actually implements and what "standard" features it omits is obviously useful. A list of suggested extensions to the standards which can't be xrefed to the content of the actual standards isn't.

I agree. As such I have clarified on the Wiki that the part about the two-file-modules is merely a suggestion.

Edit: nearly forgot this:


Quote
To come back to your problem: as you see it should work correctly. However we know from past experience that something there is fishy when multiple include files are used, but we've not yet been able to pinpoint the problem. Or maybe it was indeed solved already. That's the problem: we don't have a reproducible case and thus don't know whether the problem has been solved or not.

Bearing that in mind, I think I'll try having separate .itf files when I've next got something I'm building as a library, and will also revisit the project I mentioned a few posts ago where stuff wasn't getting recompiled. I'll report back presently if I can pin a reliable test case down.

A reproducible test case would be very welcome.

There is this: https://gitlab.com/freepascal.org/fpc/source/-/issues/37478

This is about errors when using precompiled units. What I want is the compiler not detecting that something changed in indirectly used files and finishing successfully, but with no changes.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 07, 2022, 02:05:17 pm
As usual I'd like to express my appreciation of the work that you and the rest of the core team puts into this stuff.

Noted your comment about the RTL's heavy use of include files, which hadn't escaped me even though I didn't appreciate how robustly they were handled.

I agree. As such I have clarified on the Wiki that the part about the two-file-modules is merely a suggestion.

I find myself wondering how many make/build implementations would be broken by the double-dot scheme suggested.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on June 08, 2022, 09:39:33 am
Noted your comment about the RTL's heavy use of include files, which hadn't escaped me even though I didn't appreciate how robustly they were handled.

I had especially remarked about the stub file approach you suggested, not the RTL's general use of include files. Though yes, it does use quite a lot, but there the recompilation isn't a problem, because the RTL is always done using a clean build.

I agree. As such I have clarified on the Wiki that the part about the two-file-modules is merely a suggestion.

I find myself wondering how many make/build implementations would be broken by the double-dot scheme suggested.

Probably less then you'd expect. At work (in a C++ context) we make heavy use of dotted filenames for headers, source files and build artifacts (because it's much nicer to look at) and so far found no critical issues with MSVC, MSBuild or GNU make. Even FPC's ChangeFileExt handles this correctly by searching the point from the end and not from the start.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 09, 2022, 01:11:55 pm
This is about errors when using precompiled units. What I want is the compiler not detecting that something changed in indirectly used files and finishing successfully, but with no changes.

Found something when I wasn't expecting it.

An in-project unit brought into a called unit (not the main program) using

Code: Pascal  [Select][+][-]
  1. uses Hash32 in '../hash32/hash32.pas';
  2.  

where ../hash32 isn't set up in the Lazarus project paths (-Fu), I think that's similar to the case I had earlier, but doesn't have $unitpath muddying the water.

An edit to a primality test in hash32.pas was ignored until I did a Lazarus "Clean directory". I think I can reproduce that, please leave it with me... I mention it in case I keel over during the next few days.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on June 17, 2022, 01:39:37 pm
where ../hash32 isn't set up in the Lazarus project paths (-Fu), I think that's similar to the case I had earlier, but doesn't have $unitpath muddying the water.

An edit to a primality test in hash32.pas was ignored until I did a Lazarus "Clean directory". I think I can reproduce that, please leave it with me... I mention it in case I keel over during the next few days.

I've not forgotten this. The same project fails intermittently if I build from makefile with something like

Code: Text  [Select][+][-]
  1. FPCFLAGS=-Fu../hash32/ -Fu../ -Sa
  2.  

i.e. it's the relative path rather than the uses clause. This is currently causing me enormous pain since I've got code that fails if one of the runtime check options isn't enabled... and until I started vaping every single .o and .ppu in the tree I couldn't test it reliably.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on August 10, 2022, 10:08:14 am
If it would be with the yet to be integrated multiline string then it's just that: a string in an include file or the file itself.

Somewhat belated comment, wandering OT slightly.

I've previously said that I'm unhappy with the proposals for multiline strings, because apart from anything else they are likely to claim e.g. the " character and that's not something to be done lightly. I've also remarked that in some scripting stuff of my own I've allowed strings to be optionally delimited by / which made them into regexes... however while convenient that clashes with usage from at least one other language.

I wonder whether it would be possible to do something like using "..." for a multiline literal string, but mandating that it must in all cases have an associated type, and that no automatic type conversions will be made?

There might also need to be a local directive to tell the compiler how to deal with a nested " (i.e. whether to treat "" or \" specially) but in general that would allow a string to be explicitly defined as C-like (i.e. potentially using \ escapes), regex-like and so on without ambiguity.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on August 10, 2022, 01:51:18 pm
I've previously said that I'm unhappy with the proposals for multiline strings, because apart from anything else they are likely to claim e.g. the " character and that's not something to be done lightly. I've also remarked that in some scripting stuff of my own I've allowed strings to be optionally delimited by / which made them into regexes... however while convenient that clashes with usage from at least one other language.

It uses ` (backtick, ASCII character #60), not ".

I wonder whether it would be possible to do something like using "..." for a multiline literal string, but mandating that it must in all cases have an associated type, and that no automatic type conversions will be made?

The point of the multi line string feature is that an unmodified, multi line string can be pasted into the source (as long as it doesn't contain backticks, as those need to be doubled, but these are likely much more seldom than a "). Anything else can just as well be solved with the existing concatenation.

There might also need to be a local directive to tell the compiler how to deal with a nested " (i.e. whether to treat "" or \" specially) but in general that would allow a string to be explicitly defined as C-like (i.e. potentially using \ escapes), regex-like and so on without ambiguity.

We don't want to do C-like stuff. And this is not what this feature wants to solve.
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on August 10, 2022, 02:13:11 pm
It uses ` (backtick, ASCII character #60), not ".

I was /very/ careful to say "e.g." there. I don't want to argue for or against any particular character.

The main point I was trying to make was the desirability- in my opinion- of never making any assumptions about the actual type of a string decorated in this fashion, which is not anything I've seen argued in this forum.

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on August 11, 2022, 08:54:55 am
The main point I was trying to make was the desirability- in my opinion- of never making any assumptions about the actual type of a string decorated in this fashion, which is not anything I've seen argued in this forum.

I don't get your point. A multiline string constant is no different from an ordinary string constant as far as its type is concerned and follows the same rules regarding e.g. Unicode. The only difference is in how it's parsed and that the compiler automatically inserts newlines and indentation (based on compiler directives).
Title: Re: Separating definition and implementation parts
Post by: MarkMLl on August 11, 2022, 09:39:25 am
I don't get your point. A multiline string constant is no different from an ordinary string constant as far as its type is concerned and follows the same rules regarding e.g. Unicode. The only difference is in how it's parsed and that the compiler automatically inserts newlines and indentation (based on compiler directives).

I was originally concerned that this would be a wedge that heralded the insertion of an increasing amount of the syntactic sugar that you decry. with different decoration depending on what it was to be used for. However it occurred to me that this could be prevented with enforced typing.

"I'll get me coat."

MarkMLl
Title: Re: Separating definition and implementation parts
Post by: marcov on August 11, 2022, 09:48:00 am
Even FPC's ChangeFileExt handles this correctly by searching the point from the end and not from the start.

Well, it is safe to call changefileext on a string without extension. If you have dotted filenames, you might have to sanitize your code that that never happens (since that would lob off another segment of the string).
Title: Re: Separating definition and implementation parts
Post by: PascalDragon on August 11, 2022, 01:49:02 pm
I was originally concerned that this would be a wedge that heralded the insertion of an increasing amount of the syntactic sugar that you decry.

Why do you think that is still not integrated? I have more important features to fry than that...

with different decoration depending on what it was to be used for. However it occurred to me that this could be prevented with enforced typing.

I still don't get what typing would solve there, especially as in Pascal the result type of an expression (on the right) does not depend on the left side (except for function pointers).

Even FPC's ChangeFileExt handles this correctly by searching the point from the end and not from the start.

Well, it is safe to call changefileext on a string without extension. If you have dotted filenames, you might have to sanitize your code that that never happens (since that would lob off another segment of the string).

For dotted filenames without extension one needs to be careful of course.
TinyPortal © 2005-2018