Recent

Author Topic: Object Pascal, Memory Safety, the US Whitehouse and future programming  (Read 14948 times)

AlexK

  • Full Member
  • ***
  • Posts: 101
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #105 on: October 14, 2025, 02:22:40 pm »
Also currently variant parts cannot have managed types, and as String is probably the most commonly used type in Pascal, not being able to have string usable would be kinda bad.

Nobody expects Pascal with a lot of magic or obfuscation.
I would leave Variant as it is with simple types only.

For struct composition:
Code: Pascal  [Select][+][-]
  1. type
  2.   TChildRec = record
  3.     A: Integer;
  4.   end;
  5.  
  6.   TComposed = record
  7.     TChildRec; // just a record type without any keyword, like Golang
  8.     B: Double;
  9.   end;
  10.  

Warfley

  • Hero Member
  • *****
  • Posts: 2021
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #106 on: October 14, 2025, 04:38:23 pm »
Nobody expects Pascal with a lot of magic or obfuscation.
What makes you think that? Pascal is full of magic. As I said the probably most commonly used type is string, which is full of magic (reference counted, lazy copy on member access, implicit conversion from and to pchar, hidden codepages for formatting, etc.). Not to mention all the other magic in the language like other manged types (dynamic arrays, COM interfaces), all the magic that is hidden in classes (hidden pointers, allocators, etc.) and so much more.
Also notable mention for the magic variant record type "variant" which is a whole thing in itself.

But Managed types exist and are very common. So all the commonly used structures in the language should be able to handle them transparently. You can't have a major language feature that is just incompatible with another major language feature. That just does not make sense.

I would leave Variant as it is with simple types only.
Aside from the managed types, the other thing the merge request implements, that variant branches cannot overlap and that only one variant branch can be active at a time is also specified like that in the ISO 7185 Pascal Standard. The reason variants are so messy as they are right now is because of Borland building them messy like this in TP. Variants where never supposed to allow to use multiple branches at the same time. Note that not even C allows this. Accessing different fields of a union is UB in C. So TP inherited a very structured approach to either-or types from Pascal, and messed it up so much that even C is more restrictive

For struct composition:
Code: Pascal  [Select][+][-]
  1. type
  2.   TChildRec = record
  3.     A: Integer;
  4.   end;
  5.  
  6.   TComposed = record
  7.     TChildRec; // just a record type without any keyword, like Golang
  8.     B: Double;
  9.   end;
  10.  
Nah this creates ambiguity as you are allowed to shadow type names:
Code: Pascal  [Select][+][-]
  1. type
  2.   TChildRec = record
  3.     A: Integer;
  4.   end;
  5.  
  6.   TComposed = record
  7.     TChildRec: Integer; // Perfectly valid
  8.     B: Double;
  9.   end;
  10.  
So having an additional keyword makes it much clearer

AlexK

  • Full Member
  • ***
  • Posts: 101
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #107 on: October 15, 2025, 07:46:44 am »
I stand corrected.

This proposal makes sense and introduces type safety for variant records by using simple run-time checks.
https://gitlab.com/freepascal.org/fpc/source/-/merge_requests/822


But in "record composition" MR, embedding of advanced records should NOT make their methods/properties callable with a containing record, it's considered harmful.
https://gitlab.com/freepascal.org/fpc/source/-/merge_requests/498


Explanation from Golang.
Why struct composition("type embedding") can't be an alternative to subtyping(class based "oop"):
https://github.com/uber-go/guide/blob/master/style.md#avoid-embedding-types-in-public-structs

The only correct style is to tediously define methods for a containing record that explicitly call methods of inner record.
« Last Edit: October 15, 2025, 07:54:36 am by AlexK »

Warfley

  • Hero Member
  • *****
  • Posts: 2021
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #108 on: October 15, 2025, 12:30:21 pm »
The only correct style is to tediously define methods for a containing record that explicitly call methods of inner record.
So that if you change one implementation of the inner function you gain the great opportunity to change the definition of the outer function resulting in a bug. More code equals more abilities to skrew something up.

Thats what is often observed with functional languages. When Ericsson measured the robustness of their code base when translating from C++ to Erlang, they measured that the amount of bugs, as well as development time per line of code in Erlang was roughly the same as in C++, but because Erlang programs where 4-10 times smaller than the C++ equivalents, the overall number of bugs and the overall efficiency was 4-10x better.

So any additional code you have to write should be duely justified. There was this idea that boilerplate code helps to reduce errors. This was the major philosophy behind Java and even before that COBOL. But with modern research into programming language efficiency we know that this is simply not the case. The number of errors a programmer makes scales linearly with the amount of code they have to write, even if you don't have additional logic. More code => More bugs
« Last Edit: October 15, 2025, 12:32:36 pm by Warfley »

AlexK

  • Full Member
  • ***
  • Posts: 101
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #109 on: October 15, 2025, 02:39:34 pm »
The only correct style is to tediously define methods for a containing record that explicitly call methods of inner record.
So that if you change one implementation of the inner function you gain the great opportunity to change the definition of the outer function resulting in a bug.

On the contrary, a delegate implementation guards against possible bugs caused by a modification of inner method(somewhere far away in other unit).


Record composition. There are 2 ways.

1) Not promoting inner methods. Easy implementation, equally versatile.
2) Automatic promotion of inner record's methods to be callable by an outer record. (difficult, harmful)

Problems with the second way follow.
Two or more embedded records may have identical methods/properties.
You basically have to resolve Multiple Inheritance in this case.
Do note that embedding can have many levels and ALL the methods are promoted to the most outer record(bubble up).

Now you compile a call to a method on advanced record:

Code: Pascal  [Select][+][-]
  1. SomeRecord.SomeMethod; // more than one SomeMethod are promoted

Golang uses algorithm "The Rule of the Shallowest Depth".
Compiler creates a table with all the methods assigned a depth of embedding. Methods in the outer record are of depth 0. So it chooses SomeMethod with the lowest depth. As a programmer you are not sure which method wins unless you've remembered the hierarchy by exploring source code in different units.

If there are two SomeMethod with the same depth - compiler error "multiple inheritance conflict".

Outer record can embed two records from other libraries and one of those libraries in new version coincidentally introduces identical method with the same depth, and your program no longer compiles for some users. And it should be so rare that nobody is accustomed to fixing such cases, or chooses not to report a bug.
And so on.

Warfley

  • Hero Member
  • *****
  • Posts: 2021
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #110 on: October 15, 2025, 05:18:33 pm »
Problems with the second way follow.
Two or more embedded records may have identical methods/properties.
You basically have to resolve Multiple Inheritance in this case.
Do note that embedding can have many levels and ALL the methods are promoted to the most outer record(bubble up).
Thats in my implementation not an issue, because if you try to composite two records with colliding identifiers, the compiler will just throw an error and not let you do that. Alternatively, you can give the composition a name to disambiguate:
Code: Pascal  [Select][+][-]
  1. type
  2.   TChild1 = record
  3.     A: Integer;
  4.     B: Boolean;
  5.   end;
  6.  
  7.   TChild2 = record
  8.     A: Double;
  9.     C: Char;
  10.   end;
  11.  
  12.   TComposite = record
  13.     contains TChild1;
  14.     contains TChild2; // Error because no disambiguation possible
  15.   end;
  16.  
  17.   // Alternatively
  18.   TCompsite = record
  19.     contains c1: TChild1;
  20.     contains c2: TChild2; // Still a Warning, so you should avoid this as well, but not an error
  21.   end;
  22.  
  23. // usage
  24. var
  25.   c: TComposite;
  26. begin
  27.   c.c1.A := 42; // Because A is ambiguous, disambiguate with composition field c1
  28.   c.c2.A := 3.14; // Because A is ambiguous disambiguate with composition field c2
  29.   c.B := True; // No ambiguity, works fine
  30.   c.C := 'A'; // No ambiguity, works fine
This works for all member identifiers, if it's fields, consts, subtypes or methods.

So the typical diamant style multi inheritance is not an issue, because it's not inheritance. If you have collissions they either throw an error or a warning. So best is to not have collisions in the first place, but if you must, you can always disambiguate

PascalDragon

  • Hero Member
  • *****
  • Posts: 6191
  • Compiler Developer
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #111 on: October 16, 2025, 11:45:48 pm »
For some reason TObject.NewInstance is virtual, which means it can be overridden without calling default implementation in TObject.
https://lazarus-ccr.sourceforge.io/docs/rtl/system/tobject.newinstance.html

Correct. This way one can implement for example some memory pool or something if one desires.

Class constructors are not instance constructors. The later can be virtual as well. The former are only called once per program per type.

Yes, this behaviour introduced "Self can be Nil" to the language.

No, that is just what you assume. Self can be Nil, because the language describes no checks for Self to not be Nil (the instance checks that the compiler can automatically perform are part of the implementation, not the language). There is nothing that forbids you from calling a method on a Nil instance. It's valid code as far as the language is concerned. That more often than not this will lead to some crash or at least strange behavior is a different topic.

If some class overrides TObject.NewInstance and doesn't call inherited; then there's no guarantee that Self points to a valid memory block. So "Self can be Nil".

Another entrance for "Self can be Nil" in the language is this:
Code: Pascal  [Select][+][-]
  1. Writeln(SomeClass(nil).SomeMethod);

Compiler inserts a call to SomeMethod that will have Self equal to Nil.

To fix it without run-time check insertion compiler must advise/demand with error "You should wrap it in an IF block checking for Nil value".

No. The ability to pass have Self be Nil is a central part of how TObject.Free works.

I'll make it short: there is no interest to make any changes to how Nil works in relation to class-types.

AlexK

  • Full Member
  • ***
  • Posts: 101
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #112 on: October 17, 2025, 05:23:46 am »
Self can be Nil, because the language describes no checks for Self to not be Nil

The language is entirely defined by implementations.
There's no something like "C++ reference". ISO standards are not relevant.

If some implementation decides Memory Manager is pluggable(like TObject.NewInstance) with "Self can be Nil" as a consequence, then it's pragmatical to omit any checks of Self in general.
"Self can be Nil" and that's it.
I was exploring what leads to what and why.

After all, fast compilation must remain one of FreePascal's strengths.
Otherwise there would be not much practical sense of choosing FreePascal over something else, in some hypothetical situation.

Warfley

  • Hero Member
  • *****
  • Posts: 2021
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #113 on: October 17, 2025, 08:11:13 am »
What makes you think that NewInstance implies that self can be nil? Have you looked how NewInstance is used in objpas.inc? If it returns nil, the constructor will never be called. So if there is a real chance that your memory allocator may return nil, you must check if the result.of the constructor was nil. But if you do that you never call a single method with nil.

AlexK

  • Full Member
  • ***
  • Posts: 101
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #114 on: October 17, 2025, 09:05:19 am »
What makes you think that NewInstance implies that self can be nil?

Code: Pascal  [Select][+][-]
  1. class function newinstance : tobject;VIRTUAL;
  2.  
  3. class function TObject.NewInstance : tobject;
  4. var
  5.   p : pointer;
  6. begin
  7.   getmem(p, InstanceSize);
  8.   if p <> nil then
  9.     InitInstance(p);
  10.     NewInstance:=TObject(p);
  11. end;

TObject.Create docs:

"Create creates a new instance of TObject. Currently it does nothing (except allocating memory for the new instance).
Note that allocating the memory for the object instance happens in hidden code generated as part of every constructor, not only in TObject.Create. The hidden code calls NewInstance.
"

NewInstance is virtual, hence can be overriden and then all subtypes call custom NewInstance implementation.
It can possibly return Nil on failure.
I suppose that hidden call to NewInstance assigns Self.
This case looks like a deliberate choice in the language implementation to allow Self be Nil.


Other case where Self can be Nil I posted earlier, is the same as in C++.
The part before dot is not checked for Nil by compiler, it just inserts a call to SomeMethod with Self = Nil.
Code: Pascal  [Select][+][-]
  1. SomeClass(nil).SomeMethod;

In C++:
Code: C  [Select][+][-]
  1. SomeClass *a  = 0;
  2. a->someMethod();//bomb, "this" is null inside someMethod(), will crash only if "this" is accessed

When it's already a common consensus in the implementation that Self can be Nil,
TObject acquires Free method that's aware that Self can be Nil in implementation/language:
Code: Pascal  [Select][+][-]
  1. destructor TObject.Destroy;
  2. begin
  3. end;
  4.  
  5. procedure TObject.Free;
  6. begin
  7. // the call via self avoids a warning
  8. if self<>nil then
  9.   self.destroy;
  10. end;
« Last Edit: October 17, 2025, 10:06:55 am by AlexK »

cdbc

  • Hero Member
  • *****
  • Posts: 2466
    • http://www.cdbc.dk
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #115 on: October 17, 2025, 09:51:51 am »
Hi
I find it a great feature, that you can plugin your own memory-manager / -pool into TObject.NewInstance.
I've done that, with preallocating memory for a lot of items in a linked list and then doling it out via 'NewInstance' -- Works great  8)

I'll leave this discussion with a quote from @PascalDragon:
Quote
I'll make it short: there is no interest to make any changes to how Nil works in relation to class-types.
...Afterall, (s)he IS one of the implementors of the compiler!
Regards Benny
« Last Edit: October 17, 2025, 09:54:03 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6 -> FPC 3.2.2 -> Lazarus 4.0 up until Jan 2025 from then on it's both above &: KDE6/QT6 -> FPC 3.3.1 -> Lazarus 4.99

Thaddy

  • Hero Member
  • *****
  • Posts: 18344
  • Here stood a man who saw the Elbe and jumped it.
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #116 on: October 17, 2025, 10:27:17 am »
SomeClass(nil).SomeMethod; is a hardcast. Programmer resposibility applies.
Also when somemethod is a static class method the call should succeed. Also in C++.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. type
  3.   Someclass = class
  4.   public
  5.   class function SomeMethod:integer;static;
  6.   end;
  7.  
  8.   class function SomeClass.SomeMethod:integer;
  9.   begin
  10.     Result := random(10);
  11.   end;
  12.  
  13. begin
  14.   writeln(SomeClass(nil).SomeMethod);
  15. end.

This is just to show that, given a certain context, it is legal to call methods on a nil "instance".

« Last Edit: October 17, 2025, 10:42:09 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

d2010

  • Full Member
  • ***
  • Posts: 230
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #117 on: October 17, 2025, 10:42:02 am »
SomeClass(nil).SomeMethod; is a hardcast. Programmer resposibility applies.
Also when somemethod is a static class method the call should succeed. Also in C++.
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. type
  3.   TSomeclass = class
  4.   public
  5.   class function SomeMethod:integer;static;
  6.   end;
  7.  
  8.   class function TSomeClass.SomeMethod:integer;
  9.   begin
  10.     Result := random(10);
  11.   end;
  12.  
  13. begin
  14.   writeln(TSomeClass(nil).SomeMethod);
  15. end.

This is just to show that, given a certain applicability, it is legal to call methods on a nil "instance".
Easy-Question=
Please,please the "TSomeclass "  is verry -good, but, but  the
"TSomeclass " is compatibilie with C++ or C+external.dll. or Vc2010+C++??
Hard-Question=
Can you make other version of "TSomeclass " compatibile   with C#?

AlexK

  • Full Member
  • ***
  • Posts: 101
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #118 on: October 17, 2025, 10:44:52 am »
SomeClass(nil).SomeMethod; is a hardcast. Programmer resposibility applies.
Also when somemethod is a static class method the call should succeed. Also in C++.

Type casts are like in C, not type safe. It has to be remembered.

Self in class methods:
"Inside a class method, the Self identifier points to the VMT table of the class."
https://www.freepascal.org/docs-html/ref/refsu28.html

Thaddy

  • Hero Member
  • *****
  • Posts: 18344
  • Here stood a man who saw the Elbe and jumped it.
Re: Object Pascal, Memory Safety, the US Whitehouse and future programming
« Reply #119 on: October 17, 2025, 10:45:41 am »
C# is not my  forte, but I can do it for C++. Wait a moment, launching vscode.
Code: C  [Select][+][-]
  1. class TSomeClass {
  2. public:
  3.     static int SomeMethod();
  4. };
  5.  
  6. int TSomeClass::SomeMethod() {
  7.     return std::rand() % 10;
  8. }
The latter is actually a bit more typesafe.
Alternatively something horrible like this:
Code: C  [Select][+][-]
  1. ((TSomeClass*)nullptr)->SomeMethod()
« Last Edit: October 17, 2025, 10:51:13 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

 

TinyPortal © 2005-2018