-
Content Count
2561 -
Joined
-
Last visited
-
Days Won
133
Everything posted by Anders Melander
-
Interesting way to copy dynamic arrays.
Anders Melander replied to pyscripter's topic in RTL and Delphi Object Pascal
B := A makes them the same array. SetLength just makes B unique (and contains an implicit copy). I don't get what advantage assignment followed by SetLength gives you over a simple Copy. With Copy the intent is explicit. -
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
I like this quote from Graig (in the comments): Wise words.- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
Because the implementation wasn't designed to handle it. IMO there are better solutions. Docking for example (just not the VCL's docking - it's broken beyond repair).
-
Here you go. I've only included the stuff that directly deals with switching between SDI and MDI. The original code had a lot of logic related to positioning of the child windows, different layouts and and such. MDI_SDI.zip
-
How can I get same rounded value using SimpleRoundTo?
Anders Melander replied to ertank's topic in RTL and Delphi Object Pascal
Good thing we got that settled. *cough*Asperger*cough* 🙂 -
How can I get same rounded value using SimpleRoundTo?
Anders Melander replied to ertank's topic in RTL and Delphi Object Pascal
I once worked at a place that made calculation software for the construction business. When I started there all numbers were stored internally as strings. Apparently someone there knew about the problems associated with floating point numbers and had decided to solve the problem by representing all values as decimal formatted strings instead. Problem solved, right? Well, not exactly because every time they needed to recalculate values (i.e. just about every time the user did anything in the application) the strings were converted to floats, recalculated and then back to strings. Need to adjust the precision? Easy; Just truncate the length of the string. Clever, Eh? Unfortunately this little "pearl" was the least of their design problems. The whole calculation was represented internally as a tree structure and what do you do when you need a tree structure? You use a TTreeView of course! No need to reinvent the wheel. A good example of what can happen when you turn your mockup or proof of concept into a product without a rewrite. -
I'll see if I can find time to create a proof of concept for you tomorrow.
-
Okay. But just so you know, it is possible to do without any visual artifacts - but you need to do few things to get it to work.
-
Why shouldn't it be done? I've previously worked on an application where the user, at run-time, could change between MDI and SDI if they wanted to (*). I had to do a few things to avoid flicker but apart from that it worked fine. *) Apparently some user gets confused by MDI and others by SDI.
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
Ah, yes. I missed that. Easily solved though (I think): var FSingleton: ISingleton = nil; function Singleton: ISingleton; const MagicValue = pointer(1); begin if (FSingleton = nil) then if (TInterlocked.CompareExchange(pointer(FSingleton), MagicValue, nil) = nil) then begin // Create instance and reference interface (RefCount=1) var Instance: ISingleton := TSingleton.Create; // Copy interface pointer value (RefCount=1) pointer(FSingleton) := pointer(Instance); // Clear interface reference without ref counting (RefCount=1) pointer(Instance) := nil; end; // Wait for value to become valid while (pointer(FSingleton) = MagicValuel) do YieldProcessor; Result := FSingleton; end;- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
Yes, I originally had a test for nil before the CompareExchange but removed it "for clarity". Why do you say it doesn't work with interfaces? After all an interface reference is just a pointer and the object construction and assignment should take care of the initial reference count. var FSingleton: ISingleton = nil; function Singleton: ISingleton; const MagicValue = pointer(1); begin if (FSingleton = nil) then // Hapy now? :-) if (TInterlocked.CompareExchange(pointer(FSingleton), MagicValue, nil) = nil) then FSingleton := TSingleton.Create; // Wait for value to become valid while (pointer(FSingleton) = MagicValuel) do YieldProcessor; Result := FSingleton; end; What am I missing?- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
Yes, as long as all implementations set pixels via direct memory access then they should perform the same and then benchmarking is pointless. I haven't looked at the new revision to see if that is the case.
-
If you're focusing on performance then you should perform the pixel loop in Y-X order instead of X-Y order. - and replace all the constant divisions with reciprocal multiplications. E.g. x/50 = x * (1/50).
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
Okay. Here goes: You can but don't need to do bit fiddling. We just need to store 3 different states in the pointer; Unassigned Assigned Locked - being assigned It's easy to identify the first two states; If the pointer value is nil then the pointer is unassigned, if it's non-nil then it's assigned. But what about the locked state? Well, for a pointer to an object we can take advantage of the fact that memory allocations are aligned so the lower n bits will always be zero and can be (mis)used to store a lock flag. However since it's a pointer we can just as well just use a pointer value that are known never to be returned by the memory manager. For example ordinal 1. var FSingleton: TSingleton = nil; function Singleton: pointer; const MagicValue = pointer(1); begin if (TInterlocked.CompareExchange(FSingleton, MagicValue, nil) = nil) then FSingleton := TSingleton.Create; // Wait for value to become valid while (FSingleton = MagicValuel) do YieldProcessor; Result := FSingleton; end; Now you're mixing two different arguments. I'm not opposing full pointer exchange. I'm opposing the optimistic object instantiation (which presumably will cause a lock in the memory manager but regardless will be costlier than doing an explicit lock).- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
I don't think we're talking about the same.
-
Can I change the entry point for a VCL application?
Anders Melander replied to JamieR's topic in Algorithms, Data Structures and Class Design
The entry point is the begin...end block in the dpr file. You can instantiate whatever you want from there. The default is to create the mainform (and whatever "autocreate" forms/modules you have configured) in there. The first form to be created with Application.CreateForm becomes the main form. If you don't want a main form then just don't use Application.CreateForm. Oh, and btw, Application.Run is the message loop. -
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
It doesn't need to be, FTOH you can use the low bits of the pointer as a spin-lock flag. That's rather condescending. It's not that I'm not comfortable with it. It's just a solution I personally wouldn't use. I would say that what constitutes "good" is subjective and not defined by "because it is".- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
Not really. It's not the loading of the EXE that takes time. It's the application startup, login, select various application stuff, navigate to the POI, etc. Imagine if you were developing the Delphi IDE and was working on some problem that could only be reproduced with a specific project. How long time does it take to start the IDE, load the project, etc.
-
Not in this project. It's a C/S desktop application and there hasn't been a need for logging. No, what I'm talking about is the compile, debug, edit cycle.
-
I'm often working on applications where it can take 5-10 minutes to launch the application and navigate to the point of interest. Hot reload could save me hours every day.
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
The critical section is only an object because Embarcadero chose to make it one. It doesn't need to be. A spin lock is virtually costless and does not require any instantiation. Works, yes, but I beg to differ on the good part. It's not a pattern I would use. Too "clever".- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
Yes, I already acknowledged that. Having a Rudy moment?- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
Yes, but you can't use TMonitor without an instance which is exactly when we need it. A simply spinlock would probably be the cheapest in this particular case, but my example was just to illustrate what I meant. Keyword here is Lazy- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
Got it. No race condition then. My point was that since the code instantiates an object it isn't as lockless as it appears. The locking being performed is just out of view. A critical section would be much cheaper - and in plan view. var HelperRegistryLock: TCriticalSection; InternalHelperRegistry: IHelperRegistry; function HelperRegistry: IHelperRegistry; begin // Once InternalHelperRegistry has been assigned no locking occurs if (InternalHelperRegistry = nil) then begin // Locking here only happens when there's a race to create the instance HelperRegistryLock.Enter; try if (InternalHelperRegistry = nil) then // Locking inside MM only happens here - a single time InternalHelperRegistry := THelperRegistry.Create; finally HelperRegistryLock.Leave; end; end; Result := InternalHelperRegistry; end; initialization HelperRegistryLock := TCriticalSection.Create; finalization InternalHelperRegistry := nil; HelperRegistryLock.Free; end.- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with:
-
SudokuHelper - Example for uncoupled design via interfaces
Anders Melander replied to PeterBelow's topic in I made this
The possible race condition I referred to has to do with the (presumably reference counted) lifetime of InternalHelperRegistry but since I haven't looked at the rest of the code there might not be a problem - for example if InternalHelperRegistry is guaranteed to stay alive elsewhere. With regard to locklessnes, doesn't the instantiation of an object cause a lock in the memory manager?- 38 replies
-
- interfaces
- uncoupled design
-
(and 2 more)
Tagged with: