Considering that we now can have constants within records and classes -

Considering that we now can have constants within records and classes -
why can't we have resource strings in there?

type
TMyRec = record
const
ThisIsOK = 'String';
resourcestring <- [dcc32 Error] : E2029
ThisIsNotOK = 'string';
end;

[dcc32 Error] : E2029 'END' expected but 'RESOURCESTRING' found

Comments

  1. That might have to do with resources always being in the global scope of the EXE/DLL.

    ReplyDelete
  2. Jeroen Wiert Pluimers But resourcestring naming can't be global?

    unit A;
    interface
    resourcestring
    ResName = 'name';
    ...
    unit B;
    interface
    resourcestring
    ResName = 'lastname';

    How are they named globally?
    AFAIK, you can also have resource strings in the implementation section of a unit?

    ReplyDelete
  3. The resource string is not a constant. It can vary in different translations.

    Initialized variables in records and classes would be an interesting addition.
    TMyRec = record
    MyField: Integer = 111;
    end;

    ReplyDelete
  4. T n T It is a constant from a compilation perspective, but it is correct that it's returned value can be changed with the translation tools at run time.

    ReplyDelete
  5. Lars Fosdal The compiler can embed constants in the code. It's impossible for resource strings.

    ReplyDelete
  6. T n T Yes - the resource string is a run-time lookup.

    ReplyDelete
  7. why not ? It could be just a kind of namespace after all.

    ReplyDelete
  8. And what size should the record become with a resourcestring inside, in your opinion?

    ReplyDelete
  9. Why on earth would you want the same constant in every instance of a record?

    ReplyDelete
  10. a constant is not duplicated, it is not part of the record (AFAIK) it is just a namespace question

    ReplyDelete
  11. Jeff Dyer It would not be the same constant. The constants would be tied to a specific context, so that constants that happens to have similar or even identical names, could co-exist without namespace pollution

    ReplyDelete
  12. hide this in a unit (x): resourcestring rs = 'rs';

    uses x;

    Ta = record
    const
    a: string = rs;
    end;

    ReplyDelete
  13. Jeff Dyer constants declared inside types are associated with the type and not the instances of that type. So your question is a non-sequitur.

    ReplyDelete
  14. David Heffernan If all records of type Tx have the same constant in them , that adds no information to the system, as far as I can see. We can surely infer the type of the record using "if X is Tx", and the constant can't help us identify individual records, so I don't see what the point of this is at all.

    ReplyDelete
  15. The point is to isolate resourcestrings for use in a limited context - i.e. to avoid the "global variable".

    ReplyDelete
  16. Lars Fosdal That is mixing internal data structures with presentation. Not good IMO.

    ReplyDelete
  17. Jeff Dyer what difference do you see between a const string and a resource string ?!

    ReplyDelete
  18. Paul TOTH AFAIK the point of resource strings is to be able to build different versions of the application for different installations, for example multi language or different clients without resorting to configuration files. Those are the only times I've used them.

    ReplyDelete
  19. Jeff Dyer Translation is the reason we do it as well. However, we have a large number of UI screens, and texts and terms can be similar but not necessarily identical in all contexts - hence using the same translation is at times completely wrong.

    Like for any other type / const / variable scoping - it would be beneficial to be able to limit the scope of a resourcestring so that it is only accessible with the scope that it belongs to.

    ReplyDelete
  20. Lars Fosdal mixing presentation strings and business data leaves a bad smell to me.

    ReplyDelete
  21. Jeff Dyer It's about using the type as a namespace, and keeping scope as narrow as possible.

    ReplyDelete
  22. David Heffernan It still smells.

    ReplyDelete
  23. Why don't you just isolate like I showed yesterday, I don't think there is a better solution or ever will be. Records are not made to represent a namespace.

    ReplyDelete
  24. Jeff Dyer In general, yes. However, when the presentation strings are fed as attributes to a generic class which purpose is to hold, sort, filter and format SQL query data specific to a presentation, and that is fed to an empty grid at runtime through a TGridView class which adapts the data to the specific grid type, we are in the presentation layer, not the business logic layer.

    TOrderGridSet = class(TGridSet)
    public
    [GridAutoSize]

    [InitField('Batch', 60),Autosize]
    SchoolClass: TGridSet.TFieldString;

    [InitField('Date, 90),Autosize]
    ConsumptionDate: TGridSet.TFieldDate;

    [InitField('Client', 60),Autosize]
    ConsumerName: TGridSet.TFieldString;

    ...

    ReplyDelete
  25. Anyways - that "smell" thing is not the question here. The question is if there is any logical reason in the compiler for not allowing "private" resourcestring declarations.

    ReplyDelete
  26. Jeff Dyer I'm not making any comment on how Lars Fosdal chooses to design his code. I'm explaining to you why you would declare constants inside compound types like records or classes.

    ReplyDelete
  27. Lars Fosdal While technically possible, this is not a primary concern in Delphi. The unit is a namespace. If you need two different resource strings with the same name, you may need to split your unit into two ones.

    ReplyDelete
  28. T n T - If you split it into two units that means you introduce a unit sequence dependency since the last unit in scope is the one providing the value you refer to, and you don't get any hint or warning informing you that there is a namespace clash.

    ReplyDelete
  29. Lars Fosdal you can prefix the name with the unit name to ensure that there's no collision.

    my first impression with class method or class const and type was that it is not necessary because namespace are handled by units.

    now I use them sometime to avoid splitting my code into several units :)

    ReplyDelete
  30. Paul TOTH I use class internal types and constants all the time.

    Not only does it make scoping crystal clear - it also prevents OOP inheritance abuse, since the internal classes can't readily be hijacked for something they wasn't intended for.

    I often do stuff like this

    TMyDBClass = class(TDBObject)
    type
    fn = record const
    view = 'v_MyDBTableView';
    field1= 'field1';
    field2 = 'field2';
    end;
    private
    FField1: string;
    FField2: string;
    public
    property Field1 read FField1 write FField1;
    property Field2 read FField2 write FField2;
    end;

    so that I can stuff like

    sql = QBuilder.Select([fn.field1, fn.Field2]).From(fn.view);

    and do

    Field1 := recset.FieldByName[fn.field1].AsString;

    to make sure that all my field references are not simply multiple string constants, but one single constant. Makes it trivial to refactor field names and to avoid the accidentally misspelled field name in FieldByName['filed1'].

    ReplyDelete
  31. Lars Fosdal I do the same

    TCustomer = record
    CONST
    TABLE_NAME = 'Customers';
    KEY_FIELD = 'Id';
    public
    Name: string; // I miss the [size] suffix for Unicode string
    !
    Birth: TDateTime;

    ReplyDelete

Post a Comment