Jump to content

Lars Fosdal

Administrators
  • Content Count

    3324
  • Joined

  • Last visited

  • Days Won

    110

Posts posted by Lars Fosdal


  1. Not all for loops are created equal.

    Consider
    for x in [value1, value2, value3]

    You would expect to see x vary in the order of the values in the list.  However – if x and the values are of an enumerated type, looping the “list” does NOT loop in the apparent order of the constant, but in the order of the enumerated type declaration, such as it would for any set.

     

    Example at: https://larsfosdal.blog/2019/02/18/delphi-pitfalls-enumerated-types-and-for-loops/


  2. Yes, the examples leak. I didn't want to clutter it up with too much housekeeping code. 

     

    Thank you, Uwe, for enlightening me on variable vs value capture. IMO, the compiler could need a hint or warning if a variable capture happens in a loop, because it is really easy to overlook. 

     

    I use a number of variations on this to do dependency injection. It really helps with avoiding pulling too much project specific code into general code and keep the libraries isolated from each other. 

     

    This code in particular is part of a web server that (now correctly) supports a configurable collection of JsonRPC protocol handlers. The web server knows nothing about Json, and the protocol handlers knows almost nothing about http.

    • Like 1

  3. Code that looks correct, and appear to compile alright, but which doesn't execute well.
    Can you spot the error? See my blog post for a link to a SCCE.

    var
      Handler: THandlerClass;
      hType: THandlers;
    begin
      Broker.Clear;
      for hType in [foo, bar]
      do begin
        case hType of
          foo: Handler := TFoo.Create;
          bar: Handler := TBar.Create;
        end;
        Broker.AddHandler(Handler.OnHandle);
      end;
    end;


    https://larsfosdal.blog/2019/02/08/delphi-pitfalls-of-anonymous-methods-and-capture/


  4. When creating frames runtime in VCL, there are a set of tweaks that need to be applied to make the frame behave properly after creation (setting parent/owner etc).

     

    Are there similar tricks needed for FireMonkey, and are there other pitfalls related to dynamically creating frames at runtime?

    Is it better to drop the frames on the main form at design time?

    • Like 1
    • Thanks 1

  5. SSD disks are usually connected via SATA (Serial ATA) or PCIe using the NVMe protocol.  The first does not do parallel operations, while the second does. However, the speed benefit of the latter is when writing large amounts of data in parallel to individual areas. When deleting files, the OS is rewriting minor amounts of data in a shared area that needs to be integrity managed i.e. shared access locking, so I would suspect that there is no gain to parallelizing deletion of files.


  6. I have a new stored proc that takes a varchar(max) argument for logging - and I occasionally run into this problem when the argument is very long.

     

    It then raises the following exception
    EFDException [FireDAC][Phys][ODBC]-345.
    Data too large for variable [#9].
    Max len = [8000], actual len = [24448]
    Hint: set the TFDParam.Size to a greater value

     

    Note that I have a couple of varchar(5000) arguments in the same method that does not complain, so I assume that the default length for strings is 8000 chars.

     

    What is the best practice for dealing with this situation?

     

    My wrapper code for the stored proc does not really know anything about the potential sizes of these strings as it passes the values as variants.

     

    Is it acceptable to always measure the length of the string and dynamically increase TFDParam.size?

     

    I have a case already that deals with XML logging to an XML field.  

          vtUnicodeString:
          begin
            p.DataType := ftString;
            s := String(ConstParams[ix].VUnicodeString);
            len := Length(s) * SizeOf(Char);
            if Len > p.Size  // Autosize 
            then begin
              p.DataType := ftWideMemo; 
              p.Size := Len + 2;
            end;
            p.Value    := s;
          end;
     

    But - what happens if the actual field is not type

    , but [varchar(max)] ?
    
    
    

    Can I do the above for long string fields?

     

    What is the recommended action for handling changes to TFDParam.size for long varchar arguments?

     

×