Recent

Author Topic: Managed Objects  (Read 10082 times)

PascalDragon

  • Hero Member
  • *****
  • Posts: 6283
  • Compiler Developer
Re: Managed Objects
« Reply #15 on: July 06, 2023, 09:30:09 pm »
Are records good? yes.
Is inheritance good? Yes.

So then surely it must follow: are records with inheritance good?

Is chocolate good? Yes.
Is cheese good? Yes.

So is chocolate with cheese good? Well, your milage may vary.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12595
  • FPC developer.
Re: Managed Objects
« Reply #16 on: July 06, 2023, 11:02:22 pm »
Are records good? yes.
Is inheritance good? Yes.

So then surely it must follow: are records with inheritance good?

Is chocolate good? Yes.
Is cheese good? Yes.

So is chocolate with cheese good? Well, your milage may vary.

My favourite analogy would be from 10km up, all problems look small :-)

Ryan J

  • Full Member
  • ***
  • Posts: 141
Re: Managed Objects
« Reply #17 on: July 08, 2023, 04:40:45 pm »
Are records good? yes.
Is inheritance good? Yes.

So then surely it must follow: are records with inheritance good?

Is chocolate good? Yes.
Is cheese good? Yes.

So is chocolate with cheese good? Well, your milage may vary.

hehe good point. But none the less I don't see how records with inheritance are offensive like certain food combinations. I literally can't think of a  time where making a record inherit another record would make code worse than if I did the same thing with classes. They're less powerful than classes since self is not a pointer but no less powerful than not having it at all.

Bad Sector

  • Jr. Member
  • **
  • Posts: 69
    • Runtime Terror
Re: Managed Objects
« Reply #18 on: July 08, 2023, 09:03:54 pm »
Is chocolate good? Yes.
Is cheese good? Yes.

So is chocolate with cheese good? Well, your milage may vary.

Sorry but this is a very bad analogy.

And there is no point in having such pointless analogies, records with inheritance (and/or objects with all of records' features) are good to have. There is no point in trying to excuse such obvious and arbitrary lack of useful functionality with cheese, chocolate or any other type of food.
Kostas "Bad Sector" Michalopoulos
Runtime Terror

Ryan J

  • Full Member
  • ***
  • Posts: 141
Re: Managed Objects
« Reply #19 on: July 09, 2023, 04:24:03 am »
And there is no point in having such pointless analogies, records with inheritance (and/or objects with all of records' features) are good to have. There is no point in trying to excuse such obvious and arbitrary lack of useful functionality with cheese, chocolate or any other type of food.

This is all just technical debt of adding features over time and not unifying the concepts into a single new version. To extend my logic if inheritance is good an enums are good, why can't you inherit from an enum?

Type helpers exist now which allow yet another way to extend types, which is similar to inheritance but not using the same syntax. You could imagine those concepts being unified too.

Even the memory model of being manually managed for classes (because Pascal is not an ARC language I've been told) is inconsistent because there are ansi strings, dynamic arrays and interfaces which do ref counting. If ref counting is good why isn't there a fully ref counted class type?

Probably people can think of more.




PascalDragon

  • Hero Member
  • *****
  • Posts: 6283
  • Compiler Developer
Re: Managed Objects
« Reply #20 on: July 09, 2023, 08:52:42 pm »
This is all just technical debt of adding features over time and not unifying the concepts into a single new version. To extend my logic if inheritance is good an enums are good, why can't you inherit from an enum?

At some point this stops being Pascal. We don't want that.

Type helpers exist now which allow yet another way to extend types, which is similar to inheritance but not using the same syntax. You could imagine those concepts being unified too.

It is not similar to inheritance at all. It's more like a decorator pattern.

Even the memory model of being manually managed for classes (because Pascal is not an ARC language I've been told) is inconsistent because there are ansi strings, dynamic arrays and interfaces which do ref counting. If ref counting is good why isn't there a fully ref counted class type?

Because it wouldn't be backwards compatible, because code out there is using circular references thus you'd have tons of memory leaks if something like that would be introduced and introduing it optionally for some sub part of the class hierarchy wouldn't solve the problem if you'd assign an instance e.g. to TStrings.Objects.

The only way to solve this is managed records paired with default fields, because then the reference counting is outside of the class type.

Warfley

  • Hero Member
  • *****
  • Posts: 2037
Re: Managed Objects
« Reply #21 on: July 10, 2023, 12:08:36 pm »
The only way to solve this is managed records paired with default fields, because then the reference counting is outside of the class type.

One of the issues was with Delphi that when they decided to make classes, they wanted to hide the fact that they are pointers, while also making them raw pointers. So any solution to build additional arf pointer support, will produce code that looks more complex than code that uses manual memory management, even though it is actually much more simple
The most extreme is with ref counted wrapper types that always requires you to write something cumbersome like ptr.get.method.
One way that could be streamlined is by being able to overload the dereference operator ^ (as shared_ptr is implemented in C++). So you use a smart pointer like a normal pointer. Butwhile being better it still looks more complex than normal class use because classes are designed to hide their pointer nature.
Also due to their special kind you need different shared pointer kinds for classes, objects and other types, because they all have different ways destructors/finalizers are called.

The only way this could be mitigated is by introducing compiler magic, e.g. the for-in loop already has functionality to call the appropriate destructor type independent. If the type of the enumerator is a class Destroy will be called, if it's a managed record finalize will be called, and I think for objects the destructor (done?) Is called.
If that would be allowed for a special ref counting type this would make it already massively easier.

Lastly the whole recounting could be hidden in the type system, e.g.
Code: Pascal  [Select][+][-]
  1. procedure Foo;
  2. shared var
  3.   SharedSL: TStringList; // reference counted shared pointer
  4. Begin
  5.   SharedSL := TStringList.Create; // error because TStringList is a different type than shared TStringList
  6.   SharedSL.Create; // construction for shared pointer (potentially no ARGS constructor is called automatically)
  7.   SharedSL.Add('Foo');
  8.  

But this of course would require a major change to the language, and is maybe not worth it

Swami With The Salami

  • Guest
Re: Managed Objects
« Reply #22 on: July 11, 2023, 07:18:53 pm »
A managed record is completely foreign to me. I don't know where or when it evolved and although I'm sure it may be useful I've never even considered it. But I've also abandoned interfaces and generics - I suppose I am satisfied doing things the old way.

But the suggestion that those 6 lines of code  are too much just to fire up a TFileStream ignores the chief benefit of this approach: encapsulation. That's the way it's suppose to work. When we approach a problem in our professional life we produce a class that we can present to other programmers. It may only take a day or it may take a few months but in the end it would be wrapped up in bookends and used just like the TFileStream - 6 lines of code that I do not find cumbersome at all.

We've seen the electric piano mutate into the synthesizer... there are so many things about Pascal today that I do not understand.To me there is no difference between and a class and an object (other than the former being on paper while the latter is in memory) and I appreciate how much I can accomplish while keeping things simple. That's the way it's suppose to work.

I've heard it said many many times (and more frequently as time passes) that OOP is a mess. There may be some validity to that but I'm too simple to understand. OOP is the only thing I am passionate about when it comes to programming.


Warfley

  • Hero Member
  • *****
  • Posts: 2037
Re: Managed Objects
« Reply #23 on: July 11, 2023, 08:04:53 pm »
But the suggestion that those 6 lines of code  are too much just to fire up a TFileStream ignores the chief benefit of this approach: encapsulation. That's the way it's suppose to work. When we approach a problem in our professional life we produce a class that we can present to other programmers. It may only take a day or it may take a few months but in the end it would be wrapped up in bookends and used just like the TFileStream - 6 lines of code that I do not find cumbersome at all.
But you don't loose encapsulation, there is literally nothing you loose you just let the compiler perform the destructor call for you, that's it.

The question is, if you want to create a local variable that is created in a function and will be destroyed when the function ends, why do I as a programmer write extra code for this? The compiler knows exactly when the function is over and can easily take that job for me.

Programmers should ba lazy, everything you have to do manually is something you can make a mistake with. As I said often enough, memory management errors are some of the most common types of errors, and also the most security critical. When Mozilla rewrote the CSS component of Firefox in Rust, a memory safe language, they did an analysis about all the bugs they had: https://hacks.mozilla.org/2019/02/rewriting-a-browser-component-in-rust/
Over half of all bugs they had where memory or null pointer bugs, many of which being critical security bugs, and all of this can be avoided by simply letting the compiler do the memory management for you.

Personally I believe a language feature that removes 50% of all bugs and 95% of security critical bugs at nearly nearly no runtime performance loss, while also cleaning up the code is actually quite good.
I like having less bugs.

Especially in the case of local variables that does not outlive the function it's in, there is absolutely no reason to not do this, this comes pretty much at a net zero cost (the fact that objects are on the stack and the heap isn't involved means it is probably even more efficient).

Some people like to do it the old way, but I personally don't like to repeat the errors of the past. I like to learn from the past and do things better in the future

Swami With The Salami

  • Guest
Re: Managed Objects
« Reply #24 on: July 11, 2023, 08:41:59 pm »
Thanks - I wasn't suggesting that there was anything wrong with your process. I am merely wrestling with my own shortcomings.

An object may be referenced in any number of places so you, as a programmer, must write the extra code. All good programmers are lazy. If you think about it that's precisely why they are good programmers.

50% of all bugs ... 95% of security critical bugs ... I'm afraid I'm not following you - I must have missed something you said earlier.

I do not mean to imply that your ideas do not have merit. I am, however, a champion of the old OOP methodology .


Warfley

  • Hero Member
  • *****
  • Posts: 2037
Re: Managed Objects
« Reply #25 on: July 11, 2023, 08:52:34 pm »
This 50% and 95% referral to the Mozilla article where they reviewed all the bugs in their css engine and found that memory bugs made up pretty much half of all bugs and 32 out of 33 security critical bugs.

And yes, other references are indeed a problem, you can use reference counting but then you need to deal with cyclic references and threading. Alternatively you can use a garbage collector which solves most problems but requires you to stop the world (i.e. pause all threads to do the cleanup).

That's why this thread was pretty much solely about local objects whose.lifetime is bound to their owner, e.g. local variables (like FileStreams) or members of other classes. Because I think that this is really something that can be "optimized" without any major performance loss and none of the caveats of reference counting or garbage collection

Swami With The Salami

  • Guest
Re: Managed Objects
« Reply #26 on: July 11, 2023, 09:29:13 pm »
Saying I must have missed something you said earlier was just my Kurt Vonnegot-speak for I smoke a lot of weed and have a short attention span.

But having been a professional programmer for the last thirty years I've seen a lot of half-baked programs in an unreliable unfinished state. Unfortunately I was often responsible for salvaging a lot of these mostly .NET projects and I've had to ask when precisely does the garbage collector kick in? When programs are written to run twenty-four seven it is better to be on the right side of memory management!

You can devise a way to treat local short-lived objects differently than others but then that would be just another level of complexity, wouldn't it? That's not the lazy thing to do (or is it?)

Warfley

  • Hero Member
  • *****
  • Posts: 2037
Re: Managed Objects
« Reply #27 on: July 11, 2023, 10:13:27 pm »
You can devise a way to treat local short-lived objects differently than others but then that would be just another level of complexity, wouldn't it? That's not the lazy thing to do (or is it?)
Not really, I mean we have this concept already since the 50s, it's called a a stack frame. All local variabes are automatically freed by the compiler, and we don't even think about it. I mean isn't it weird that we write:
Code: Pascal  [Select][+][-]
  1. sl := TStringList.Create;
  2. try
  3.   // Use SL
  4. finally
  5.   sl.Free;
  6. end;
But not:
Code: Pascal  [Select][+][-]
  1. i := 42;
  2. try
  3.   // Use i
  4. finally
  5.   i.Free;
  6. end;

When Delphi introduced classes, they introduced a new type which explicetly does not have a feature that all other types until then had. Delphi classes intentionally try to hide the fact that they are pointers, so they desperately want to look like normal local variables, but then they lack one of the most essential features of those. And the thing is, there are types that do this way better, Strings and Arrays are also pointers that hide the fact that they are pointers, yet we don't need to do the following:
Code: Pascal  [Select][+][-]
  1. s := 'Foo';
  2. try
  3.   // Use s
  4. finally
  5.   s.Free;
  6. end;

So that classes must be handled manually are an exception not the rule, so the way it currently is adds additional complexity, while if classes would just behave as literally any other type for the history of procedural programming, it wouldn't be the case.

Quote
But having been a professional programmer for the last thirty years I've seen a lot of half-baked programs in an unreliable unfinished state. Unfortunately I was often responsible for salvaging a lot of these mostly .NET projects and I've had to ask when precisely does the garbage collector kick in? When programs are written to run twenty-four seven it is better to be on the right side of memory management!
The bugs that Mozilla analyzed where the bugs found in production, i.e. those that slipped through testing. Sure there will probably be much more logic bugs during the development, thats what debugging and testing is for. The thing with memory bugs is that these are the kind of bugs that are extremely hard to find in testing, while also, as previously said, are often extremly security critical (a simple use after free on user controlled data can be exploited to gain root access to the computer the program is running on).

So yes there will be other bugs, but unless you show me specific examples where the lack of memory management produced a bug, this is no reason why manual memory management is better. The fact that there are bugs in .Net programs does not prove that if the language would have manual memory management it would have no bugs. The opposite is the case, you would have the exact same bugs + additional memory management bugs.

I'm extremly confident in saying that over 30 years of research, since automatic memory management has become the norm, has shown conclusively that when it comes to code maintainability manual memory management is always worse than automated. Google recently release that 70% of their security bugs are due to manual memory management.  Just type in "memory management bugs" in google scholar and you will find mountains of academic research into that topic.
The discussion on that is settled, all evidence that we have show that manual memory management is a liability and only for extreme low level or performance oriented code relevant. It's not a question if it's good, it is undeniably. The question is how can we use it.

Swami With The Salami

  • Guest
Re: Managed Objects
« Reply #28 on: July 11, 2023, 11:06:33 pm »
We have a lot of historical literature from the Roman Era describing fantastical places and fanatical personalities but we must remind ourselves that most of what we read about those things was written by people who lived centuries later.

I remember the campaign surrounding Delphi when it first came out. They never used the word pascal but anyone with a little familiarity recognized it in the pictures on the brochures. They may have also downplayed the word pointers, I don't remember, but they certainly didn't keep it a secret. Of course they emphasized Object Oriented but in those days everything was marketed as Object Oriented even though very little of it actually was!  I remember Delphi did some things differently than its predecessor (Turbo Pascal for Windows) but I don't remember the details. Nevertheless pointers were always a part of the language, as least since Turbo Pascal 5.5 where I got started.

I don't think I understand what you're saying but I'm sharing my recollection and narrative about those days.

As an aside Delphi was immensely popular for a long time but I quickly tired on dragging components off of the tool bar and placing them on forms ... it was easier to write a "factory" that spit out forms the way we used to do in the days before "RAD". Even back in the nineties I was "old school".

 

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1315
Re: Managed Objects
« Reply #29 on: July 12, 2023, 12:32:45 pm »
There are plenty of ways to do automatic memory management in FPC. For classes: use interfaces. And if you want everything on the stack: use anonymous functions.

Heck, you can make everything static, if you want. Declare everything global, on program start. I worked on applications that did that. I even wrote a few of those (long ago, in BASIC, and for micro-controllers). Although it's generally a bad thing. We have a heap for a reason. It's far more efficient to do dynamic memory management than leaving it to the O/S to do paging. And you get lots of namespaces and very long names, which introduces other kinds of errors.

It also depends on your reference: if you compare Rust with C++, it will be a lot more skewed than when you compare FPC with Rust. C++ is notorious for creating memory errors.

Yes, it's more work to free them, but if you write the code to do that directly after creating them, it's all fine. Just a bit more verbose.

 

TinyPortal © 2005-2018