Recent

Author Topic: Really VOID Class  (Read 5374 times)

damieiro

  • Full Member
  • ***
  • Posts: 188
Re: Really VOID Class
« Reply #15 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.



« Last Edit: September 24, 2021, 02:15:05 pm by damieiro »

y.ivanov

  • Sr. Member
  • ****
  • Posts: 283
Re: Really VOID Class
« Reply #16 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  :(

damieiro

  • Full Member
  • ***
  • Posts: 188
Re: Really VOID Class
« Reply #17 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
« Last Edit: September 24, 2021, 08:03:20 pm by damieiro »

y.ivanov

  • Sr. Member
  • ****
  • Posts: 283
Re: Really VOID Class
« Reply #18 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
« Last Edit: September 27, 2021, 09:21:06 pm by y.ivanov »

damieiro

  • Full Member
  • ***
  • Posts: 188
Re: Really VOID Class
« Reply #19 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.

« Last Edit: September 25, 2021, 01:47:48 pm by damieiro »

Thaddy

  • Hero Member
  • *****
  • Posts: 10929
Re: Really VOID Class
« Reply #20 on: September 25, 2021, 01:55:01 pm »
Zero Cost.
Except bow and arrow notation to access the heap parts.... ->
The average programmer productivity is 4-5 hours per day. Peak performance 72 hours for short bursts. MTBF is 1 second or less.

MarkMLl

  • Hero Member
  • *****
  • Posts: 3250
Re: Really VOID Class
« Reply #21 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
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 9589
  • FPC developer.
Re: Really VOID Class
« Reply #22 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.
« Last Edit: September 25, 2021, 03:03:52 pm by marcov »

korba812

  • Full Member
  • ***
  • Posts: 198
Re: Really VOID Class
« Reply #23 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?

Blade

  • Full Member
  • ***
  • Posts: 142
Re: Really VOID Class
« Reply #24 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.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 9589
  • FPC developer.
Re: Really VOID Class
« Reply #25 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.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 7437
  • Debugger - SynEdit - and more
    • wiki
Re: Really VOID Class
« Reply #26 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.




« Last Edit: September 25, 2021, 05:59:23 pm by Martin_fr »

MarkMLl

  • Hero Member
  • *****
  • Posts: 3250
Re: Really VOID Class
« Reply #27 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
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 7437
  • Debugger - SynEdit - and more
    • wiki
Re: Really VOID Class
« Reply #28 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