-
Content Count
242 -
Joined
-
Last visited
-
Days Won
2
Everything posted by balabuev
-
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Let's imagine that I want to change the code and call C (instead of B) from A: procedure C(st: string); begin _AddRef(str); try Writeln(st); finally _Release(str); end; end; procedure B(const st: string); begin C(st); end; procedure A(st: string); begin _AddRef(str); try C(st); // Call C directly without B. finally _Release(str); end; end; Whether your new _AddRefConst/_ReleaseConst functions need to be used? -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
I commented only parts I understand. Basically I do not understand what is your initial idea. Even, if we simplify things and will not talk about interlocking, I cannot understand how second counter (LockCount) or negative values in RefCount can help. Given your original code: procedure C(st: string); begin Writeln(st); end; procedure B(st: string); begin C(st); end; procedure A(st: string); begin B(st); end; I can rewrite it with some pseudo-code, which will higlight, what is happened inside: procedure C(st: string); begin _AddRef(str); try Writeln(st); finally _Release(str); end; end; procedure B(st: string); begin _AddRef(str); try C(st); finally _Release(str); end; end; procedure A(st: string); begin _AddRef(str); try B(st); finally _Release(str); end; end; Where _AddRef and _Release - are two RTL funcions, which increase and decrease reference count correspondingly. Can you modify this code to highligh your ideas... I just trying to understand - whether something else should be generated by the compiler directly inside A, B and C functions? Or you speak only about modifying _AddRef and _Release RTL (pseudo-)funcions? -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Yes. Just two remarks: Reference count is not belong to S or G. It belongs to shared memory to which both S and G points. And also we speaking about several threads, so there are several S variables. Before S goes out of scope, it can be passed by value to some other function(s), like DoSomethingWithS(s) in my code. Or assigned to some other string variables, like s2 := s; or even just re-assigned s := 'abc'. Each such operation will increas and/or descreas shared reference counter. So, it, actually, may be touched many times. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Yes. But my point is: even with this critical section protection and even with this read-only use case - ref-counts still should be interlocked. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Without interlocking, strings as well as dynamic arrays will not be usable in multi-threaded enviroment at all. Again, given this code: var G: string; CriticalSection: ...; procedure ThreadTask; var s: string; begin CriticalSection.Lock; // Protected access to shared global G variable. s := G; // CriticalSection.Unlock; // DoSomethingWithS(s); end; What do you say to the user, when he starts complaing about random AVs? The code is correct. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Everything related this aspect is veeery tricky. First, the goal of having interlocted ref-count field protection is tricky. It's not because we want thread-safe strings. It's included to be able to simulate value-type semantics for strings in muli-threaded environment (for preventing concepts leaking, in Dalija's terms). This is described in my previous post. Second, the implementation is also tricky. It's a kind of state of the art piece of code. Hard to understand. Anyway, check for -1 can be made without locking because: Only string literals have a ref-count equal to -1. And string literals are static. So, this -1 exist at its respective memory location from the start of the program to the end. This -1 is never changes to any positive value and vise versa. So, if you compare any ref-count with -1 even without protection, you will always detect, whether this string data is a static string literal data, or dynamically allocated data. During this comparison the value itself of a positive ref-count does not matter. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Not agree. Imagine several identical tasks running in different threads: var G: string; CriticalSection: ...; procedure ThreadTask; var s: string; begin CriticalSection.Lock; // Protected access to shared global G variable. s := G; // CriticalSection.Unlock; // DoSomethingWithS(s); end; Logical viewpoint: The code above reads the string from shared global variable G into thread local variable s. Then, since s is local we can do with it anything without futher protection. Phisical viewpoint: Even after assignment of value of G to variable s, they still point to same char memory, so, more than one thread can access it. This also applies to reference count field, which is a part of metioned shared memory. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Because otherwise, you will not be able to use same global variable of type string in different threads: 1) Even for read-only use cases, because we already described that ref-count value changes even in cases, when string char data is not modified. 2) Also for read-write use cases, even if the access to shared global string variable is protected with critical section in user's code. And this leads to the conclusion, that any potential additional field, like LockCount will also need locking. Moreover locking of two integer fields simultaneously is a much bigger problem (imho). -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
You missed the fact that increments and decrements are interlocked. So, they are slow operations. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Thanks, God! Not agree: procedure P(const S: string); var p, eof: PChar; begin p := Pointer(S); eof := p + Length(S); while p <> eof do begin // Do something. Inc(p); end; end; Here, for example, eof variable is a pointer, which holds not nil address, while point to no meaningfull data. And unlike object references and other more obvious reference types this case is not too exoting for pointers. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
I knew that you'll say this . With Pointer type I just wanted to highlight the fact that its values have no associated second part (like heap chars data in strings). In definition from Wikipedia this mising second part is called - "actual value". Yes, pointers usually points to some data, but this data cannot be considered a part of pointer value - pointer values point to (or hold location of) some external data. I mean that pointer value itself (the address) is quite disconnected from the data (if any) to which it points. And so, the "actual value" of Pointer - is the stored address itself. So, if I tell you just the fact that some variable is represented by a pointer to heap actual data, you will not be able to guess, whether I'm speaking about a variable of a value type (like, for example, TFoo) or a variable of a reference type (like, for example, dynamic array). It's impossible to distinguish between these two things based on provided information. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
I should argue, that strictly technical definition of value type vs reference type is also confusing: type TFoo = record S: string; end; var S: string; // string is a reference type (in memory layouting sense). F: TFoo; // TFoo is a value type. While the memory layouts are identical in both cases. Also, @Dalija Prasnikar, just for fun, how you define for yourself Pointer type? Is it a value type or a reference type? procedure P; var x: Integer; p: Pointer; begin p := @x; end; -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
I want to kindly remeber that the topic is not exclusively about strings... procedure TForm11.Button1Click(Sender: TObject); type TFoo = record X: Integer; BigData: array[0..15] of Integer; end; var s1: TFoo; procedure Test(const Value: TFoo); begin s1.X := 9; ShowMessage(Value.X.ToString); end; begin s1.X := 7; Test(s1); end; I know, I know, this works as expected. Because: 1) Delphi is Delphi! 2) If you thinking differently, then: 2.1) You thinking about wnything else, but not about Delphi. 2.2) Shut up and goto (1) -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
You did not get my point. I guess we both understand that in Swift as in most other languages strings are implemented as pointer to heap allocated memory. As well, as dictionaries. But, nevertheless they call them value types. Because the value type notion is more general, than you think. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
You wrong here. There EXIST a more general, or more conceptual if you like, notion of value types and reference types. Just as a good example, please look here: https://developer.apple.com/swift/blog/?id=10 Period. Next: No, let's quote again two things: - First, is a qualifying condition of the value type from Wikipedia: [a type is a value type, if: ] A value of value type is the actual value. - Second, your own words: Value of the string is sequence of characters. Dont' you see the full match? -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
I meant in Delphi's documentation. You yourself suspected me that I'm speaking about anything, but not about Delphi, right? But, even this definition from Wikipedia, which is by the way quite abstract (as it should be!), does not contradict with my point of view. Value of the string type is an ordered sequence of characters. Logically, nothing wrong. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
You invented this definition for youself. Btw, in fact, the definitions of "value type" and "reference type" are nowhere documented. And I do not agree to equalize reference type notion with just something allocated on heap. In common sense reference type is something, which allow to hold references to shared data (emphasis, as you say, is on SHARED word). This "shared" property should be visible to the user. So, the user should be able to determine, whether two references are pointing to single data or not. String data does not have this property, because given two string variables: - On read operartions you cannot really see the difference between phisically shared chars (single memory block) or two different memory blocks with the same content. - On write (or take address of) operations strings utilizes COW, and so, no writing to shared data really happened. Of course, you can determine this using some hack like: if Pointer(s1) = Pointer(s2) then But, thats another story. Sure. I understand. But, this does not change my point. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
The "desired behaviors" of the string type is to behave like a value type. Anyway, "s1" and "Value" in the test code are two different variables. Both of them store values, so we speak about two different (but equal) string values. And when you change one of them, the other should not be changed. Because: - [My viewpoint] string is a value type. - [Your viewpoint] internally string implements COW, and so, this is a desired behavior. When something is leaking through - it's called a bug. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Negating the reference count is not better than just incrementing it. Because you still have to do: - Slow interlocking. - Negating it back at the end, which will still imply try/finally. And so, there no sense to introduce another layer of complexity. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
String type conceptually is a value type. Come on! All thouse tricks, like ARC and copy-on-write (as well as copy on taking address of char, etc) are exist to allow string type to be a value type. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
I want to say that you again messed up concepts and implementation details. Pointers, heap data, ref-counts - are all implementation details terms. And just for note, I undestand how things works internally very precisely. But, I intentionaly want to keep the logic on the conceptual level. [1] Well, yes and no. Being formal - you are not correct, because the value of reference type is the reference itself. Yes it points to some associated data, but the value is just a reference itself. [2] Conceptually, string type in Delphi is a value type (I don't care about implementation details). [3] As described in documentation, "const" parameters are variables, just like value parameters. And this is quite important, because we should recall simple thing: variable is a slot which holds a value. From [1], [2] and [3] the following very important idea can be formulated: Because of [3] each variable holds its own value. Values (conceptually) are not shared between two or more variables. Because of [1] this is also true for reference types. And, finally repeating [2] - string type in Delphi is a value type, NOT a reference type. * Disclaimer: As I noted in this topic previously, practically, I agree that "const" modifiers cannot be implemented better than currently. And so, this is a kind of unfixable inconsistency. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
We should try to split concepts from implementation details. Conceptually "const" means that we are not allowed to change the value of the parameter inside the function. Conceptually "const" does not necessary imply passing by reference. Here is a definition from docs: Passing by reference can be considered only as an optimization, which compiler should do silently and on its own risk. Optimizations should not violate formal language concepts and should not introduce side effects in correct code. Original Marco's code is fully correct, and should work, simply because Value parameter is not assigned inside the function body, and thus "const" constraint is not violated by the programmer. procedure TForm1.Button1Click(Sender: TObject); var s1: string; procedure Test(const Value: string); begin s1 := '456'; ShowMessage(Value); end; begin s1 := Copy('123', 1); Test(s1); end; * All this is my theoretical viewpoint. -
Runtime create new "fields" with RTTI on a tComponent
balabuev replied to microtronx's topic in RTL and Delphi Object Pascal
As about lifetime, TDictionary as well as TObjectDictionary do not provide sufficient functionality also. The corresponding data entries will not be removed from the dictionary when the component is destroyed. For that, FreeNotification and RemoveFreeNotification methods should be used. But, this will complicate things a lot. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Agree. But, in this case Pointer(Value) will point to already deallocated "old" string memory, while Pointer(s1) will point to actual string content. Without ShowMessage, old (deallocated) memory block remains unchanged, thats why it seems that everything works ok. ShowMessage internally use heap memory, and so, the content of "old" block potentially becomes replaced, thats why strange random string is reported in this case. -
Delphi 10.4.1 code navigation - Cursor is vanished
balabuev replied to RonaldK's topic in Delphi IDE and APIs
Agree, and I've added a comment to QP. But, my point is that code constructs, I've shown, are veeeery old too.