Jump to content

havrlisan

Members
  • Content Count

    65
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by havrlisan

  1. havrlisan

    3rd party library not showing in a Form.

    Great to hear that solved your problem. To clarify, changing the ClassGroup property changes that line of code you edited:
  2. havrlisan

    3rd party library not showing in a Form.

    The TDataModule has a published property ClassGroup, check if that's set to VCL (because TSVGIconImageCollection is VCL only).
  3. I think this wouldn't scale well, because as soon as you have more types and classes, keeping track of all the aliased (or as you say, redefined) types will become a burden, let alone a refactoring. Another consideration is that some types will have helpers (eg. enumerations or records), which cannot make an alias, so you'd end up including the unit anyway, I find it clean enough to have a MyTypes unit that contains the scope-related types and then include that unit wherever I need a type from it. It's easier to track it, and the LSP will be thankful.
  4. Hi all. When you open up an FMX form or a frame, its controls will have their style applied if the style is loaded, eg. you have the data module opened which contains the TStyleBook that contains the styles. There are two possible scenarios with loading styles: load the styles first, then open the form/frame, or open the form/frame, and then load the styles. The second scenario doesn't apply to all controls though. It applies to all the standard FMX controls such as TLabel, TEdit, TPanel, etc., but not to custom controls. A good example is the recently added TSkLabel: style will not get applied until you reopen the frame or reload the form designer (by viewing it as text, then changing back the view to form). Has anyone successfully solved this problem?
  5. havrlisan

    Tool to sort units used in project by dependency

    I'm genuinely curious about how hard it is to implement. I remember seeing it in the Android Studio, which seemed like an awesome feature. I agree; it is the same thing I do on rare occasions. I wonder how much of an impact the unused units have on compilation time, and whether it is even noticeable on medium-sized projects (~500.000 lines of code).
  6. havrlisan

    Tool to sort units used in project by dependency

    This would be a whole lot easier if Delphi had such a feature. Is it that hard to implement that?
  7. havrlisan

    Problems closing IDE

    It's a shame Parnassus Debugger gets so little attention from Embarcadero. Such a plugin should (IMO) be integrated into the IDE, it's an insanely helpful tool for debugging multi-threading applications. Unfortunately as mentioned above, having it installed brings in unbearable errors and slows down your entire workflow. The least they could do right now is add an option inside the plugin to disable it so it doesn't load until one needs it. Installing it every time (and then uninstalling it after use) is a pain in the ass.
  8. havrlisan

    Thread leaks report (FastMM4)

    I stand corrected. What dummzeuch Dalija wrote below is the correct approach. The reason why I raise exceptions before the inherited call is to make sure nothing gets unnecessarily initialized in parent classes. Destructors should handle both scenarios though.
  9. havrlisan

    Thread leaks report (FastMM4)

    Raising exceptions in constructor will lead to memory leaks, unless the exception is raised before the inherited call. I don't see a problem with their claims.
  10. Many people do. I regularly debug my apps on Android and iOS, and less often on OS X. It's not as easy as debugging on Windows, but it's doable and most of the time helpful. I haven't attempted debugging on Linux, so cannot help you much there, although I can say that attaching the debugger may fail even when running the app through the IDE (especially on Android), so I presume attaching the debugger while the app is already running is even more painful.
  11. FYI there is a reported issue on QP regarding the mentioned bug. It's a shame it isn't mentioned anywhere, I accidentally came across it by scrolling through the issues.
  12. Hi. I ran across a deadlock situation in the System.Rtti on the OS X platform. Below is the call stack for both threads that lock each other: Thread 1: Fmx::Forms::TFrame::TFrame(System::Classes::TComponent*) + 299 (FMX.Forms.pas:7524,1 in SampleApp + 8570027) [0x1017c54ab] 1-25 System::Classes::InitInheritedComponent(System::Classes::TComponent*, System::TMetaClass*) + 107 (System.Classes.pas:4859,1 in SampleApp + 1097787) [0x1010a503b] 1-25 System::Classes::BeginGlobalLoading() + 13 (System.Classes.pas:4805,1 in SampleApp + 1096637) [0x1010a4bbd] 1-25 System::Rtti::TRttiContext::KeepContext() + 123 (System.Rtti.pas:5665,1 in SampleApp + 1462715) [0x1010fe1bb] 1-25 System::Rtti::EnsurePoolToken(System::DelphiInterface<System::IInterface>*) + 55 (System.Rtti.pas:5319,1 in SampleApp + 1607015) [0x101121567] 1-25 System::Rtti::EnsurePoolToken(System::DelphiInterface<System::IInterface>*)::DoCreate(void*) + 72 (System.Rtti.pas:5306,1 in SampleApp + 1606392) [0x1011212f8] 1-25 System::Rtti::TPoolToken::TPoolToken() + 197 (System.Rtti.pas:5253,1 in SampleApp + 1605765) [0x101121085] 1-25 System::TMonitor::Enter Thread 2: System::Rtti::TRttiInstanceMethodEx::GetAttributes() + 41 (System.Rtti.pas:6452,1 in SampleApp + 1637625) [0x101128cf9] 1-25 System::Rtti::TRttiObject::GetAttributes() + 86 (System.Rtti.pas:5788,1 in SampleApp + 1415254) [0x1010f2856] 1-25 __stub_in48s__ZN6System4Rtti37LazyLoadAttributes_MakeClosure_ActRec7_0_BodyEv + 27 (SampleApp + 1622027) [0x10112500b] 1-25 System::Rtti::LazyLoadAttributes_MakeClosure_ActRec::_0_Body() + 591 (System.Rtti.pas:5537,1 in SampleApp + 1622639) [0x10112526f] 1-25 System::Rtti::ConstructAttributes(unsigned char*) + 176 (System.Rtti.pas:5496,1 in SampleApp + 1612512) [0x101122ae0] 1-25 System::Rtti::ConstructAttributes(unsigned char*)::ConstructAttribute(void*, unsigned char*&) + 631 (System.Rtti.pas:5476,1 in SampleApp + 1611943) [0x1011228a7] 1-25 System::Rtti::TRttiMethod::Invoke(System::TMetaClass*, System::Rtti::TValue const*, long long) + 234 (System.Rtti.pas:10149,1 in SampleApp + 1437914) [0x1010f80da] 1-25 System::Rtti::TRttiInstanceMethodEx::DispatchInvoke(System::Rtti::TValue const&, System::Rtti::TValue const*, long long) + 3057 (System.Rtti.pas:6620,1 in SampleApp + 1641665) [0x101129cc1] 1-25 System::Rtti::Invoke(void*, System::DynamicArray<System::Rtti::TValue>, System::Typinfo::TCallConv, System::Typinfo::TTypeInfo*, bool, bool) + 183 (System.Rtti.pas:9346,1 in SampleApp + 1634871) [0x101128237] 1-25 System::Rtti::TRttiContext::Create() + 28 (System.Rtti.pas:5577,1 in SampleApp + 1462540) [0x1010fe10c] 1-25 System::Rtti::EnsurePoolToken(System::DelphiInterface<System::IInterface>*) + 55 (System.Rtti.pas:5319,1 in SampleApp + 1607015) [0x101121567] 1-25 System::Rtti::EnsurePoolToken(System::DelphiInterface<System::IInterface>*)::DoCreate(void*) + 29 (System.Rtti.pas:5304,1 in SampleApp + 1606349) [0x1011212cd] 1-25 System::Rtti::TRttiContext::UseContext() + 119 (System.Rtti.pas:5687,1 in SampleApp + 1606663) [0x101121407] 1-25 System::TMonitor::Enter(unsigned int) + 526 (System.pas:20052,1 in SampleApp + 131422) [0x100fb915e] 1-25 The main issue is the order of entering the TMonitor locks, which I extracted here: Thread 1: TMonitor.Enter(GCTokenLock); -- 5663:TRttiContext.KeepContext TMonitor.Enter(PoolLock); -- 5253:TPoolToken.Create Thread 2: TMonitor.Enter(PoolLock); -- 5524:LazyLoadAttributes TMonitor.Enter(GCTokenLock); -- 5687:TRttiContext.UseContext Am I at fault for reproducing these two call stacks in multiple threads (creating a frame in one, calling TRttiMethod.GetAttributes in the other), or is this a bug in the System.Rtti unit? It's worth noting that the GCTokenLock object (and locking) is only present with the USE_MONITOR_FOR_GLOBALCONTEXT compiler directive, otherwise atomic operations are used: {$IF Defined(WIN32) or Defined(WIN64)} {$UNDEF USE_MONITOR_FOR_GLOBALCONTEXT} {$ELSE} {$DEFINE USE_MONITOR_FOR_GLOBALCONTEXT} {$ENDIF}
  13. havrlisan

    Rtti multi-thread deadlock

    You're right, I see it now. Are there any downsides to that approach? And if not, is there a reason Embarcadero did not do that in initialization and finalization sections? Here's the link to the QP issue: https://quality.embarcadero.com/browse/RSP-44207
  14. havrlisan

    Rtti multi-thread deadlock

    I don't think acquiring the context would prevent the above call stacks from happening though: The first stack goes through System.Classes:BeginGlobalLoading, which directly calls EnsurePoolToken and is not avoidable. The second stack loads RTTI attributes with System.Rtti:ConstructAttributes method, which directly calls System.Rtti:Invoke method. In that method, TRttiContext is created right at the start.
  15. havrlisan

    Rtti multi-thread deadlock

    Sorry, I obviously should have pointed out that Thread 1 is the main thread, but it shouldn't matter since the problem is related to Rtti. Update: I'm aware that one solution for this problem is to wait for one thread to finish using Rtti, then let the other continue. That is what I did, but I still want to hear your thoughts on this, and whether this is a bug that should be reported, or not.
  16. Will there be any issues with declaring inline variables inside loops? Here's an example: procedure Sample(const AFixedArray: TSomeFixedArray); begin for var I = 0 to 10 do begin var LInlineVariable := TSomeFixedArray[I]; // do something end end Is it possible that the compiler will allocate more memory than needed, or something in that context? This seems to me like the only way the inline variable feature may produce issues.
  17. havrlisan

    Using inline variables inside loops

    Thanks for your reply, Remy. The code was just a simplified example for demonstration, compiler would not even allow the same variable declaration twice. Come to think of it, such compiler behavior actually does confirm what Dalija said above. This is correct, thanks for clarifying. I did not know this behavior existed in C#, but it is exactly what I wanted to achieve here. Unfortunately, I don't think we'll see such behavior anytime soon in Delphi.
  18. havrlisan

    Using inline variables inside loops

    Sorry for reviving this thread, but I came across another usage issue with inline variables inside a for loop: var LPair: TPair<string, string>; for LPair in FDict do begin var LKey: string := LPair.Key; FList.Add(procedure begin FDict.Remove(LKey); end); end; In this code I expected for LKey variable to stay on the stack as it is used in the anonymous procedure below, however, LKey will always end up with whichever value is in the last loop. Does this mean that declaring a variable inside a loop will only reinitialize it every time at the same address? Edit: to be clear, this is easily solvable by moving the block to a procedure with the key as a parameter. I'm just curious to find out the exact behavior of inline vars.
  19. I've encountered a bug with generics which I believe is a mistake in the compiler. I'll try to be as detailed as possible throughout the code below. I'm only interested in opinions on what is causing this issue in the low-level code, and on possible workarounds that are not entirely different from the implementation I intended to do here. Note that this is a bare minimum of code implementation necessary to reproduce the bug. TL;DR skip to HERE to see where the bug occurs. program GenericsBugConsole; {$APPTYPE CONSOLE} {$R *.res} uses System.Classes, System.SysUtils, System.Generics.Collections; type // Simple child class and interface inheriting from TInterfacedObject. // Contains one property necessary to demonstrate the bug (by invokation). IAncestorObject = interface ['{8B57E255-F48D-4982-B9AF-71A6ABBCDBA4}'] function GetID: TGUID; property ID: TGUID read GetID; end; TAncestorObject = class(TInterfacedObject, IAncestorObject) protected function GetID: TGUID; end; // Generic list that acts as a wrapper for the generic TList<T>. // Implementation is bare minimum for demonstration purpose. IGenericList<T: IInterface> = interface ['{B449EFCE-527D-4062-924E-A0E0421B8A16}'] procedure Add(const AObj: T); function First: T; end; TGenericList<T: IInterface> = class(TInterfacedObject, IGenericList<T>) private FList: TList<T>; protected procedure Add(const AObj: T); function First: T; public constructor Create; destructor Destroy; override; end; // Classes implementation { TAncestorObject } function TAncestorObject.GetID: TGUID; begin // irrelevant Result := TGUID.NewGuid; end; { TGenericList<T> } constructor TGenericList<T>.Create; begin FList := TList<T>.Create; end; destructor TGenericList<T>.Destroy; begin FList.Free; inherited; end; procedure TGenericList<T>.Add(const AObj: T); begin FList.Add(AObj); end; function TGenericList<T>.First: T; begin Result := FList.First; end; begin try var LList: IGenericList<IAncestorObject> := TGenericList<IAncestorObject>.Create; // HERE: // This is the place where the compiler starts acting weird. The call to Supports() passes, // and the debugger correctly shows that TCastedList is "TGenericList<IAncestorObject> as IGenericList<IInterface>". // Calling LCastedList.Add() also passes, TAncestorObject.Create will be casted to IInterface (as per arg type). var LCastedList: IGenericList<IInterface>; if Supports(LList, IGenericList<IInterface>, LCastedList) then LCastedList.Add(TAncestorObject.Create); // LObj is fetched from LList (IGenericList<IAncestorObject>), // and the debugger also shows that correctly: "TAncestorObject as IAncestorObject". var LObj := LList.First; // This is where the exception occurs. Throughout 3 different projects, I've received three different exceptions: // 1) 'c0000005 ACCESS_VIOLATION' -> Private console app, +300000 lines of code // 2) 'access violation at 0x00000001: access of address 0x00000001' -> Test FMX app, bare minimum code with TForm // 3) 'Privileged instruction' -> Not sure where I got this one, and I cannot get it again. Possibly on another test console app. var LID := LObj.ID; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.
  20. havrlisan

    Possible compiler bug with generics?

    Come to think of it, a compiler directive for raising errors in such scenarios would be an awesome option. Something like overflow and range checking compiler directives.
  21. havrlisan

    Possible compiler bug with generics?

    You're right, thank you. I did think that was the issue as you've written, but I thought it would be implicitly cast into IAncestorObject when either Added to TList<T> or when retrieved via First().
  22. havrlisan

    Possible compiler bug with generics?

    I forgot to mention a very important information: If I add the object as IAncestorObject to LCastedList (which expects IInterface), the bug does not happen. And if I add the object as IAncestorObject to the LList (which expects IAncestorObject), the bug also does not happen.
  23. havrlisan

    Using inline variables inside loops

    Very good explanation, thank you!
  24. havrlisan

    Using inline variables inside loops

    That's just unnecessarily complicating things. I'd generally declare the variable before the loop (whether it be before begin or as an inline variable, it doesn't matter), I am just wondering if the compiler is able to interpret the variable declaration as it should (?) in loops.
  25. I'm aware that the creation and manipulation of FireMonkey controls are not thread-safe, but what does it take for Embarcadero to fix/reimplement to enable this behavior? I've gathered that the main issues most certainly arise from using the TList class without locks, such as TFmxObject.FChildren and TComponent.FComponents. Besides the properties, there's also the TMessageManager.Default which returns an instance of TFixedMessageManager, which is also not thread-safe (because it also uses TList without any locks). Besides these, what else could be an issue?
×