Jump to content

Brian Evans

Members
  • Content Count

    417
  • Joined

  • Last visited

  • Days Won

    6

Posts posted by Brian Evans


  1. 1 hour ago, dormky said:

    I thought about this, but dismissed the idea as this would mean the loading gif is dissociated from the window in which the loading occurs. If the window gets resized, moved, minimized or simply if the user opens up another program in that screen space that form is in trouble (ie will not be kept visible only when the working window is visible, and centered within it).

    This seems like adding requirements covering corner cases or minutiae that are unlikely to be meaningful to actual users. Most just dislike doubt and uncertainty - is it still doing anything? did it freeze? How much longer will it take? - provide some indication that answers those questions and most users will be happy. Trying for a precise UI treatment while also not fixing threading in the main application seems like a way to waste a lot of time on a secondary issue - just get the information displayed.


  2. 7 minutes ago, Lajos Juhász said:

     

    The only exception if you are working with databases that now ship only 64 bit client libraries. Most, if not all, of the modern databases has discontinued the 32 bit client libraries.

    Two of the big ones - Microsoft SQL Server and Oracle - still provide and support 32-bit clients. The databases with per server and/or per client license fees have more resources and incentives to keep that support going.


  3. An elapsed time clock is another option. If the time taken has some predictability users tend to like this option - over time they get a feel for how long some tasks take and if they can grab a quick coffee etc.

     

    In the Delphi 7 days I used a component from the Developer Express Forum Library for this but they stopped maintaining it a long time ago.


  4. 18 minutes ago, Cristian Peța said:

    Are you storing float in string fields?

    I create fields as REAL in SQLite and I can change the decimal separator without issues. I see period or comma and all is working.

    I can update a REAL column using period in sqlite3 tool, because the tool uses only period, and I can see values with comma in my app.

    Outside of the recently (relatively anyway) introduced STRICT tables the type of a column is really just a suggestion and it will happily stick a string anywhere if asked. Most tools try to tame this by enforcing the type but don't always succeed.

     

    SQLite website: 

    1. Datatypes In SQLite

    Most SQL database engines (every SQL database engine other than SQLite, as far as we know) uses static, rigid typing. With static typing, the datatype of a value is determined by its container - the particular column in which the value is stored.

    SQLite uses a more general dynamic type system. In SQLite, the datatype of a value is associated with the value itself, not with its container. The dynamic type system of SQLite is backwards compatible with the more common static type systems of other database engines in the sense that SQL statements that work on statically typed databases work the same way in SQLite. However, the dynamic typing in SQLite allows it to do things which are not possible in traditional rigidly typed databases. Flexible typing is a feature of SQLite, not a bug.

    Update: As of version 3.37.0 (2021-11-27), SQLite provides STRICT tables that do rigid type enforcement, for developers who prefer that kind of thing.

     

     


  5. The type-less nature of SQLite makes it not ideal for data in transit between databases. You end up doing work for edge cases that a typed database would handle on it's own.

     

    Want real fun? Have both English and French users, like in Canada with it's two official languages, where the decimal separator is period and comma respectively. Soon as strings start appearing in a column storing transaction values the fun begins. It can work as long as you listen to Egon Spengler and never cross the streams. Soon as you do however ...... think an online store that occasionally gives out 99.9% discounts level bad (few would complete the reverse - an order with items having a 1000x price increase except maybe the government).


  6. As well a lot of controls with lists have a BeginUpdate and EndUpdate so you can stop visually updating the control for every change to an item. Wrap things in an Try/Finally to make sure EndUpdate is always called.

    lv1.items.BeginUpdate;
    try
      // add multiple items
    finally
      lv1.items.EndUpdate;
    end;

    From the help for Vcl.ComCtrls.TListItems.BeginUpdate :

     

    Prevents updating of the list view until the EndUpdate method is called.

    Call BeginUpdate before making multiple changes to the list of items. When all changes are complete, call EndUpdate so that the changes can be reflected on screen. BeginUpdate and EndUpdate prevent excessive redraws and speed processing time when new items are added, deleted, or inserted.


  7. As Remy already mentioned an array or list works. I tend to put such things in a dynamic array. Can move the array to someplace higher in scope if desired but for code that doesn't run that often I usually create it as needed and let it fall out of scope and be destroyed.

    procedure TForm1.Button1Click(Sender: TObject);
    Var
      SomeMemos : array of TMemo;
    begin
      SomeMemos := [Form1.Memo1,Form1.Memo2,Form1.Memo3,Form1.Memo4,Form1.Memo5];
      // Dynamic Arrays are zero based so need to subtract one compared to 1 based
      SomeMemos[5 -1].Lines.Add('test!');
    end;

     


  8. In general an ever growing queue is a bad thing - at some point adding new items has to at least pause or it grows unbounded.

     

    The default size in the .create is a bit on the low side at 10 which I think is a source of bugs. This parameter perhaps should not have a default forcing the developer to think of a sane value or the need to .grow().

     

    The defaults for create():

    AQueueDepth is the length of the queue, which is by default set to 10.

    PushTimeout is the timeout when a new element is pushed, which is by default set to INFINITE.

    PopTimeout is the timeout when a new element is popped, which is by default set to INFINITE.


  9. Sure you don't have the options reversed between debug/release? The processor might be making poor choices in where it sends instructions but it would be odd to see a couple more instructions execute faster even with poor choice of execution unit scheduling or register usage.

     

    The only difference I see is the default debug settings generate code that does range bounds checking on

    a[i]

    checking it is within the array bounds.
     

    -- range and bounds checking off
    
    Project1.dpr.51: DivandMod(a[i], 2039, resto);
    000000000036CB5E 488B05834B0300   mov rax,[rel $00034b83]
    000000000036CB65 8B0D594B0300     mov ecx,[rel $00034b59]
    000000000036CB6B 8B0C88           mov ecx,[rax+rcx*4]
    000000000036CB6E BAF7070000       mov edx,$000007f7
    000000000036CB73 4C8D05764B0300   lea r8,[rel $00034b76]
    000000000036CB7A E881FEFFFF       call DivandMod
    
    
    -- range and bounds checking on
    
    Project1.dpr.51: DivandMod(a[i], 2039, resto);
    000000000036CB83 8B053B4B0300     mov eax,[rel $00034b3b]
    000000000036CB89 48833D574B030000 cmp qword ptr [rel $00034b57],$00
    000000000036CB91 740D             jz Project1 + $150
    000000000036CB93 488B0D4E4B0300   mov rcx,[rel $00034b4e]
    000000000036CB9A 483B41F8         cmp rax,[rcx-$08]
    000000000036CB9E 7205             jb Project1 + $155
    000000000036CBA0 E8BBFFECFF       call @BoundErr
    000000000036CBA5 488B0D3C4B0300   mov rcx,[rel $00034b3c]
    000000000036CBAC 8B0C81           mov ecx,[rcx+rax*4]
    000000000036CBAF BAF7070000       mov edx,$000007f7
    000000000036CBB4 4C8D05354B0300   lea r8,[rel $00034b35]
    000000000036CBBB E840FEFFFF       call DivandMod

     


  10. 8 hours ago, Berocoder said:

    Let EurekaLog send all exceptions to  a database is not an bad idea. The downside is that unlike a textfile it needs a tool to red it. Or a SQL prompt...

    But we have already a system with log-files that contains various loggings, exceptions and callstacks.
    This use one log-file per running process.


    We are also working on a solution to log everything to one central place in Google Cloud Platform.
    So that might be the final solution 😊

    It can generate a text file per exception that contains much more than just the stack trace. You can then do whatever you want with the text file. The log viewer tool they provide can display the contents of that text file in an easy-to-read way - nicely formatted and split up. 

    ref: https://www.eurekalog.com/help/eurekalog/bug_report_page.php

     


  11. 4 hours ago, Anders Melander said:

    It sounds to me like you have a quality problem if you have that many exceptions.

     

    In the applications that I work on (users in the hundreds), every single exception that are caught by the outer exception handler (madExcept in our case) is treated as a must-fix bug. On the average I would say we get one or two a month if we've been sloppy with the QA.

    The madExcept bug reports are usually either mailed to us by the madExcept UI, or retrieved from the customer's system by our supporters, and attached to a JIRA issue. It is extremely rare that we need to compare call stacks to detect a duplicate. AFAIK madExcept can do so automatically via a hash or something but we've never used that feature.

     

    So the only advice I can offer is: fix your bugs before release 😉 

    Could just be logging the stacks of exceptions that are handled and logging them as part of seeing what errors users hit most often. Of limited use but have seen it done - like graying out invalid choices + hint of why on mouse over or click instead of letting the user select an item and then producing an error dialog/message latter on that users are hitting far too often. 

×