Jump to content

Lars Fosdal

Administrators
  • Content Count

    3416
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Lars Fosdal

  1. Lars Fosdal

    10.4 Beta with Update Subscription

    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.
  2. Lars Fosdal

    Array size increase with generics

    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.
  3. Lars Fosdal

    Array size increase with generics

    @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.
  4. Lars Fosdal

    Array size increase with generics

    Suggestions on how would be appreciated. Apart from the generic list thing - this works so well.
  5. Lars Fosdal

    Array size increase with generics

    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.
  6. Lars Fosdal

    Why upgrade?

    Once. That was enough.
  7. Lars Fosdal

    Why upgrade?

    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.
  8. Lars Fosdal

    Why upgrade?

    Which is why I started with
  9. Lars Fosdal

    Why upgrade?

    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.
  10. Lars Fosdal

    Why upgrade?

    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.
  11. Lars Fosdal

    Why upgrade?

    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.
  12. Lars Fosdal

    FTP add virtual directory

    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
  13. 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;
  14. Not having basic DB and Linux support in the Pro SKU is lunacy.
  15. Lars Fosdal

    Get class instance in record

    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?
  16. 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.
  17. 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.
  18. Lars Fosdal

    TTimer equivalent with smaller interval

    Food for @Daniel
  19. 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.
  20. Lars Fosdal

    TTimer equivalent with smaller interval

    I opened the file as a binary file in a hex viewer and there were no FF or FE bytes.
  21. 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.
  22. Lars Fosdal

    TTimer equivalent with smaller interval

    @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.
  23. Is there mathematical proof for that?
  24. Lars Fosdal

    TTimer equivalent with smaller interval

    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.
×