Jump to content

Kryvich

Members
  • Content Count

    402
  • Joined

  • Last visited

  • Days Won

    8

Posts posted by Kryvich


  1. First, I must note that

    IncludeTrailingURLDelimiter(IncludeTrailingURLDelimiter(dir1)+dir2)

    equals to 

    IncludeTrailingURLDelimiter(dir1)+IncludeTrailingURLDelimiter(dir2)

    If your problems are 1) the function name is too long, and 2) you prefer the dot notation, then 

    type
      TURL = type string;
    
      TURLHelper = record helper for TURL
        function AddDelimiter: TURL;
      end;
      
    function TURLHelper.AddDelimiter: TURL;
    begin
      Result := IncludeTrailingURLDelimiter(Self);
    end;

    and use it as follows:

    myURI := Dir1.AddDelimiter + Dir2.AddDelimiter + FileName;

     


  2. Yes, I see the same. It's strange, because when I generate tom_TLB.pas, even in Windows XP there is Spacing property in ITextFont interface. After doc.Selection.Font.Spacing := ASpaces, the Spacing property is actually returns the new value, but the edit control is not displaying as expected.


  3. Hi, Alexander. You create incredible software! They are rich in functionality, cost money and they deserve it. But perhaps you would consider creating a simplified HTML component with basic functionality only for Community Edition users, to use in free and open source projects?


  4. You need RichEdit50W, but TRichEdit utilize Riched32.dll / Riched20.dll, not MsftEdit.dll.

     

    In my program I used JvRichEdit from JVCL library, modified to utilize MsftEdit.dll instead of Riched32.dll. Updating the component version also significantly speeds up a loading of large RTF files.

    • Thanks 1

  5. I have several open-source projects, old and new, but there is no active use of enumerations. But they are actively used in my amateur projects related to linguistics and others.

    To give a hint of how the enumerations can be used, take for example the syntactic analyzer messages, warnings and errors:

      TSyntaxMessage = (smNone,
        // Here are suggestions of syntax analyzer:
        smRareLinkForWord, // Rare syntactic link
        smFirstSuggestion = smRareLinkForWord,
        smAdjToVerb,
        //...
        smSuggestionN,
        smLastSuggestion = smSuggestionN,
        // Here are warnings
        smNotLinkedWord, 
        smFirstWarning = smNotLinkedWord,
        // ...
        smWarningN,
        smLastWarning = smWarningN
        // Here are errors
    );

    We have a list of messages logically divided into groups: 1) no message smNone, 2) suggestions smFirstSuggestion..smLastSuggestion, 3) warnings smFirstWarning..smLastWarning, 4)...

    I don't need to set numerical values of members and check if they fall into the required sub-ranges. This happens automatically. Now I can write:

    case SyntaxMessage of
      smNone: ; // All is OK
      smFirstSuggestion..smLastSuggestion: ProcessSuggestion;
      smFirstWarning..smLastWarning: ProcessWarning;
      else Assert(False, 'Ops...');
    end;

    We can create a helper to work with messages:

      TSyntaxMessageHelper = record helper for TSyntaxMessage
        class function FromString(S: string): TSyntaxMessageHelper; static; // Returns TSyntaxMessage by the name
        function ToString: string; // Returns the name of message
        function Text: string; // Get a text of user's message
      end;

    And use this as follows:

    Mess1 := TSyntaxMessage.FromString('smBadUseOfVerb'); // when loading from XML etc.
    s := Mess1.ToString; // when saving to XML, JSON,...
    ShowMessage(Mess1.Text);

    Then we can declare a set of messages, add a helper for it, and work in a convenient manner.

      TSyntaxMessages = set of TSyntaxMessage;
    
      TSyntaxMessagesHelper = record helper for TSyntaxMessages
        class function FromString(S: string): TSyntaxMessages; static;
        function ToString: string;
        function Text: string;
        function First: TSyntaxMessage;
        function IsEmpty: Boolean;
        function Count: Integer;
        procedure ExcludeWarnings;
        procedure Include(const Messages: TSyntaxMessages);
        procedure Exclude(const Messages: TSyntaxMessages);
        procedure ForEach(Proc: TSomeProcedure);
        //...
      end;
    
    MyMessages := TSyntaxMessages.FromString('smRareLinkForWord smAdjToVerb smNotLinkedWord');
    if not MyMessages.IsEmpty then
      Mess := MyMessages.First;
    MyMessages.Include(OtherMessages);
    MyMessages.ForEach(DoSomething);

    We can add inline to the method declarations for faster code.

    A variable of type TSyntaxMessages will have a minimum size sufficient to store the set. The compiler will automatically check for ranges.

     

    • Thanks 2

  6. As for its own database, the program may store the enumerations in a field of any type: text, binary. But if a programmer chooses the binary format, then it is his responsibility to correctly interpret the stored data. It is possible, for example, to add a format version to the database and interpret the stored data accordingly.


  7. 3 hours ago, Lars Fosdal said:

    This is fine if you only use the enumerated reference inside your application, but if you use the ordinal - f.x. when saving to/retrieving from a database, or when transmitting to another system - you get into trouble.

    It is why textual exchange and API formats were invented. XML, JSONYAML. It's why Microsoft replaced the binary format DOC with DOCX. Do not pass an enumeration member by its numeric value, use its name.

    • Like 1

  8. Members of an enum are not objects. For ex. I have IDs of syntax relations of words in a natural language (about 200 IDs). The numerical values of the enumeration members are not important to us, only their names matter. Therefore, there is no need to specify integer values for each member of an enum in your program.

     

    1., 2., 3., 4. - it was the answer to the words of Wirth, which you quoted earlier.

    Quote

    If I know the value of the constant, I don't need anything else.

    Enumerations were invented in order not to use ordinalities of its members directly. And so as not to (accidentally) add, subtract and divide them like numbers. This is Pascal where type safety matters.

    Quote

    Also, no one forbids transferring the api header files.

    Take tlb for example, constants are beautifully declared in it.

    Headers can use enums as well. It depends on how the С-language headers are translated into Pascal code.

    Quote

    Do not touch the old field identifiers unless you want to break anything.

    With enumerations, you can reorder old values as you want. And nothing will break if the ordinalities are not directly used anywhere.

    Quote

    If you put in a record or a class, the type name will be a namespace.

    Overcomplication, misuse of software entities.

    • Like 2

  9. 1. You cannot extend a set of constants if they are defined in a record type in a third party library. There is no record inheritance.

    2. An enumeration give us more type safety than a set of integer constants.

    3. Scoped enumerations.

    4. I like prefixes. But if not, see 3.

     

    I use enums with 100 or more members. If instead of them I used named integer constants, adding and subtracting them, there would be many hard-to-find errors.

    • Like 1
×