Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 12/10/20 in Posts

  1. Dalija Prasnikar

    Weak reference is dangerous

    You are mixing apples and oranges. Weak references work fine and have their purpose when used in single thread scenario. Their purpose is not achieving some magical thread safety, but breaking reference cycles. I will say it again, assignment of any non trivial type in Delphi is not thread safe. Never has been. As soon as one thread is writing some data, all access to that data must be protected. There is no way around it.
  2. Anders Melander

    Weak reference is dangerous

    [weak] is not unsafe if you respect its limitations. Otherwise you might as well ague that strings are unsafe.
  3. Dalija Prasnikar

    Weak reference is dangerous

    Well, there is really nothing to document because nothing is really thread safe in Delphi. Unless you want every single documentation page having "This is not thread safe" (I am exaggerating a bit, but this is generally true in 99.99%)
  4. Dalija Prasnikar

    Weak reference is dangerous

    You use weak when you cannot guarantee that weak reference lifespan will be less or equal to original strong reference. For instance, let's pretend that TComponent is truly reference counted class, and that same goes for its descendants TEdit and TMenu. Edit has PopupMenu property that can be set to independent TMenu instance. Currently destroying such TMenu instance would leave dangling pointer in Edit PopupMenu property, but we have notification mechanism that notifies Edit that Menu will be destroyed and that Edit should clear reference to the menu. In imagined reference counting scenario, you could have popup menu marked as weak reference and you would not need any notification mechanism to clear that reference when PopupMenu instance is deleted because weak would zero out (clear) that reference when menu is destroyed. If you use unsafe instead of weak, then you would have dangling pointer in PopouMenu property.
  5. Dalija Prasnikar

    Weak reference is dangerous

    No. While unsafe can also be used to break reference cycles, it cannot be used interchangeably with weak, meaning unsafe used in wrong place can lead to dangling pointers. Again, using weak is perfectly fine. If you read my book example again, you will see that you cannot even safely take strong reference from strong reference if original has been written to. So now what? Don't use interfaces at all because they are not thread safe. Don't use strings and dynamic arrays because they are not thread safe?
  6. Vincent Parrett

    Prefix unit local variable names

    Likewise, and I for interfaces. As for the RTL/VCL inconsistencies - well any 20+ year old large code base will have those, people come and go, with different ideas, eventually adherence to the initial standard will wane or evolve. My code is no different. These days I use camelCase naming for parameters and variable, with occasional lapses into the old style.
  7. Anders Melander

    Weak reference is dangerous

    If the weak reference is not thread safe then the the weak-to-strong copy also isn't thread safe. As far as I can tell there's no way that [weak] references can be implemented thread safe so I don't see a bug here.
  8. David Heffernan

    Prefix unit local variable names

    I think this desire to prefix everything is not helpful. I can't see what you are gaining by doing it. And doing so introduces a risk that you will read meaning into something that the compiler does not. Which means that if you ever forget to use your chosen prefix, or use a variable defined in a unit outside your control, you might infer the wrong thing. I personally use F for fields, and T for types, and nothing else. I use F for fields to avoid a clash with properties. I think the language design pretty much forces us to do that. As for types, that's more of a historical choice. I think if I didn't already have a heap of code written that way. Wouldn't your time be better spent improving your code rather than agonising of which letter to use as a prefix? If you decide to prefix your names, then pick a system and stick to it. It doesn't matter which letters you choose!
  9. Dalija Prasnikar

    Weak reference is dangerous

    Assignment operation in Delphi are not thread safe. If you have one thread writing and other threads reading, such access must be protected or you will get crashes or buggy behavior. You can safely write and read 32bit aligned simple types, in terms that such code will not cause any crashing, but such code will also not work as intended, unless you don't care about actual values stored. So, weak references in Delphi are not thread safe. Also even strong interface references in Delphi are not thread safe. So there is no bug here, just bad test case. Excerpt from my book Delphi Event-based and Asynchronous Programming (Part 5. Thread Safety) If you have multiple threads accessing - reading and writing - the same reference, one thread can easily interfere with the other. Let's say we have a shared interface reference `Data`, pointing to a previously created object, one thread that sets that reference to nil, and another thread that tries to take another strong reference from that one with an assignment to another variable `Tmp`. The first thread will execute the `_IntfClear` function that will result in object destruction. The second thread, trying to grab a strong reference preventing object destruction, will execute the `_IntfCopy` function: var Data, Tmp: IInterface; Data := nil; // Thread 1 -> _IntfClear Tmp := Data; // Thread 2 -> _IntfCopy If the `Source._AddRef` line from the `_IntfCopy` function executes before the call to `IInterface(P)._Release` manages to decrease the reference count to zero and subsequently calls the object's destructor, all is good. The second thread will successfully capture another strong reference to the object instance. However, the first thread can interrupt the second thread at the wrong moment, just after the `Source <> nil` check was successfully passed, but before `Source._AddRef` had the chance to increment the object's reference count. In that case, the first thread will happily destroy the object instance while the second thread will happily grab a strong reference to an already nuked object, and you can forget about happily ever after. Note: Besides interface references to objects, the reference counting mechanism is also used for other types like strings and dynamic arrays. Assignment of those types is also not thread-safe.
  10. Angus Robertson

    SslHttpClient Post problem

    You don't say what errors or exceptions are reported, so no idea whether the problem is the client or server. Your code is the old way of doing this, recent versions of ICS have a new TSslHttpRest component derived from TSslHttpCli that handles all send and receive streams internally (and SSL context),, and has logging built in. There is a new OverbyteIcsHttpRestTst sample that should allow you test your request and see the result, also the OverbyteIcsSslHttpRest unit itself has several example of using TSslHttpRest to access Google, Twitter, Microsoft and other REST APIs, the code for sending a Json email is as simple as:: HttpRest.RestParams.Clear; HttpRest.RestParams.AddItem('raw', IcsBase64UrlEncode(Content)); HttpRest.RestParams.PContent := PContBodyJson; HttpRest.ServerAuth := httpAuthBearer; HttpRest.AuthBearerToken := FAccToken; HttpRest.DebugLevel := FDebugLevel; StatCode := HttpRest.RestRequest(httpPOST, EmailURL, False, ''); FResponseRaw := HttpRest.ResponseRaw; FResponseJson := HttpRest.ResponseJson; This is a sync request, so does not return until the request is done, but the third boolean argument makes it async. No events are needed, you write ResponseRaw to a file if you really need it saved. Angus
  11. loki5100

    Weak reference is dangerous

    Ouuch, this is quite serious and this could probably explain my bug: https://stackoverflow.com/questions/64829275/android-memory-corruption I just open a report on quality central: https://quality.embarcadero.com/browse/RSP-31858
  12. David Heffernan

    Prefix unit local variable names

    I don't think that's a very helpful way to think about it. I would reserve the term local for a variable declared inside the body of a procedure. This includes any by value parameters. There are two main aspects at play here: lifetime and visibility. A local variable, as defined above, is created when the procedure is called and destroyed when the procedure returns. This is a narrow time frame of life, worth of the term local. A variable declared in a unit is created when the program starts and destroyed when it ends. That is a far wider time frame, and the term local is, in my view, ot befitting such a thing.
  13. Lars Fosdal

    Prefix unit local variable names

    No, not really. I just use a longish descriptive name, and I keep the declaration near the routines where it is used. F.x. unit SoAndSo; interface // lots of other declarations procedure ClearThreadContextLog; procedure SetThreadContextId(const aId: Integer); function GetThreadContextId: Cardinal; function GetThreadContextLog: TArray<String>; procedure AddThreadContextLog(const aText: String); implementation // lots of other code threadvar ThreadContextLog: TArray<String>; ThreadContextId: Integer; procedure ClearThreadContextLog; begin SetLength(ThreadContextLog, 0); end; procedure SetThreadContextId(const aId: Integer); begin if (aId <> ThreadContextId) then DebugOut(Format('Setting ThreadContextId %d for ThreadId %d', [aId, GetCurrentThreadId])); ThreadContextId := aId; end; function GetThreadContextId: Cardinal; begin if ThreadContextId > 0 then Result := ThreadContextId else Result := GetCurrentThreadId; end; function GetThreadContextLog: TArray<String>; begin Result := ThreadContextLog; end; procedure AddThreadContextLog(const aText: String); begin var len := Length(ThreadContextLog); SetLength(ThreadContextLog, len + 1); ThreadContextLog[len] := Format('%d %s', [TThread.CurrentThread.ThreadID, aText]); end; // lots of other code end.
  14. You can switch to the Classic Code Insight and then back to LSP.
  15. Enhanced RTTI provides that information. See Working with RTTI, TRttiType.GetFields(), and TRttiField.Offset. For example: var Ctx: TRttiContext; Offset: Integer; Offset := Ctx.GetType(TControl).GetField('FParent').Offset; But why do you need to access the FParent and FWidth member directly? Why can't you use the TControl's public Parent and Width properties instead?
  16. For methods that are readily accessible you can use the idea given here (Delphi: Offset of record field - Stack Overflow), although in that Q it's in the context of records. Your TControl in the previous message has public methods, so that's easy. Your TWinControl has private methods so you'd need some form of cracker to gain access to the private methods. If it were me I'd copy the VCL unit, add it to my project, and add some code in the implementation section to dump out the info you require. Of course, the TControl that you quote here isn't the real TControl since the fields in the real one are private not public. So who knows what is really going on. Perhaps you are posting code from some experiment you are working on. Also, casting an HWND to a TControl* doesn't get you anywhere. They are not the same thing.
  17. Rollo62

    Prefix unit local variable names

    https://en.wikipedia.org/wiki/Naming_convention_(programming) here with some examples ... Anyway, it seems that I use sometimes the RadicalMixedPascalCamelSnakeCase, if it makes sense to force visual readability and visual grouping
  18. Anders Melander

    ways to organize related code in a form?

    Rubber Ducking: Monologuing a description of a problem to someone (or something) in order to get a better understanding of it.
×