Lazarus

Miscellaneous => Suggestions => Topic started by: damieiro on September 23, 2021, 07:35:20 pm

Title: Really VOID Class
Post by: damieiro on September 23, 2021, 07:35:20 pm
In the class model of Free Pascal, derived from Delphi one, we have
TObject.  -> https://wiki.lazarus.freepascal.org/TObject
And all derives from it.

I think it's desirable some kind of lightweight class without all the bloat like a
TVoidClass and TObject should derive from the TVoidClass.
TVoidClass shoud be really void (not constructor, destructor, anything), or by default a minimal set.
Even things could have more steps

TVoidClass (a really void one) -> THeapClass (with default constructor and destructor on heap) -> Tobject

This would give full delphi/Embarcadero compliance and could be the way to have a full control on the class.

Embedded systems will make use of these instead of not developed stack object model and when some improvements were doing on the classes, it will be of use for void ones...


*TVoidClass,THeapClass are example names... not the coolest ones :D
Title: Re: Really VOID Class
Post by: marcov on September 23, 2021, 07:41:46 pm
Moreover what they are exactly good for is unclear  too.
Title: Re: Really VOID Class
Post by: damieiro on September 23, 2021, 07:53:46 pm
Well, i think is good for some reasons:

1.- Less memory use. A void class has minimal memory footprint.

2.- Less side-effects. For example if you don't define an AfterConstruction it will not be called as TObject does. If not a create constructor defined, it cannot be invoked for a descendant class, etc..

3.- Not  the main idea of this, but if the model evolves, a void class could help to derive on how to make the memory allocation, and being a stack or heap or other method of allocation being a pure implementation of their descendant classes. For example a Vector class or Sprite class, could use a GPU memory model.

4.- For actually implementation, a TObject would be a descendant from a void.

5.- Are we really using all the data of TObject in our code? I think not.

6.- Could help C++ portability and viceversa. C++uses a "semivoid" . Even a TCpp class could descend from a Void one.

7.- I think on a void class as a tool, not as a trouble ;)

I think in a lot of posibilites, but all are derived from a basic void class..
Title: Re: Really VOID Class
Post by: Awkward on September 23, 2021, 08:14:25 pm
maybe easier to use standard 'object' type then?
Title: Re: Really VOID Class
Post by: damieiro on September 23, 2021, 08:28:35 pm
Object would be ok, but It's not valid idea, because.

1.- Object is a stack type one, not heap. (can be heap, but without sugar sintax)
2.- Object is deprecated in delphi and only maintained in fpc, no further development
3.- Object doesn't accept all the syntax and has no sugar-syntax implemented.

The dual model Object/class i think it's a bad idea. And heap classes has it's own advantages.

Even with object, it should be a void Class for completness (and the explained advantages)

Title: Re: Really VOID Class
Post by: Awkward on September 23, 2021, 08:52:18 pm
dual model is bad idea? say that to advanced record creators! THAT was a bad idea, to make records with bonuses if we has objects already. And your Void classes will be little more than unuseful coz direct descendants will be not compatible with TObject descendants
Title: Re: Really VOID Class
Post by: damieiro on September 23, 2021, 10:08:36 pm
Quote
dual model is bad idea? say that to advanced record creators! THAT was a bad idea, to make records with bonuses if we has objects already.

Dual model without full support *IS* bad idea. Yes. Better a full supported one.
And a stack object isn't a heap class. Well it is with manual management like any type. But well, a void class could be (with some tweaking) be the same as a object and interchangeable in pointers...

 
Quote
And your Void classes will be little more than unuseful coz direct descendants will be not compatible with TObject descendants
Which is intended. Do you need a Tobject descendand?. Declare a TMyClass=class(TObject).
Do you need a Void class descendant? Declare TMyClass=class(Void) or TMyClass=voidclass because TMyClass=class, it's taken as class(TObject).. so we can't use it.

But i do not need that over defined and oversized TObject. So give me the raw object to interact with this.

When you declare a Tcar=class... Do you use...
...DefaultHandler()?
...InstanceSize?
...GetInterface()?.
for example.
would like that your new class should not answer to .create or .destroy? (not fail safe)

This TObject in all his glory

Code: Pascal  [Select][+][-]
  1.    TObject = class
  2.        public
  3.           { please don't change the order of virtual methods, because
  4.             their vmt offsets are used by some assembler code which uses
  5.             hard coded addresses      (FK)                                 }
  6.           constructor Create;
  7.           { the virtual procedures must be in THAT order }
  8.           destructor Destroy;virtual;
  9.           class function newinstance : tobject;virtual;
  10.           procedure FreeInstance;virtual;
  11.           function SafeCallException(exceptobject : tobject;
  12.             exceptaddr : codepointer) : HResult;virtual;
  13.           procedure DefaultHandler(var message);virtual;
  14.  
  15.           procedure Free;
  16.           class function InitInstance(instance : pointer) : tobject; {$ifdef SYSTEMINLINE} inline; {$endif}
  17.           procedure CleanupInstance;
  18.           class function ClassType : tclass;{$ifdef SYSTEMINLINE}inline;{$endif}
  19.           class function ClassInfo : pointer;
  20.           class function ClassName : shortstring;
  21.           class function ClassNameIs(const name : string) : boolean;
  22.           class function ClassParent : tclass;{$ifdef SYSTEMINLINE}inline;{$endif}
  23.           class function InstanceSize : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  24.           class function InheritsFrom(aclass : tclass) : boolean;
  25.           class function StringMessageTable : pstringmessagetable;
  26.  
  27.           class function MethodAddress(const name : shortstring) : codepointer;
  28.           class function MethodName(address : codepointer) : shortstring;
  29.           function FieldAddress(const name : shortstring) : pointer;
  30.  
  31.           { new since Delphi 4 }
  32.           procedure AfterConstruction;virtual;
  33.           procedure BeforeDestruction;virtual;
  34.  
  35.           { new for gtk, default handler for text based messages }
  36.           procedure DefaultHandlerStr(var message);virtual;
  37.  
  38.           { message handling routines }
  39.           procedure Dispatch(var message);virtual;
  40.           procedure DispatchStr(var message);virtual;
  41.  
  42.           { interface functions }
  43.           function GetInterface(const iid : tguid; out obj) : boolean;
  44.           function GetInterface(const iidstr : shortstring;out obj) : boolean;
  45.           function GetInterfaceByStr(const iidstr : shortstring; out obj) : boolean;
  46.           function GetInterfaceWeak(const iid : tguid; out obj) : boolean; // equal to GetInterface but the interface returned is not referenced
  47.           class function GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
  48.           class function GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
  49.           class function GetInterfaceTable : pinterfacetable;
  50.  
  51.           { new since Delphi 2009 }
  52.           class function UnitName : {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
  53.           class function QualifiedClassName: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
  54.           function Equals(Obj: TObject) : boolean;virtual;
  55.           function GetHashCode: PtrInt;virtual;
  56.           function ToString: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};virtual;
  57.        end;                      
  58.  
  59. end;


TObject is half bloated, half hacky and full oversized for nearly 99.9% of uses.
Note: this is not a dev blame. It's being as this for historical reasons, but a raw heap class is, for me, a desirable one.
Title: Re: Really VOID Class
Post by: PascalDragon on September 24, 2021, 09:16:56 am
I think it's desirable some kind of lightweight class without all the bloat like a
TVoidClass and TObject should derive from the TVoidClass.

There is no desire to change or extend the object model. If you need something lightweight use object.

TObject is half bloated, half hacky and full oversized for nearly 99.9% of uses.

First: if smartlinking is enabled (default on Windows) any non virtual methods of TObject are removed.
Second: nothing there is hacky, it's simply a type that makes use of the low level information generated by the compiler, that's why it's a core type of the RTL.
Third: It's not oversized for 99.9% of uses, because the LCL makes use of nearly all the functionality provided by TObject to provide all the functionality we know and love and LCL usage is clearly more than 0.1%.
Title: Re: Really VOID Class
Post by: alpine on September 24, 2021, 10:41:05 am
IMHO advanced records aren't a bad idea. See https://forum.lazarus.freepascal.org/index.php/topic,46306.msg329970.html#msg329970

Such auto objects gives some advantages that C++ has by default.
Title: Re: Really VOID Class
Post by: damieiro on September 24, 2021, 12:33:18 pm
Quote
I think it's desirable some kind of lightweight class without all the bloat like a
TVoidClass and TObject should derive from the TVoidClass.

There is no desire to change or extend the object model. If you need something lightweight use object.


It's not the same and you know it. Object won't be developed further. It has not the sugar candy syntax. It's stacked, not in heap.. Same you said that it's a bad idea being with objects because their limitations can't be offered as a similar solution. It's not the same and it hasn't the same priority. And are useless in Delphi (embarcadero deprecated them).
And it's a bad idea two types of coding (for objects) and for TObjects. Duality for same things is allways bad idea. Telling that use object instead of making a voidheap one is a straw man argument. https://en.wikipedia.org/wiki/Straw_man
This argument will be acceptable if object would hace exactly the same functionality, nor less as a heap object and being sugar-sintax in heap and fully mainteinance. Object its even an antecesor of record with methods. It's an ancient way of doing things and not a supported one. Would you advise to ANY who is starting with fpc to use objects or classes? You will answer: go for classes. So no room for : Go for objects as an advice.

Quote
TObject is half bloated, half hacky and full oversized for nearly 99.9% of uses.

First: if smartlinking is enabled (default on Windows) any non virtual methods of TObject are removed.
Second: nothing there is hacky, it's simply a type that makes use of the low level information generated by the compiler, that's why it's a core type of the RTL.
Third: It's not oversized for 99.9% of uses, because the LCL makes use of nearly all the functionality provided by TObject to provide all the functionality we know and love and LCL usage is clearly more than 0.1%.

First, smartlinking only removes interface ones (below). The other are class functions that could viewed as compiler constructs and being out of class scope or in the class scope (but this is taste) -> This is RTL not a part of a class. And should be the class designer if use it or other compiler info. Give TObject as is, and let a void one to be generated as object with the same funcionality as object and fully maintained. And it's how an academic OOP should be. Why is this change problematic?. It's making the actual model to an universal, fully academic supported and fully compatible with existing code. This can have many views. One can have (by sugar sintax) define that class-RTL methods could be in all classes (like in a void class)-> example
(MyAscendant:=TFooClass.ClassParent) or as (MyAscendant:=ClassParent (TFooClass); And i could argue the later can have advantages too. could you do this with an object. NO.
But the main question is why is difficult or not viewed as neccesary a Void object which should be the academic root to start working and gives tools to do other things and not Lazarus-delphi ones? I think it's a autoimposed limitation.

Second, better not doing a smartlinking job when you don't need to smart link if better defined.


Not too much gain...
TObject = class
       public
          { please don't change the order of virtual methods, because
            their vmt offsets are used by some assembler code which uses
            hard coded addresses      (FK)                                 }
          constructor Create;
          { the virtual procedures must be in THAT order }
          destructor Destroy;virtual;
          class function newinstance : tobject;virtual;
          procedure FreeInstance;virtual;
          function SafeCallException(exceptobject : tobject;
            exceptaddr : codepointer) : HResult;virtual;
          procedure DefaultHandler(var message);virtual;
 
          procedure Free;
          class function InitInstance(instance : pointer) : tobject; {$ifdef SYSTEMINLINE} inline; {$endif}
          procedure CleanupInstance;
          class function ClassType : tclass;{$ifdef SYSTEMINLINE}inline;{$endif}
          class function ClassInfo : pointer;
          class function ClassName : shortstring;
          class function ClassNameIs(const name : string) : boolean;
          class function ClassParent : tclass;{$ifdef SYSTEMINLINE}inline;{$endif}
          class function InstanceSize : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
          class function InheritsFrom(aclass : tclass) : boolean;
          class function StringMessageTable : pstringmessagetable;
 
          class function MethodAddress(const name : shortstring) : codepointer;
          class function MethodName(address : codepointer) : shortstring;
          function FieldAddress(const name : shortstring) : pointer;
 
          { new since Delphi 4 }
          procedure AfterConstruction;virtual;
          procedure BeforeDestruction;virtual;
 
          { new for gtk, default handler for text based messages }
          procedure DefaultHandlerStr(var message);virtual;
 
          { message handling routines }
          procedure Dispatch(var message);virtual;
          procedure DispatchStr(var message);virtual;
 
          { interface functions }
          function GetInterface(const iid : tguid; out obj) : boolean;
          function GetInterface(const iidstr : shortstring;out obj) : boolean;
          function GetInterfaceByStr(const iidstr : shortstring; out obj) : boolean;
          function GetInterfaceWeak(const iid : tguid; out obj) : boolean; // equal to GetInterface but the interface returned is not referenced
          class function GetInterfaceEntry(const iid : tguid) : pinterfaceentry;
          class function GetInterfaceEntryByStr(const iidstr : shortstring) : pinterfaceentry;
          class function GetInterfaceTable : pinterfacetable;

 
          { new since Delphi 2009 }
          class function UnitName : {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
          class function QualifiedClassName: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};
          function Equals(Obj: TObject) : boolean;virtual;
          function GetHashCode: PtrInt;virtual;
          function ToString: {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}ansistring{$else FPC_HAS_FEATURE_ANSISTRINGS}shortstring{$endif FPC_HAS_FEATURE_ANSISTRINGS};virtual;
       end;                     
 
end;



Title: Re: Really VOID Class
Post by: Thaddy on September 24, 2021, 12:47:48 pm
1.- Object is a stack type one, not heap. (can be heap, but without sugar sintax)
2.- Object is deprecated in delphi and only maintained in fpc, no further development
3.- Object doesn't accept all the syntax and has no sugar-syntax implemented.
1. So is C++ did you know that?
2. There are reports at Embarcadero to deprecate deprected for objects
3. True, but still much of it

If you are reluctant to use objects you can always use class abstract.
On small, memory pressured, embedded platforms I would go for either Object or fully procedural code.
Title: Re: Really VOID Class
Post by: damieiro on September 24, 2021, 12:48:32 pm
IMHO advanced records aren't a bad idea. See https://forum.lazarus.freepascal.org/index.php/topic,46306.msg329970.html#msg329970

Such auto objects gives some advantages that C++ has by default.

Advanced records it's a good idea. It's even a modern idea. And perhaps (i do not know) better implemented in FPC that object.

But advanced records has other target. These goes for encapsulation, but not for inheritance.
And advanced records use the same memory schema and syntax for all.

But classes and object were two foundryes for same target: A OOP model. C++ has ONE model for ONE target. We have TWO models (one being deprecated slowly) and other with a healthy future.
But TObject is not Zero-Starting Object as their stack counterpart.
And for that reason one cannot do auto objects or other way of doing things. Even their method like AfterConstructions cannot be intercepted for debug (which is really weird).
But the worse is that i think that argumentation (with more or less academical aproach or things like that) is, for me, a bit dissapointing.
For example, the good reasons for having a void object class or intercept/callback a clearly debug-targeted method (as after  construction) will be more "operable" if embarcadero does their own interception. Then we go for support it. If not, it won't be. And i would like to thing more on which is convenient to have and will give a better foundation for future.

It's like the operator mess options: A bad idea if you have a really equivalent way to do it. And a good idea if this could give useful hint to compiler. Not a pascal/c syntax flame. Simply put it what gives to you.
A void object gives you a raw object with all the power. And with the advantage that are a good existing foundry to mimic like TObject. And with nearly Zero Cost.

My view /INMHO:

Advanced records: It's ok. Targetting for encapsulation, not inheritance.  Has its room

Object/TObject: Two things to target the same, first deprecated, the second less academical by autoimposing limits, but far better developed and supported. So the future of a void OOP start is with TObject. There is not other way to aproach actually.

Title: Re: Really VOID Class
Post by: damieiro on September 24, 2021, 12:55:38 pm
Quote
    1.- Object is a stack type one, not heap. (can be heap, but without sugar sintax)
    2.- Object is deprecated in delphi and only maintained in fpc, no further development
    3.- Object doesn't accept all the syntax and has no sugar-syntax implemented.
Quote
1. So is C++ did you know that?
2. There are reports at Embarcadero to deprecate deprected for objects
3. True, but still much of it

If you are reluctant to use objects you can always use class abstract.
On small, memory prssured, embedded applications I would go for either Object or fully procedural code.

1.- This is C++ basis. Do you know that i know that? -> More than 30 years with pascal/c/c++. I started with Z80/8088 assembly... And here are people with far more experience. We are all veterans if we are discussing a teoretical model and their deep consecuences.. Please, do not treat others as beginners. And for the sake of the argument. Yes this is a C++ model. A ancient one and a robust one. What are wrong if we can do C++ things in a pascal syntax?. Is it some kind of grial not taking any idea that can be useful if not pascal existant (which is not true: really we are with Delphi-class)?
We can say that TP-Object is c++ too. Or we can agree that there is a academic model and implementations. And a void/root object is nearer to the teoretical. And not only c does it. Pascal does it with TP-Object but it won't give their extension and borland were for the class one..
2.- Embarcadero is not my way. You shouldn't use a languaje construct that it's not safe their continuity or depends on a private company. That was the Borland story.. Want we to repeat same mistake?
3.- But still bad supported and i think we are making a zombi. Let object dead (or deprecate gently) and then we can go for a Class complete model that should allow lightweight things or tinkering. And remove all dual mainteinance of compiler. With more tools we can construct even more tools. If you only give me a plastic hammer for not harming me, i won't do the job.

Quote
If you are reluctant to use objects you can always use class abstract.
And it will be marvellous if i can declare TMyAbstractClass = class (ReallyEmptyVoidClass) and then define it and it only occupies their vmts and tables with the minimal operational info. And less memory movement.. and better maintenance than procedural-only.

Quote
On small, memory pressured, embedded platforms I would go for either Object or fully procedural code.
Well, in this scenario i go for only procedural (better say:structured) paradigm and not mix with OOP paradigm in Pascal because i couldn't rely on their future. If a void class or similar c++ construct (which should be obvious to put on top of any hierarchy like object) i would prefer oop if the memory pressure is not very very critical. This applies to C++  too.



Title: Re: Really VOID Class
Post by: PascalDragon on September 24, 2021, 01:32:44 pm
But the main question is why is difficult or not viewed as neccesary a Void object which should be the academic root to start working and gives tools to do other things and not Lazarus-delphi ones?

Simply because it's not necessary. If you need something lightweight you can use records or objects. There is simply no need to introduce yet another concept.

Not too much gain...

Even then the methods exist only once inside the binary. Yes, the virtual methods are referenced in each VMT, but each VMT only exists once per class type. There are much bigger size related problems than that in the RTL (e.g. that the whole managers for strings, memory, threads, etc. can't be smartlinked).
Title: Re: Really VOID Class
Post by: MarkMLl on September 24, 2021, 02:04:25 pm
On small, memory pressured, embedded platforms I would go for either Object or fully procedural code.

Let's face it, conventional wisdom has it that the entire concept of a heap is incompatible with resource-constrained systems. OK so you can deallocate locally in the reverse order to allocation... but at that point you might as well be putting stuff on the stack. Except of course that the stack has its own hazards if the platform can't increase its size on demand. Which is something that the majority of CS graduates find hard to stomach, which makes them fundamentally unsuited to embedded system work.

Elsewhere this morning I spotted this:

Quote
Meanwhile the DOS version uses .NET Core’s ability to produce self-contained executables along with some very significant tricks to pare down the size of the finished program from many megabytes to an eventual DOS-suitable 27k.
https://hackaday.com/2020/02/09/c-the-language-for-all-platforms-now-including-windows-3-11-and-dos/

Allowing that that was probably a minimal "Hello, World!" it would still be vastly excessive on a classical embedded system. But it does indicate the extent to which at least some modern tools developers treat ideas of economy and efficiency with contempt... all in the name of "accelerating the development cycle" which ultimately means that the consumer can watch his cat videos with a different background colour.

MarkMLl
Title: Re: Really VOID Class
Post by: damieiro on September 24, 2021, 02:12:51 pm
Quote
But the main question is why is difficult or not viewed as neccesary a Void object which should be the academic root to start working and gives tools to do other things and not Lazarus-delphi ones?

Simply because it's not necessary. If you need something lightweight you can use records or objects. There is simply no need to introduce yet another concept.

No. The concept is the SAME: OOP fully or not fully. TObject is a SUBSET of a more academical OOP. It starts with a branch instead of the void node. Simply make the node and then derive TObject. If the FreePascal model is robust, it could be done easily without tinkering:
  Practical examples: How do you make a managed Object with TObject? How will you do a smart pointer or things like that with a really big TObject? Object cannot do the job and TObject cannot is very big for a simple data type. And yes, it could be done with advanced records, but... it's a bit messy. In this scenarios, speed an minimal memory footprint are neede (it would be ironical thay TObject would be really bigger than the smart pointer declaration).
  We have really little managed types and this kind of limitation is, INMHO by-far the starting point of TObject. There are a lot of other examples. We have a top speed compiler, a fantastic foundation (TObject and sugar sintax) and we are voluntary cutting a hand and a feet for nothing. We are looking downwards tobject, but not upwards to the logical root and complete the model and terminate dual object-tobject system.
Quote
Not too much gain...

Even then the methods exist only once inside the binary. Yes, the virtual methods are referenced in each VMT, but each VMT only exists once per class type. There are much bigger size related problems than that in the RTL (e.g. that the whole managers for strings, memory, threads, etc. can't be smartlinked).

Figure that you want to manage very simple structures (like smart pointers). You can only do it in a effective way if making a Object with internally would have an array of these or going for non oop struct, but not a smart pointer by declaration because of the bloat in OOP.
And yes, there is only one on the binary, but multiplied by vmt and a with indirection a lot of times and multirreferenced without sense. A nightmare if looking for parallelisation or other internal speed-ups.

Do the calculus:
how many bytes is the minimal size of a TObject? How many indirections even for a simple task like constructing it?. Then ask same for a void one (a similar c++ example). Leave out the class constructors (you can take these as system procedures or advanded records) and all out of these (it could be redeclared by derivation).
 
But the main gain is not that.
The main gain is to eliminate dual mainteinance of object/tobject and the aperture of a powerful tool with full compatibility (really even more potent that the c++ counterpart, more mainteinable and similar or better speed).

Please. Figure how to implement it and as compiler dev you will see a lot of sinergies. Like the academical view find.



Title: Re: Really VOID Class
Post by: alpine on September 24, 2021, 02:34:51 pm
On small, memory pressured, embedded platforms I would go for either Object or fully procedural code.

Let's face it, conventional wisdom has it that the entire concept of a heap is incompatible with resource-constrained systems. OK so you can deallocate locally in the reverse order to allocation... but at that point you might as well be putting stuff on the stack. Except of course that the stack has its own hazards if the platform can't increase its size on demand. Which is something that the majority of CS graduates find hard to stomach, which makes them fundamentally unsuited to embedded system work.
*snip*
As I've recently realized, there isn't a strict necessity to use classes on the heap:
https://forum.lazarus.freepascal.org/index.php/topic,54470.msg404786.html#msg404786
with the only trouble that the class InstanceSize is not well known at compile time to declare storage with the exact size.

Anyway, I can't understand exactly where is the problem with object  :(
Title: Re: Really VOID Class
Post by: damieiro on September 24, 2021, 07:48:39 pm
As I've recently realized, there isn't a strict necessity to use classes on the heap:
https://forum.lazarus.freepascal.org/index.php/topic,54470.msg404786.html#msg404786
with the only trouble that the class InstanceSize is not well known at compile time to declare storage with the exact size.
Anyway, I can't understand exactly where is the problem with object  :(

Well, object is better defined than their heap counterpart. It starts from a void declaration and it works fine... But.. and it's a big BUT.
1.- It's deprecated in delphi and does't work in embarcadero compiler.
2.- It's only maintained in fpc, but not will receive new features.
So, you risk coding for a future deprecated candidate.

But if object will be never be deprecated, it will need to be actualized to:
1.- Accept sugar syntax that classes had for heap allocation (and not playing with classical pointers operation).
If you use them directly (e.g. a TMyObject) then it's fully located where you declared (e.g. global variable or stack). But to instantiate them using New a things like that, thus they'd reside on the heap. Classes hide this allocation by syntax.
2.- Full operator overload: You can use global operator overloads, but not member operator overloads which are necessary to support custom operators inside generics. Allthough objects can use generics this actual-compiler limitation doesn't allow to use generic to their potential.
3.- Polimorphism with TP-Object is posible, but not as natural as with a heap class. Very annyoning
4.- A funny thing it's that TP-Object would be better candidate for managed types (less bloat) than some kind of auto-classes, but if i would expect some managed types with oop i will need a heap void class, not tobject and tp-object (AFAIK) in the managed ones. It could be interesting a TP-Object a managed type. It will take the "sugar" of advanced records and being a full-capable allocated class without explicit allocation. I left this as an idea... But it's not in the road the enrichment of tp-object... This will (perhaps) make a revival of tp-object.

The fact through object is it were the 1st version of OOP in pascal, classes their 2nd edition and object with all new things (like generics of managed types) will be barely supported and allways the last one behind classes.
And it hides the main discusion. The class model (the really advanced, developed, and up-to-date model) when go for a void class throws to object, but not to their natural solution which is a class object and not a TP-object
Title: Re: Really VOID Class
Post by: alpine on September 24, 2021, 10:22:51 pm
@damieiro,
Regarding your post #12, I assume you're quite familiar with the Delphi development through the decades (and hence FPC, which one of goals is to be compatible).

Thus I wonder why you'd expect FPC to be a (very)good fit for embedded development. It (TP/Delphi) evolved from an educational language to a powerful RAD/GUI/DB tool. One cannot expect it to be equally good in both.

Personal opinion:
Embedded system is quite a vague term. If the meaning is for bare-metal, no OS environment, I'd go for pure-C, no OOP at all. At the other hand, if the system has enough RAM to run your app on the top of an OS, a few extra entries into the VMT will not be such a burden.

There is lot of other things to take care for FPC to be a good for embedded tool, IMHO the class(TObject) is further in the list.

So, I would use the tools for their intended purpose...

BTW, some people use Python for embedded development  :o
Title: Re: Really VOID Class
Post by: damieiro on September 25, 2021, 12:35:30 pm
Hi y.ivanov

Well, and this is a personal taste, i think that a common feeling is that pascal is somewhat higher level than C.

But it's not their primary design. Like C, it's though as a that no other lower languaje (except pure assembly) be under it.

For embeded systems, you will go without classes, and a structured C or pascal would do the job. And specific thinking on the platform. So, I fully agree with you and MarkMLI
But for some enviroments, a lightweigh object aproach could help. It's simply to have the tools. And in some cases, you will manage the memory, not the compiler. And yes, this kind of low level is also pascal an c, not  C Only.

If we were some decades ago, the turbo pascal and turbo c were similar in performance and target. Same as wirth aproach. So there is not a lower C than Pascal. It's more low level C software than in pascal, and i think that we are subtle, removing the low level tools, that are Pascal too.

Pascal is a low level with strong types and better aproach to avoid mistakes and gives (INMHO) better foundation than C. Then, for low level, it could do the job same or better than C or C++ (less error prone).

I think we are mixing syntax with power. A void class gives a power tool to the developer. Perhaps useful, perhaps useless, but gives the basic foundation. Tobject it's too big. And object it's not properly maintained (well the effords won't be here).

I think, for example (this could be as a general view) that if i would like to do a smart pointer (a low-middle level aproach) in C++ i can do it with oop paradigm or structured. In FPC i cannot do it because of the overbloat with classes. But i can, ironically, make my own memory manager, to, for example, redirect all heap calls to stack calls or my own internal memory.

Embedded systems is not the main theme of the proposal. It's an example. The main theme it's to have the tool,and a durable one. And i agree, it's a vague term.

Title: Re: Really VOID Class
Post by: Thaddy on September 25, 2021, 01:55:01 pm
Zero Cost.
Except bow and arrow notation to access the heap parts.... ->
Title: Re: Really VOID Class
Post by: MarkMLl on September 25, 2021, 02:28:14 pm
Pascal is a low level with strong types and better aproach to avoid mistakes and gives (INMHO) better foundation than C. Then, for low level, it could do the job same or better than C or C++ (less error prone).

As well as the moderately-strong typing, there are a couple of other distinguishing features.

The first is that Pascal allows up-level addressing (which changes the behaviour of the stack frame) and in its later incarnations supports explicit and implicit finalisation code (which changes the behaviour of the code blocks).

The second is that Pascal, as described by J&W, had implicit support for string operations including implicit I/O operations. And I'd emphasise that this was long before people knew how to define library interfaces which could accommodate that sort of thing: a minor change to I/O semantics required a compiler rebuild.

I would also say that the intention of Pascal was to be a viable successor to ALGOL-60, in direct competition to ALGOL-68. However unlike its immediate predecessor ALGOL-W it explicitly broke ALGOL syntax: Wirth was basically washing his hands of ALGOL because he felt slighted by the standardisation process (I blame John McCarthy for that).

I do not accept the characterisation of Pascal as a "toy" or "teaching" language, since it basically had the same functionality as ALGOL-60 as defined. And just as at least one ALGOL-60 dialect was used for systems programming (by Burroughs), at least one Pascal dialect was used for systems programming (by Cray).

And I particularly point a finger there at people who criticise Pascal's lack of explicit named-file handling and text output formatting since neither of those was defined by core ALGOL-60, which didn't stop various derivatives borrowing e.g. FORTRAN's standardised formatting strings.

Quote
I think we are mixing syntax with power. A void class gives a power tool to the developer. Perhaps useful, perhaps useless, but gives the basic foundation. Tobject it's too big. And object it's not properly maintained (well the effords won't be here).

I presume that what you're really talking about here is TVoid as an ultimate ancestor? (Don't peer into it, it's empty.) "Void class" is a bit close in naming to "nullable instances" etc.

I think I'd point out that Advanced Records might be worth considering as a lightweight alternative to both objects and classes... in fact I believe that at one time Wirth was wont to rant about how nothing done by OO programming couldn't be similarly achieved by records in Oberon.

And I'd suggest that if you really need an ultimate TVoid then the nature of an open-source project like FPC means that you can write and submit an implementation as a patch, but I am troubled by the comments in the current TObject(?) implementation that some of the VMT offsets are "graven in stone" due to the requirements of supporting assembler code. And if you weren't satisfied by the reaction to your patch, you could obviously fork the project.

Quote
I think, for example (this could be as a general view) that if i would like to do a smart pointer (a low-middle level aproach) in C++ i can do it with oop paradigm or structured. In FPC i cannot do it because of the overbloat with classes. But i can, ironically, make my own memory manager, to, for example, redirect all heap calls to stack calls or my own internal memory.

I think you can do it by overloading the assignment operator, specifically defining Tsomething := PTsomething. However this is likely to get extremely messy since as I understand it the := operator is used for both explicit assignment and implicit casting... I'd be happier to see those distinguished and also to see ^ and possibly @ as being overloadable.

MarkMLl
Title: Re: Really VOID Class
Post by: marcov on September 25, 2021, 03:00:37 pm
Do the calculus:
how many bytes is the minimal size of a TObject?

Code: [Select]
{$mode delphi}

uses classes;
var x : tobject;
begin
 x:=tobject.create;
writeln(x.instancesize);
end.

Prints "4" on a 32-bit system, which is due the VMT pointer that is needed to make the difference between objects and records. Anything without it is not an object but a record/struct.

Note that in Delphi the instance size is afaik double that due to the monitor field. (which I still don't understand why they made it global rather than part of some sync primitives ancestor, but I don't comprehend their use entirely)

Quote
How many indirections even for a simple task like constructing it?. Then ask same for a void one (a similar c++ example).

No idea. Many probably. But we are talking about classes/OOP here, and not bare structs. So there needs to be some functionality in there somewhere.

Quote
But the main gain is not that.
The main gain is to eliminate dual mainteinance of object/tobject and the aperture of a powerful tool with full compatibility (really even more potent that the c++ counterpart, more mainteinable and similar or better speed).

Eliminating Dual maintenance, full compatibility and extensions are three things that are probably mutually exclusive.

Quote
Please. Figure how to implement it and as compiler dev you will see a lot of sinergies. Like the academical view find.

We don't see the synergies, and to be frank, you are not doing a really good job advocating them either. A lot of sentiment and spin, but low on facts and design.

I've read three pages of replies, and I have seen nothing but throwing random C++ functionality about and some deep seated belief that there should be something below tobject.
Title: Re: Really VOID Class
Post by: korba812 on September 25, 2021, 03:02:00 pm
how many bytes is the minimal size of a TObject?
The size of the empty class data (like TObject) is exactly the same as the data size of an empty classic object - it's just the size of a pointer to the VMT.  How classes and objects would work without a VMT?
Title: Re: Really VOID Class
Post by: Blade on September 25, 2021, 04:48:48 pm
dual model is bad idea? say that to advanced record creators! THAT was a bad idea, to make records with bonuses if we has objects already. And your Void classes will be little more than unuseful coz direct descendants will be not compatible with TObject descendants

Advanced Records is a great idea.  Various programmers don't want the syntax baggage associated with Class-based OOP or various aspects of OOP such as inheritance (where it can be unclear what has been inherited).  Note- keep in mind that records/advanced records can do direct inheritance, that is a record contained within another record.

Object Pascal's situation is a very good one, because by having records, advanced records, objects, and classes then the programmer has greater freedom to choose what they believe will be best for them.  It helps removes OOP style spaghetti or unnecessary complexity where possible.

Usually the only situations where a programmer will be forced or obligated to use something they don't like is because they have a boss who has mandated it must be done a certain way, their company is paying them to do so, and they don't want to quit.
Title: Re: Really VOID Class
Post by: marcov on September 25, 2021, 05:46:17 pm
I think that advanced records are chiefly due to generics.

The specialize syntax

Code: Pascal  [Select][+][-]
  1.     xx = {specialize } yy<zz>;

doesn't really allow to specify operators and other methods that operate on zz.

Solution to avoid having to navigate all available scopes to find them:  bundle them nearly up with the record type.
Title: Re: Really VOID Class
Post by: Martin_fr on September 25, 2021, 05:57:51 pm
From what I understand the OT wants something like this:

Code: Pascal  [Select][+][-]
  1. type
  2.   TVoid = class {empty} end;
  3.  
  4.   TObject = class(TVoid)
  5.     constructor create;
  6.     procedure NewInstance; special internal new-instance;
  7.     procedure AfterConstruction; special internal after-construction;
  8. ...
  9.   end;
  10.  

So TVoid would be a pointer (like any object) to the instance-mem. The instance-mem would have a pointer to the VMT, but the VMT would be 0 bytes.
Technically, even the PVMT could be skipped, and the instance-mem starts at 0 bytes.

That does open a can of worms..... (the likes of which Pandora would gladly have exchanged her gift against).

For starters, the PVMT must have the typeinfo pointer (rtti). That is required for allowing any managed types inside the class.
Sure of course in theory that can be done conditionally. Except then you need some flag that distinguishes a VMT with RTTI from one without....
And the compiler needs to add checks for that flag. Or it needs to add extra duplicated code depending on the type used.... (calls to Initialize for managed fields).
I am not an expert on this. Maybe other options could be found. But it would be a pretty massive and complex undertaking....

Similar for any introduction of "special internal" (all the magic that comes with current classes) the compiler would probably end up adding extra code (compared with today).

So unless someone wants to write half the compiler from scratch....



There are a couple of things were I think it would be nice if they could be controlled away.
They do affect classes, but are not limited too. Mainly RTTI.

Through RTTI classes (and afaik enums/sets) include the unitname into the exe. For Classes its also the class name, and for some other types the typename too.

It's not about the exe size (well there is some deep down instinct from 4 or 5 decades ago, when the byte was still a valuable resource), it's more about privacy/security.
If you have a package with useful classes. One of them sits in a unit, that is called "IllegalMovieDatabase" or "SpyOnGlobalKeyboardHook", but the class can of course be used for other stuff, then you may get some strange feedback if you sell your app to some big company (or even government department), and they find that string in your app.




Title: Re: Really VOID Class
Post by: MarkMLl on September 25, 2021, 10:26:10 pm
So TVoid would be a pointer (like any object) to the instance-mem. The instance-mem would have a pointer to the VMT, but the VMT would be 0 bytes.

Hypothetically: would a TVoid require the capability of virtual methods, or could that be added in its descendants, i.e. TObject et al.?

Object Pascal does a sterling job of providing a robust underpinning to the sort of facility that used to be hardcoded into the typical "4GL". But with types fragmented into classes, objects, strings, dynamic arrays and so on I think it could be argued that anything that provided a common foundation would be a useful abstraction. If TVoid is a zero-length entity from which others might be derived, the suggestion might have some merit.

Quote
Sure of course in theory that can be done conditionally. Except then you need some flag that distinguishes a VMT with RTTI from one without....

The "Smalltalk way" would be to move pointers out of alignment by ORing-in one or more low bits on a byte-addressed architecture. In fact I believe that x86 has for some while had a facility (i.e. a bit in one of the configuration registers) to recognise this specific case and react sensibly. ** "Just sayin'" :-)

** I don't, however, know whether this sort of thing can be manipulated at the per-process level. My understanding is that there are a number of things in the architecture which have been added to keep "mainframe" manufacturers like Unisys and SGI happy, and which are likely to be unused by anybody else and possibly redundant from the POV of the original sponsor who has moved on to a different architecture and support chipset.

MarkMLl
Title: Re: Really VOID Class
Post by: Martin_fr on September 25, 2021, 11:49:06 pm
So TVoid would be a pointer (like any object) to the instance-mem. The instance-mem would have a pointer to the VMT, but the VMT would be 0 bytes.

Hypothetically: would a TVoid require the capability of virtual methods, or could that be added in its descendants, i.e. TObject et al.?

It could be addressed per "type" but not per "descendant", as that would create incompatible types. (And of those we have enough)

That is, as soon as a class (or subclass (aka always)) introduces the need for a vmt, it can no longer be stored in anything that does not have that space for the PVMT.
So if TVoid should be a real base class, then it needs to have a PVMT.

And the PVMT points to more than just the virtual methods (for classes, different with old style objects).

The PVmt has pointers for
- the RTTI too(for manage types, even if only in some descendant),
- the parent class type (for is operator).
- other stuff (not reviewed)

The PVMT, could have zero methods in it. But must exist.

Code: Pascal  [Select][+][-]
  1. // TMyObject > TObject > TMyVoid > TVoid
  2. var Foo: TVoid;
  3. begin
  4.   Foo := TMyObject.create;
  5.   if Foo is TMyVoid then ; // works only via PVmt for TVoid  (ref to base class)
  6.   Foo.Free; // If TMyObject has managed types their memory will leak, unless RTTI (e.g. via PVmt) exists in TVoid.
  7. end;


Old style objects have a different vmt, therefore this is not comparable.

And also you can not store a TMyOldChildType in a variable that is TMyOldParentType. (you can have pointers of those types work like that).
But "Dispose( PMyOldParentType(ptr) );" would leak managed types introduced in TMyOldChildType (not tested, but pretty sure)




"AfterConstruction" and "NewInstance" are virtual methods. They could be introduced by a descendent.

Though for "NewInstance" it really makes no sense at all to drop it (from declaration). What would be the gain?
- 1 pointer (2 bytes on some embedded, 4 or 8 otherwise) per class (not instance)
   On embedded, how many classes will you have? Say 50, then its 100 to 200 bytes. If unlucky some of it may be eaten by new code that gets generated, as instances still need memory.
- 1 indirect call converted to direct call.

Yet the latter (indirect call) can be removed by WPO (de-virtualization). So no need to alter the type definitions. (not sure if current WPO would do it)

Technically the first (saving the pointer) could also be done by WPO. Once it is entirely de-virtualized, it could be scratched from the VMT. => Only currently that part of the VMT is hardcoded, and can not be altered. Yet making it modify-able is less a task, than any adding (even part of) TVoid.

In the same way, unused methods (access to unit name, access to class name) could be reduced (by WPO), and (again currently hardcoded, not modify-able) the RTTI could shrink. (Again not trivial, but in theory...)


TinyPortal © 2005-2018