-
Content Count
3416 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Lars Fosdal
-
10.4 10.4 Beta with Update Subscription
Lars Fosdal replied to ŁukaszDe's topic in Delphi IDE and APIs
Note that even if every update subscriber gets access to the beta, they are still under NDA and may not discuss testing 10.4 Denali in public. -
Array size increase with generics
Lars Fosdal replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
For me, using JSON is a must. The same single JsonRPC server serves Google Glass Java applets, Python clients in VoCollect A500 hip computers, Delphi FireMonkey touch applications under Windows 10, and various APIs to PLCs and third-party autonomous robots from Toshiba, Elettric80 and others. If I can find a viable alternative that allows me to replace the TArray<T>'s with TObjectList<T>, I'll be happy to have a look at it for robustness and speed, but the current solution handles a very large number of transactions daily, and the serializing and deserializing is not something that raises issues. -
Array size increase with generics
Lars Fosdal replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
@Uwe Raabe Both ways. I implemented a generic JsonRPC server and client using this method of JSON serializing/deserializing. The protocol endpoint handler code does not see the raw JSON all, only objects. -
Array size increase with generics
Lars Fosdal replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Suggestions on how would be appreciated. Apart from the generic list thing - this works so well. -
Array size increase with generics
Lars Fosdal replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I'd like to do that - but when creating Json with the TJson helpers, the TList<T> creates an unwanted effect. TArray<T>: {"int":0,"list":[{"str":"A"},{"str":"B"},{"str":"C"}]} TObjectList<T>: {"int":0,"list":{"ownsObjects":true,"listHelper":[{"str":"A"},{"str":"B"},{"str":"C"}]}} Ideally, I'd like to use TObjectList<T> - but have the Json look like what a TArray produces. program TArrayVSTList; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes, Generics.Defaults, Generics.Collections, Rest.Json; type TObj = class(TObject) private FStr: String; public property Str: String read FStr write FStr; constructor Create(const s: String); virtual; end; TListTest<T:TObj> = class(TObject) type TCont = class(TObjectList<T>); private FInt: Integer; FList: TCont; public property Int: Integer read FInt write FInt; property List: TCont read FList write FList; procedure Add(const s: String); constructor Create; virtual; destructor Destroy; override; end; TArrayTest<T:TObj> = class(TObject) type TContA = TArray<T>; private FInt: Integer; FList: TContA; public property Int: Integer read FInt write FInt; property List: TContA read FList write FList; procedure Add(const s: String); constructor Create; virtual; destructor Destroy; override; end; { TObj } constructor TObj.Create(const s: string); begin str := s; end; { TListTest<T> } procedure TListTest<T>.Add(const s: String); begin FList.Add(TObj.Create(s)); end; constructor TListTest<T>.Create; begin FList := TCont.Create; end; destructor TListTest<T>.Destroy; begin FList.Free; inherited; end; { TArrayTest<T> } procedure TArrayTest<T>.Add(const s: String); begin var len := Length(FList); SetLength(FList, len + 1); FList[len] := T.Create(s); end; constructor TArrayTest<T>.Create; begin // Nothing needs to happen here end; destructor TArrayTest<T>.Destroy; begin for var Element:T in List do Element.Free; SetLength(FList, 0); inherited; end; procedure TestJson; begin var Arr := TArrayTest<TObj>.Create; Arr.Add('A'); Arr.Add('B'); Arr.Add('C'); Writeln(TJson.ObjectToJsonString(Arr, [joIgnoreEmptyStrings, joIgnoreEmptyArrays, joDateIsUTC, joDateFormatISO8601])); var List := TListTest<TObj>.Create; List.Add('A'); List.Add('B'); List.Add('C'); Writeln(TJson.ObjectToJsonString(List, [joIgnoreEmptyStrings, joIgnoreEmptyArrays, joDateIsUTC, joDateFormatISO8601])); end; begin try try TestJson except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; finally Write('Press Enter: '); Readln; end; end. -
Once. That was enough.
-
Every bloody time I've tried to use the 64-bit debugger, breakpoints stopped working, evals were wrong, stepping stopped working, so in the end, I simply decided it was too soon. I really hope they get it right eventually.
-
Which is why I started with
-
By keeping current, you will deal with changes, one version at a time. After the D5->XE2 experience, I very much prefer that option. @Fr0sT.Brutal mentioned 64-bit. We didn't even go there yet, as the 64-bit debugger is utter and completely crap.
-
The worst breaking changes were Ansi -> Unicode. Migrating a million line D5 project to XE2 was something that I would prefer not to attempt again. Since then, there are been mostly type or constant renames, which are trivial in comparison. Other challenges have been the deprecation of BDE and dbExpress. Fortunately, FireDAC turned out quite well. I agree that the transition between the "named" version has been pretty much trivial, but then again - we usually don't migrate until the first Update pack shows up Last night, four of our SQL Servers that still linger on 2008R2 refused to accept schema updates for two specific stored procedures that were using functions only found in 2012 and upwards. The rest of our servers are 2012 and 2016/17. That is a similar risk to your components no longer getting updates for your Delphi version since the component author drew a line in the sand and started using language features or classes that only exist in the newer Delphi versions.
-
From my experience, the complexity of dealing with multiple generations of breaking changes has been far more expensive in man-hours than the cost of keeping current. Of course, that does not necessarily apply for everyone, and I can understand the cost perspective for a one-man shop - but for a corporate developer that is continuously developing internal systems, it is a no-brainer to stay current. You get the fixes, you get the support, and since we do relatively frequent releases, we do the testing anyway. Rio -> 10.4 will mean a lot of work on the FMX side - but on the bright side - you can finally stop having to think about two memory models when you write code for cross-platform. That dual model has actually been a roadblock for cross-platform for us. We did not want to spend time on that duality.
-
I've never set these up, but isn't that something you would configure on ISS itself, and then refer to from Delphi? Lots of security angles to consider
-
Array of named and typed parameters. (My Mind is blank)
Lars Fosdal replied to Tommi Prami's topic in Algorithms, Data Structures and Class Design
Here is a variation I use - I like type safety. type Setting = record i: integer; s: string; d: double; constructor Create(const _i: integer; _s: string; _d:double); end; Option = record const One: Setting = (i:1; s:'First'; d:0.01); Two: Setting = (i:2; s:'Second'; d:0.02); Three: Setting = (i:3; s:'Third'; d:0.03); class function Add(const _i: integer; _s: string; _d:double): Setting; static; // Sugar end; constructor Setting.Create(const _i: integer; _s: string; _d: double); begin i := _i; s := _s; d := _d; end; class function Option.Add(const _i: integer; _s: string; _d: double): Setting; begin Result := Setting.Create(_i, _s, _d); end; procedure Foo(const Options: TArray<Setting>); begin for var Option: Setting in Options do if Option.i in [2, 4] then Writeln(Format('i:%d s:%s d:%f', [Option.i, Option.s, Option.d])); end; procedure TestFoo; begin Foo([Option.One, Option.Two, Option.Three, Option.Add(4,'Fourth',0.04)]); end; -
FireDAC Client / Server (ODBC) Add-on web/ESD installer?
Lars Fosdal replied to Nathan Wild's topic in Delphi IDE and APIs
Not having basic DB and Linux support in the Pro SKU is lunacy. -
Get class instance in record
Lars Fosdal replied to Ugochukwu Mmaduekwe's topic in Algorithms, Data Structures and Class Design
Not sure that I understand the full context, but assuming you have an instance of TB in TA, overriding TA.AfterConstruction would allow you to assign self to that instance of TB? -
As a Delphi expert, do you ever need to refactor or improve your code?
Lars Fosdal replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
I have to admit that there are parts of our Delphi code that I want to move to .NET Core and C# - mostly because that makes it far easier to integrate it with other solutions we have on the MS platforms. That said - doing end-user applications for Windows in C# is nearly unthinkable. -
As a Delphi expert, do you ever need to refactor or improve your code?
Lars Fosdal replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
/blush -
Dictionaries, Hashing and Performance
Lars Fosdal replied to Clément's topic in Algorithms, Data Structures and Class Design
I would expect the hash generator you apply to your key would be pretty significant. My hashing needs are typically focused on strings shorter than 100-something chars, Int32 references, or Int64 references, typically varying from a few hundred to less than twenty thousand elements.- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
Food for @Daniel
-
Dictionaries, Hashing and Performance
Lars Fosdal replied to Clément's topic in Algorithms, Data Structures and Class Design
Which applies to the TDictionary hashing, I see. Thank you, @Kas Ob. It is entirely possible that my prime size cargo cult stems from this article https://web.archive.org/web/20080515141600/http://www.concentric.net/~Ttwang/tech/primehash.htm which is a different algorithm than the Delphi one.- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
I opened the file as a binary file in a hex viewer and there were no FF or FE bytes.
-
Dictionaries, Hashing and Performance
Lars Fosdal replied to Clément's topic in Algorithms, Data Structures and Class Design
I didn't make a claim. I asked a question. You answered. I asked if there was a mathematical proof that supported your answer. The other thread I mentioned seems to indicate that prime sizes have a purpose, so I'd like to understand. This is off topic for this thread, so please respond in the other thread or in DM.- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
@Kas Ob. It was a direct cut/paste from BDS to the forum editor in Chrome - so hard to say where the $FEFF was introduced. I can't replicate that error using BDS or VSCode. A proper realtime OS with a functional nanosleep is a better choice than windows for high resolution timing, I suppose.
-
Dictionaries, Hashing and Performance
Lars Fosdal replied to Clément's topic in Algorithms, Data Structures and Class Design
Is there mathematical proof for that?- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
Anyways - under Windows, we have the so-called multimedia timer, https://docs.microsoft.com/en-us/windows/win32/multimedia/about-multimedia-timers but a caveat is that actual minimum resolution varies with platform and device https://docs.microsoft.com/en-us/windows/win32/multimedia/timer-resolution var TCaps: TTimeCaps; // WinAPI.MMSystem; rc: MMResult; begin rc := timeGetDevCaps(@TCaps, SizeOf(TCaps)); // WinAPI.MMSystem; if rc = 0 then Writeln(Format('Min %d / Max %d', [TCaps.wPeriodMin, TCaps.wPeriodMax])) else Writeln(Format('timeGetDevCaps returned %d', [rc])); end; outputs Min 1 / Max 1000000 on my computer. Oddly enough, the resolution is 1ms - so, in theory it is impossible to use a timer to get a better resolution than 1 ms. Still - the WaitableTimer has 100ns resolution, so that should work, right? https://docs.microsoft.com/en-gb/windows/win32/api/synchapi/nf-synchapi-setwaitabletimer function NanoSleep(const NanoSec: Int64):Boolean; var Timer: THandle; Constraint: _Large_Integer; begin Result := False; Timer := CreateWaitableTimer(nil, True, nil); if timer <> 0 then try Constraint.QuadPart := -NanoSec; if SetWaitableTimer(Timer, Constraint.QuadPart, 0, nil, nil, False) then begin WaitForSingleObject(Timer, INFINITE); Result := True; end; finally CloseHandle(Timer); end; end; but even that is incredibly erratic. const ns: Int64 = 10000; var st: TStopWatch; ix: Integer; begin st := TStopWatch.StartNew; for ix := 1 to 10 do NanoSleep(ns); st.Stop; Writeln(st.ElapsedMilliseconds); end; and does not seem to work at low intervals - unless I screwed something up? Windows is not a real time OS - so it seems milliscond timing will be iffy - unless you use a power consuming loop of instructions - and that is not desirable.