Jump to content

Ali Dehban

Members
  • Content Count

    22
  • Joined

  • Last visited

  • Days Won

    5

Ali Dehban last won the day on April 6

Ali Dehban had the most liked content!

Community Reputation

25 Excellent

About Ali Dehban

  • Birthday 05/29/1986

Technical Information

  • Delphi-Version
    Delphi Community Edition

Recent Profile Visitors

964 profile views
  1. You're absolutely right, this is the normal usage, but at the moment you want to have one function to avoid repeating with the "obj" as input parameter then Delphi forces you to write that function in this way. As I mentioned this is not necessary and what you wrote is ok 99 percent of the time. There is one benefit with such a function that is the possibility to limit the input type to classes.(No primitive types like integer) I'm writing a library and I wanted to force the developers to use it in this way in this case.
  2. @pmcgee Hi. In most scenarios your sample would be enough, I agree. But why I used this: function UseInterface<T> ( obj: IMyInterface<T> ) : T; begin Result := obj.DoSomething; end; Because I wanted to call ClassObj.DoSomething from within another class and using one function which is not necessary but I wanted to know how it works in Delphi. When you are calling something like these generic object's generic members/methods from within another object(different class) then Delphi forces you to write like that. For instance, something like this won't be compiled which was my desired call but it's not allowed: function UseInterface(obj: T): T; Besides, I wanted to limit the input type to classes (no primitive types at all) which is possible if I use such a function, so my final function is even more complicated like this: function UseInterface<T: class>(obj: IMyInterface<T>): T; The keyword "class" here can limit the input type only to classes, so Integer or String is no longer allowed here.
  3. Ali Dehban

    ChatGPT plug-in for RAD Studio.

    The wrong warning is fixed now. @Die Holländer GitHub and release has been updated. If you prefer to follow it here it's ok but it would be easier for me to follow everything in one place, GitHub. If possible, please open an issue on GitHub in the future.
  4. Ali Dehban

    ChatGPT plug-in for RAD Studio.

    Perfect. Thank you for your reply. It's just a warning and won't be a problem but the warning shouldn't appear. I'm wondering how can I duplicate this. I'll try to fix it.
  5. Ali Dehban

    ChatGPT plug-in for RAD Studio.

    Hi fellows, I wanted to inform you that I have made an improvement to my AI-integration plug-in called ChatGPTWizard. Now it supports Ollama, the offline AI chatbot server. You can download the latest version (v3.0) to try it out here: https://github.com/AliDehbansiahkarbon/ChatGPTWizard To set up your offline GPT-like server read this section: https://github.com/AliDehbansiahkarbon/ChatGPTWizard#:~:text=How to use it in Offline mode I am eagerly looking forward to receiving your valuable feedback. Thank you in advance.
  6. I see. Well, beyond the curiosity, it depends on the nature of the project. As a general sample, it could/might be useful to implement something like an ORM, especially in an Active-Record structure or like that. (More info about the Active-Record: https://guides.rubyonrails.org/active_record_basics.html) In my case, I need it in a multi-purpose data access layer of a project but with complex data types, not Integer and String parameters combined heavily to RTTI functionalities. Thank you for your feedback.
  7. First, thank you for your response. Second, I thought so but! It seems using RTTI's TValue it is possible to handle this situation somehow. I'm just not sure if everything goes right with this code or not at the end, I tested with "ReportMemoryLeaksOnShutdown := True;" and there is no memory leak. Please have a look at the final version and share your thoughts with me. Best regards. type IMyInterface<T> = interface ['{D68085A3-6AFB-46D9-A4EE-B46563758127}'] function DoSomething: T; end; TMyClass<T> = class(TInterfacedObject, IMyInterface<T>) function DoSomething: T; end; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } function UseInterface<T>(obj: IMyInterface<T>): T; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass<T> } function TMyClass<T>.DoSomething: T; var ctx: TRttiContext; typ: TRttiType; val: TValue; begin ctx := TRttiContext.Create; typ := ctx.GetType(TypeInfo(T)); if typ.TypeKind = tkInteger then val := 20 else if (typ.TypeKind = tkString) or (typ.TypeKind = tkUString) then val := 'Hello' else if typ.AsInstance.MetaclassType.InheritsFrom(TStringList) then begin val := TStringList.Create; val.AsType<TStringList>.Add('Hello from StringList'); end; Result := Val.AsType<T>; ctx.Free; end; { TForm1 } function TForm1.UseInterface<T>(obj: IMyInterface<T>): T; begin Result := obj.DoSomething; end; procedure TForm1.Button1Click(Sender: TObject); var obj1: IMyInterface<Integer>; obj2: IMyInterface<String>; obj3: IMyInterface<TStringList>; lvstr: TStringList; begin try try obj1 := TMyClass<Integer>.Create; obj2 := TMyClass<String>.Create; obj3 := TMyClass<TStringList>.Create; ShowMessage(UseInterface<Integer>(obj1).ToString); ShowMessage(UseInterface<String>(obj2)); lvstr := UseInterface<TStringList>(obj3); ShowMessage(lvstr.Text); except on E: Exception do ShowMessage('Exception: ' + E.ClassName + ': ' + E.Message); end; finally lvstr.Free; obj1 := nil; obj2 := nil; obj3 := nil; end; end; Generic Interface-final.zip
  8. Hi mates, I have something on my mind but I couldn't implement it correctly, imagine a generic interface, some classes inherited from that interface, and one method in each class with the same name, now I'm trying to use this interface type every where for different approaches but it doesn't compile correctly. Please have a look at the code if you get a chance and share your thoughts with me, I do appreciate you in advance. The question is how can I implement such an idea properly and safely? I have attached a sample project to save you time too. unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Rtti; type IMyInterface<T> = interface function DoSomething: T; end; TMyClass<T> = class(TInterfacedObject, IMyInterface<T>) function DoSomething: T; end; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } function UseInterface<T>(obj: IMyInterface<T>): T; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass<T> } function TMyClass<T>.DoSomething: T; var ctx: TRttiContext; typ: TRttiType; begin ctx := TRttiContext.Create; typ := ctx.GetType(TypeInfo(T)); if typ.TypeKind = tkInteger then Result := 20 // E2010 Incompatible types: 'T' and 'Integer' else if typ.TypeKind = tkString then Result := T('Hello') // E2089 Invalid typecast else if typ.AsInstance.MetaclassType.InheritsFrom(TStringList) then Result := (typ.AsInstance.MetaclassType.InitInstance(typ) as TStringList) //E2010 Incompatible types: 'T' and 'TStringList' else Result := Default(T); ctx.Free; end; { TForm1 } function TForm1.UseInterface<T>(obj: IMyInterface<T>): T; begin Result := obj.DoSomething; end; procedure TForm1.FormCreate(Sender: TObject); var obj1: IMyInterface<Integer>; obj2: IMyInterface<String>; obj3: IMyInterface<TStringList>; begin try obj1 := TMyClass<Integer>.Create; obj2 := TMyClass<String>.Create; obj3 := TMyClass<TStringList>.Create; ShowMessage(UseInterface<Integer>(obj1).ToString); ShowMessage(UseInterface<String>(obj2)); ShowMessage(UseInterface<TStringList>(obj3).Text); except on E: Exception do Writeln('Exception: ', E.ClassName, ': ', E.Message); end; end; end. Generic Interface.zip
  9. Ali Dehban

    DateTime problem in fastreport's PFD export.

    It seems "mm" is defined in the fast report format options for minute, what does it mean "hh:mm" in fast report equals "hh:nn" in Delphi likely.
  10. Ali Dehban

    DateTime problem in fastreport's PFD export.

    You are right, It's designed by the customer itself, and the designer used IIF() to fill the MemoView to select one from two available TdateTime fields by some conditions and the result of IIF is text.
  11. Ali Dehban

    DateTime problem in fastreport's PFD export.

    Sure, I mean the retrieved data field from the database is TDateTime, but when you read from a TfrxMemoView you'll get it as text.
  12. Ali Dehban

    DateTime problem in fastreport's PFD export.

    The value is pure TDateTime. The desired format would be 'hh:nn'. But this 'HH' is a mistake I think (the support team did or myself during tests) and I just copied the current script without more checks, I'm not sure how and when this happened and why it is still working in UI mode. Thank you for the hint, I will investigate more and inform you about it, further.
  13. Ali Dehban

    DateTime problem in fastreport's PFD export.

    1- Invisible means running the exe in the command line with some input parameters to do a certain job and terminate with no UI (Application.ShowMainForm := False) Note: Do not ask me to change it to a Windows service or web service, etc, I wish I could but it's not possible because I'm not the owner of the product and it should work as is by their command; 2- And this is the script: procedure XReportOnAfterData(Sender: TfrxComponent); var LvTimeValue: string; LvLength: Integer; begin if Sender is TfrxMemoView then begin LvTimeValue := Trim(TfrxMemoView(Sender).Text); LvLength := Length(LvTimeValue); if LvLength > 0 then begin try TfrxMemoView(Sender).Text := FormatDateTime('HH:mm', StrToDateTime(LvTimeValue)); except TfrxMemoView(Sender).Text := 'Error: N/A'; end; end; end; end; Thank you for your response by the way.
  14. I'm maintaining an aged legacy application written in Delphi. I'm experiencing something weird in a report made by Fastreport (ver 5.5.6) and Delphi (XE5). There is a situation in which the exe will be triggered with some input parameters to export the expected document to PDF or Image to be used on a website or somewhere. The specific report that I'm talking about has some fields that are formatted by Pascal script to 24-Hour format or AM/PM to meet each customer's needs. (Dynamic report). Everything is perfect in the report preview, the printed report, and export to PDF, image, or Excel in the visible mode of the application(normal usage of the application). but those formats don't apply in invisible mode, those fields come up with the default format of the server. I checked the SQL Server result and the application report preview in visible mode and everything is fine but on the same machine when it executes in invisible mode it doesn't work. I doubted those Pascal scripts (OnAfterData event has been used), so I put some log functions and I realized those Pascal scripts are running, I can verify they are running each time but don't affect the final exported file. Does anybody have the same experience, Any advice?
  15. Ali Dehban

    Strange Benchmark Results; Am I Missing Something?

    Of course, we don't have the magic parallel=true flag but still, we can use parallelism. Maybe this is not the perfect one but something like this will give you the maximum performance probably. I'm adding this reply just for those who may need something like this, this is not the real answer probably. Anyway, I was able to achieve a 25% improvement in performance by using the code below: Remarks: - NumTasks = 4; ==> Specifies the number of parallel tasks to be used which is limited by the available resources, you can try with more or less chunks. - sw: An instance of TStopwatch to measure the elapsed time. - The code utilizes TParallel.For to parallelize the loop, dividing the range of numbers from 1 to 1000000000 into chunks based on the number of tasks (NumTasks). - Each parallel task calculates the sum of multiples within its assigned chunk using the SumMultiples procedure. - The partial sums from each task are added to the total using TInterlocked.Add for thread-safe operations. uses System.SysUtils, System.Diagnostics, System.Threading, System.SyncObjs, System.Math; const NumTasks = 4; procedure SumMultiples(var partialTotal: Int64; start, finish: Int64); var num: Integer; begin partialTotal := 0; for num := start to finish do if (num mod 3 = 0) or (num mod 5 = 0) then partialTotal := partialTotal + num; end; Var total: Int64; sw: TStopwatch; begin sw := TStopwatch.Create; sw.start; total := 0; TParallel.For(1, NumTasks, procedure(index: Int64) var start, finish, partialTotal: Int64; chunkSize: Int64; begin chunkSize := 1000000000 div NumTasks; start := (index - 1) * chunkSize + 1; finish := Min(index * chunkSize, 1000000000); SumMultiples(partialTotal, start, finish); TInterlocked.Add(total, partialTotal); end); sw.Stop; WriteLn(total); WriteLn('Total time ', sw.ElapsedMilliseconds, ' ms'); Readln; end.
×