Jump to content

Recommended Posts

Posted (edited)

Discussion started with:

 

On 4/14/2019 at 6:16 AM, AlekXL said:

 

On 4/14/2019 at 5:25 AM, Joseph MItzen said:

More importantly, how much time is that manual memory management costing the developer and how many errors are introduced because of it?

This is valid point, I must concede. We need to have an option to reference count just for explicitly designated object types and variables. And a first-class one, without need to build an interface wrapper.

Which means not some crappy wrappers like shared_ptr, no, lets introduce compiler magic and (non-breaking) language  changes.

like
 


FObject: auto TObject; // compiler, just manage the lifetime automacally

type TMyRefObject = class auto (TObject) // all instances are automatic

var manualRef := unsafe(RefCountedObject); // Compiler, I understand the risk, just give me raw pointer

var autoInline := auto TObject.Create;// compiler, manage it automatically

 

 

 

Edited by AlekXL

Share this post


Link to post

Then I posted my musings about Marco Article

On 4/14/2019 at 6:30 PM, AlekXL said:

Marco was right, when he said that forced arc is no-go, because of legacy, and fragmentation.

But why would he say, that on-demand arc is not viable?

Quote

but an ARC-enabled object won’t easily coexist with a non-ARC-enabled one

they would coexist just fine.

Arc -> non arc

unsafeInstance := unsafe(safeInstance);// you are on your own

is valid, although not safe. Just add hidden 4-byte field to TObject, at negative offset, FRefcount. Like in string constants, make sure this  field is negative for non-ARC instances. According to the type of variable (class OR auto class), which currently manipulate instance, compiler would know, whether to call gen _Addref and _Release on assignments.

Quote

and we would need containers for both flavors of objects and would make it impossible to mix them

Generally, yes, if you are talking about generics. But RTL and FMX should not use ARCed instances anyway.

And for user code, kindly let's us decide for ourselves. Again, non ARC instance pointer would be able to hold ARCed instance

Quote

This would end up as an extremely complex scenario.

For whom, may I ask? For me this is Merlin's blessing! 

 

 

Share this post


Link to post
Posted (edited)

Then Rudy commented about coexistence of ARC and non-ARC objects

 

r1.png

Edited by AlekXL

Share this post


Link to post
Posted (edited)

Which I responded

I explained in detail, how such objects can coexist. Learn to read.

If you so sure, pray tell,

{$J-}
const strTypedConst:string='FOO';
var   bar:string;
begin
bar:=strTypedConst
end.

Is strTypedConst  constant is ref-counted? Effectively? And bar variable? What actually happens, when its value assigned to bar?

Same goes to non-arc objects -- they just have their FRefCount locked , by some negative "magic" value, in constructor. Effectively, their are not ref-counted.

 

Surely you know, that ctor invocation has hidden param, which tells whether to call NewInstance, or not (1 or 0 respectively). Why not add value 2, which would instruct the ctor, which memory model to use (1 -- for classic objects FRefCount locked, 2-- for auto   objects.

  

And yes, before you ask stpd question -- assigning non ref-counted instance (variable) to a ref-counted variable should be forbidden at compile time -- I wrote this before

 

 

Edited by AlekXL

Share this post


Link to post

Then Rudy added

Quote

Heh, that doesn't even work properly for interfaces, even if they are not refcounted, You can make objects not being refcounted, but they would still live in an ARC environment, with al the possible problems and disadvantages. Note that your example contained a string constant, not just a non-refcounted object. Obviously you thought about it, but didn't think this through to the bitter end. 

"possible problems and disadvantages"? Which are? I could easily point out obvious and incontestable advantages (need I really), but surely I would abstain from even dreaming it , in fear of some vague "bitter end"

Share this post


Link to post

I tried to show my point

Quote

typed string constants do have tstrrec structure, their values can be stored in string variables without copying its value, and magic functions to addref and release are called on them, with no effect. So they live in the world of arc without their lifetime being affected by this.

That's how non refcounted instances should live  

And Rudy gave some reply

Quote

They are not **objects** that can actively reference **other** objects. See how this doesn't even work for interfaces. What makes you think it would be different for objects? Again: no, they can not easily live together

Then I just asked Rudy to stop beating around the bush, and give us use case of those "problems"

Quote

 

Please give an code example, not a vague words. What is the mysterious problem you taking :  "this isn't working for interfaces"?!

Can non-refcounted instance hold member instance of interface? Yes. They do that all the time. Can an ref-counted instance hold a reference to non-ref-counted object? Yes, absolutely. 

 

And now we waiting, what he could possibly reply?

Share this post


Link to post
Quote

What are talking about? Uniquestring is about COW on top of ARC! Nothing to do with ARC itself. Where I suggested to make instances COW capable? Think!

If  ARC pointer to instance is to be passed as var parameter, it's just passed without anything.


procedure Modify(var instance:auto TObject);// auto here is mandatory to accept ref_counted instances
begin
	instance := auto TObject.Create();//instance is replaced, _Release is called, then ctor!
    // _Release with do NOTHING if FRefCount is NEGATIVE!
end;

procedure Test();
begin
	var inst := auto TObject.Create();
    Modify(inst);//just pass without any fuss
    var classic = TObject.Create;// Non refcount, FREFCOUNT := -1000
    Modify(classic);//just pass without any fuss
end;

Your code contains memory leak. After a call to "Modify", pointer to original object, inside "classic" variable, will be lost.

Share this post


Link to post
On 4/18/2019 at 2:59 PM, AlekXL said:

We need to have an option to reference count just for explicitly designated object types and variables.

No, you don't need reference counting. Refcounting is just one of the possible ways to avoid lifetime issues (memory management is actually not the problem, for that we have a memory manager; lifetime management of objects is the problem).

 

Delphi already employs several different ways to do (automatic or semi-automatic) lifetime management.

  • For the VCL, it uses an ownership model with notifications.
  • New RTTI uses an object pool controlled by a context.
  • You can use (refcounted) interfaces instead of plain objects.
  • Some objects are automatically managed already (strings, dynarrays, variants, interfaces, anonymous methods).
  • Third parties have alrady developed smart pointers and/or managed object pools.

C++ uses smart pointers and stack based objects with automatic management (default constructors, etc.).

Other languages use a real garbage collector.

 

Each of these have their pros and cons. But you certainly don't need refcounting. There are alternatives.

 

FWIW, you could also do what Objective-C on the Mac did: use manual reference counting (MRC) and autorelease pools. But that would have the same problem as your solutions: different kind of objects that are not really compatible, i.e. that do not easily co-exist.

 

Oh, I agree that memory management is not only something that can be done wrong, it is also something that takes time and consideration, something I'd rather leave to the runtime, no matter how. But ARC is not the only way to achieve this.

Share this post


Link to post
Posted (edited)
On 4/18/2019 at 3:09 PM, AlekXL said:

but an ARC-enabled object won’t easily coexist with a non-ARC-enabled one

In that other, long thread, you already had to admit that that is not true.

 

I gave the example of   

TMyContainer.Add(A: auto TObject);

You said the container would be for ARC only. That showed that you would

  • either need separate containers for ARC and for non-ARC objects
  • or, if you could mix objects in such a container after all, you would need to write explicit runtime code to distinguish them so you would know if you should release or free them, or, if you copied a reference, if references should be counted, etc. You claimed it could be done at compile time, but that is not true if you can mix objects.

That shows that your ARCed objects would not easily co-exist with non-ARC objects.

Edited by Rudy Velthuis

Share this post


Link to post
On 4/18/2019 at 3:59 PM, AlekXL said:

Please give an code example, not a vague words.

I gave one simple one, and that already proved that you were wrong claiming that:

  • the compiler can detect such differences at compile time
  • The objects can easily co-exist

Both claims turned out to be wrong.

 

Add to that that although not all objects use ARC, you

  • either have to implement the refcounting methods anyway, and they simple don't do anything,
  • or your code must check at runtime if the objects is ARCed or not (and if not, it doesn't get these methods), simply to find out if addref or release must be called.

Both options mean that there is a runtime cost: either the code that calls the nonfunctional refcounting methods, or the code that must check if an object is managed or not.

 

Also note that managed objects can not be treated the same way as non-managed objects WRT casting etc.

Share this post


Link to post
On 4/18/2019 at 3:40 PM, AlekXL said:

Learn to read.

I see you're trying to find more friends. <g>

  • Haha 1

Share this post


Link to post
Posted (edited)
5 hours ago, Rudy Velthuis said:

That shows that your ARCed objects would not easily co-exist with non-ARC objects.

Semantics. You can coexist with your neighbors, without mingling with them. Problem arouses when they misbehave.

If I follow your logic, then AnsiString cannot easily coexist with UnicodeString, let alone RawByteString

15 hours ago, Микола Петрівський said:

Your code contains memory leak. After a call to "Modify", pointer to original object, inside "classic" variable, will be lost.

classic is meant to be freed explicitly via FreeAndNil or similar. Modify is not responsible for managing lifetime of such variables

 

Actually I find defect in my theory: You cannot pass non-arced variable as arced argument. This is because the container could return  such non-arced instance into arced variable, which is invalid.

We need some raw class type , which would accept both arced and non-arced instances (like rawbytestring which unlike AnsiString is codepage agnostic) .

Caveat : raw typed instances cannot be passed as var or out params. Or with must require them to match exactly, as usual to such params. And unlike RawByteString they cannot not be assigned to either flavor of instance without explicit typecast

like
 

TRawObject = raw TObject;//can point to TObject as well as auto TObject

function DoSomething(const instance:raw TObject):string;// raw here is to accept both flavors! Arced or not!
begin
     result := instance.ClassName;
end;

procedure Test();
begin
    var inst := auto TObject.Create();
    var str=Modify(inst);//just pass without any fuss
    var classic = TObject.Create;// Non refcount, FREFCOUNT := -1000
    str := Modify(classic);//just pass without any fuss
end;

And yes, with need a runtime type check to detect, whether we a dealing with unsafe or not, and also safe typecast as 
 

procedure Check(const inst: raw TObject);

var obj:TObject;

type TAutoObj= auto TObject;

var autoObj:TAutoObj;

begin

if inst is unsafe then // unsafe is going to be keyword anyway, as operator casting

obj := unsafe inst //OR

//obj := TObject(instance);//same!

else

autoObj := inst as TAutoObj;//or maybe

// autoObj := inst as auto TObject;// but since auto is directive, 
// this can be tricky to stupid LL(top-down) parser do detect, where auto is directive, and where is symbol name

end;

 

 

 

 

Edited by AlekXL

Share this post


Link to post
Posted (edited)
30 minutes ago, AlekXL said:

Semantics. You can coexist with your neighbors, without mingling with them

If every container or function taking objects as parameters must be done twice, then that is some kind of Apartheid, instead of easy co-existence. And you claimed there would be easy co-existence.

 

I assume you know what Marco Cantù wrote, and that that probably is the opinion of the entire Delphi team (http://blog.marcocantu.com/blog/2018-october-Delphi-ARC-directions.html):

Quote

 

We had many requests to make ARC optional, but an ARC-enabled object won’t easily coexist with a non-ARC-enabled one, and we would need containers for both flavors of objects and would make it impossible to mix them. This would end up as an extremely complex scenario. Mixing ARC and non-ARC is not a viable solution

 

 

That is exactly what I am saying, and you have proven it a few times now. I have shown that you must either separate containers and functions, or that you must add explicit runtime code to everything that allows you to mix such objects, i.e. there is an added runtime cost (and not just at compile-time, as you claimed). If you add that, no matter how you implement it, even if it is only as a flag, there is a runtime cost too, then it is clear that this is not a viable solution. It is kludgy, it requires a lot of code duplication, it slows things down and it is confusing.

 

I am very much in favour of finding a way to make lifetime management of objects easier, and ARC would be one way, but mixing ARC and non-ARC is not a viable one.

Also, the move back to non-ARC was done for simplicity and speed and to finally get back to one object model for all platforms. You would lose these advantages with your mixing model.

 

So you can talk about it a little more, but I am sure that neither your attitude nor your arguments are helpful in convincing them. In other words: I am pretty sure what you want will never be done. Perhaps you can convince the FPC people to implement it for you (although I guess they would refuse that too, for similar and probably for some more reasons), or you can try to find a group of people who fork FPC and then implement if for you. Good luck.

 

I have said what there is to be said. I agree with the Delphi team and I am pretty sure they had the same insight and reasons as I had.

 

Edited by Rudy Velthuis
  • Like 1

Share this post


Link to post
Posted (edited)
8 hours ago, Rudy Velthuis said:

I gave one simple one, and that already proved that you were wrong claiming that:

 

8 hours ago, Rudy Velthuis said:

the compiler can detect such differences at compile time

yes, it can. Aside from unsafe typecast , it perfectly capable. Or did I forget some of your argument? Repeat it please, or provide a direct link to it.

8 hours ago, Rudy Velthuis said:

The objects can easily co-exist

Yes, they can. No more tricky than AnsiString,  UnicodeString and RawByteString codepage-wise

8 hours ago, Rudy Velthuis said:

Add to that that although not all objects use ARC, you

  • either have to implement the refcounting methods anyway, and they simple don't do anything

no. There is methods that would not do refcounting, if they are designed to work with non-refcounted objects, or simply is not designed to manage instance lifetime

8 hours ago, Rudy Velthuis said:

or your code must check at runtime if the objects is ARCed or not (and if not, it doesn't get these methods), simply to find out if addref or release must be called.

yes, but only in case of raw class. Just like you do codepage checks on RawByteString

Edited by AlekXL

Share this post


Link to post
Posted (edited)
2 hours ago, Rudy Velthuis said:

If every container or function taking objects as parameters must be done twice, then that is some kind of Apartheid

No. If container is not designed to manage lifetime, then it can be specialized once. And generics can be specialized as many times, as needed

2 hours ago, Rudy Velthuis said:

And you claimed there would be easy co-existence. 

Again this is no more tricky than AnsiString,  UnicodeString and RawByteString codepage-wise

we would need containers for both flavors of objects and would make it impossible to mix them

Not exactly.  Example TMyListRaw and TMyListClassic can hold both flavors.

type TMyListRaw= TList<raw TObject>;//can hold both flavors, ref_cout overhead, runtime checks, when extracting item
type TMyListClassic= TList<TObject>;//can hold non-arc, and unsafe arc (static typecast),not ref_cout overhead (no lifetime management),
                                    //no runtime checks, can only extract non-ref counted items,
type TMyListAuto=TList<TObject>;   //can hold only arc-ed instances, no runtime checks, effective ref_count logic/lifetime management
  

 

2 hours ago, Rudy Velthuis said:

, or that you must add explicit runtime code to everything that allows you to mix such objects

No. TMyListClassic can hold arced instances without runtime checks. It just don't manage their lifetime, neither it returns manageable instaces.

2 hours ago, Rudy Velthuis said:

there is an added runtime cost

No. There is no runtime cost for non-arced objects. Neither for legacy code, nor for "i-hate-arc" code. Cost added when you choose it.

2 hours ago, Rudy Velthuis said:

I am very much in favour of finding a way to make lifetime management of objects easier, and ARC would be one way, but mixing ARC and non-ARC is not a viable one

We already mixing memory management paradigms, when using objects through interfaces

2 hours ago, Rudy Velthuis said:

So you can talk about it a little more, but I am sure that neither your attitude nor your arguments are helpful in convincing them

Playing dismissal game again?

2 hours ago, Rudy Velthuis said:

I am pretty sure what you want will never be done

It's not about what will be done. It's about how it shall be done. Truth is truth.

2 hours ago, Rudy Velthuis said:

Perhaps you can convince the FPC people to implement it for you

Perhaps some day EMBT Delphi would be forces to copycat FPC, not the other way around

Edited by AlekXL

Share this post


Link to post
51 minutes ago, AlekXL said:

No. If container is not designed to manage lifetime, then it can be specialized once. And generics can be specialized as many times, as needed

I will not repeat my arguments. I have already shown what is wrong with yours.

 

You know my view, you know the view of the people responsible art Embarcadero. Your efforts to "convince" them are futile, both because of your bad arguments and because of your behaviour.

 

And it is not even sure they will ever read this. This is not an official outlet of Embarcadero. That can be found here: https://community.idera.com/developer-tools/p/forums

 

Share this post


Link to post
1 minute ago, Rudy Velthuis said:

your bad arguments and because of your behaviour

dismissal again? As you wish.

 

Share this post


Link to post
Posted (edited)
1 hour ago, AlekXL said:

t's not about what will be done. It's about how it shall be done. Truth is truth.

It is quite a bit to claim you only know the truth and the people at Embarcadero don't. But aside from that, it is futile to argue how it shall be done if it is sure it will never be done. That is truth.

And now I'm probably finished with the topic.

Edited by Rudy Velthuis

Share this post


Link to post
Just now, AlekXL said:

dismissal again? As you wish.

 

I am saying they will certainly dismiss it. You don't have to convince me, as I don't decide such things.

Share this post


Link to post
37 minutes ago, Rudy Velthuis said:

It is quite a bit to claim you only know the truth and the people at Embarcadero don't

No only me, obviously. But people in EMBT ? I 'm aware only of Marco. And yes, I believe I know better than Marco.

Marco was against inline variables. Somebody strong-armed their introduction to the language.

39 minutes ago, Rudy Velthuis said:

You don't have to convince me,

convince you? Please ! That never was a goal.

I used you as opponent, to check my design, and to influence others. Somebody who could have similar concerns but no time or inclination to oppose me directly. And yes you were useful.

Thanks.

Share this post


Link to post

We already have mixed memory management model where ARC based classes coexist with non ARC based classes. Now different people have different views how well that model works, but generally it doesn't. It is complex model that requires plenty of knowledge to use it safely, and even if you know how to use it, you constantly have to jump through the hoops because quite commonly you don't have what you really need in particular code. You will either have reference counted class when you don't need one, or you will have non reference counted when you could really use it. On top of that you have TComponent based ownership model that will get in your way when you least need it.

 

OK, it is not all that bad... but situation is far from ideal.

 

Then we got ARC compiler, that solves all that duality problems perfectly. To be clear, no memory management model is perfect for all use cases, but in case of Delphi full ARC was the best fit in terms of existing code bases and integration with existing ARC based model for interfaces. 

 

But, it turned out that even though it was the best fit for majority use cases, changes required in existing code bases were too huge, also it required learning and adopting to new ways of writing code. Guess what? ARC was not welcomed by majority of Delphi developers that lead to decisions Macro explained in his blog post and decision that ARC compiler is deprecated.

 

So, after this ARC compiler failure. You want to implement your completely different mixed model that would still suffer from various problems - because no matter how far you go (and even if you can make your model work slightly better that the current one) you still cannot successfully mix ARC and non-ARC objects. Not only you didn't solved original problem, you also introduced another one - your model is completely incompatible with existing code and would require even greater changes to existing code bases. 

 

For me that is end of story. This is not viable option, no matter how you turn it.

  • Like 3

Share this post


Link to post
Posted (edited)
1 hour ago, Dalija Prasnikar said:

that would still suffer from various problems - because no matter how far you go (and even if you can make your model work slightly better that the current one) you still cannot successfully mix ARC and non-ARC objects

Again, baseless non-technical dismissal

1 hour ago, Dalija Prasnikar said:

Not only you didn't solved original problem, you also introduced another one

Which is? Problem was and is lack of more than just manual memory management. And what problem I introduced?

1 hour ago, Dalija Prasnikar said:

your model is completely incompatible with existing code

Well, that's a direct lie. Are you referring old legacy code, my model is exactly to address backward compatibility. Old non-ARC code would not even notice the changes introduced by my model. It would be unaffected

 

Even new, ARC-enabled code would benefit from it - either you instruct your class type to be ARCed, OR in case of library classes, you may force ARC throw variable/field declaration.

I can only imagine what a horrible mess it would be, when current ARC disappear, and the code depended on it would cause leaks.

My approach will fix that, causing minimum pain -- just fix declaration, adding one directive, auto. And every other approach would cause serious rework

1 hour ago, Dalija Prasnikar said:

For me that is end of story. This is not viable option, no matter how you turn it.

You don't even realize how incoherent this statement is, do you? Wrong, misleading. Harmful even.

Edited by AlekXL

Share this post


Link to post
3 hours ago, AlekXL said:

Marco was against inline variables.

Was he? Not as far as I know. EOM.

Share this post


Link to post
Just now, AlekXL said:

Is it intellectual laziness

There you go again. On the Embarcadero server, I would have already cancelled that message and suspended your access for a few days. You obviously can't discuss without being insulting.

Share this post


Link to post
Posted (edited)
3 hours ago, AlekXL said:

convince you? Please ! That never was a goal.

Then why do you complain about my dismissal?

I can't dismiss anything here. The people at Embarcadero can, and I do think they know the compiler better than you do, and the language and all the relevant issues too, no matter what you think.

 

And they are the only ones you must convince. No one else here can do what you want. Only they can. Telling them they are more or less stupid or ignorant about their own product  is not the best way to achieve anything from them.

Edited by Rudy Velthuis

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×