can I be sure the FName of the record is an empty string?
Yes. After
Self := Default(TRec);
the record will consist of only zero bytes, that is, FNr = 0 and FName = ''.
(If Self.FName had somehow pointed to a string heap object before this line, the compiler and RTL would have dealt with that. So this assignment is much smarter than a FillChar(Self, SizeOf(Self), 0). You could also achieve the same effect with a Self := MyDefRec where MyDefRec is any TRec value that you have defined yourself and use as a default value.)
But of course this analysis only applies to situations where you actually do use this constructor you have written.
So if you do
var LRec := TRec.Create(394);
then you are guaranteed that LRec.FName is empty and that LRec.FNr = 394.
If you'd done
var LRec := Default(TRec);
you'd ended up with LRec.FName = '' and LRec.FNr = 0, since the "default" integer value is zero. In this case, your constructor is not used; instead, you simply assign the "default" ("zeroed out") TRec to LRec (which is exactly what the first line of your constructor also does).
But if you do
procedure Test;
var
LRec: TRec;
begin
ShowMessage(LRec.FNr.ToString);
ShowMessage(LRec.FName);
end;
the TRec.Create constructor has never run, nor have you assigned anything to LRec initially.
Now, recall that local variables of non-managed types are not initialised. For instance, a local integer variable will initially have the value that happens to be at that address in memory; it's effectively "random". But local variables of managed types, like strings and dynamic arrays, are of course initialised to nil (empty string or empty array). (So they do not point to any string or dynamic array heap object. Recall that string and dynamic array variables are simply pointers.)
Records are not managed, but can contain managed fields.
So in our example above, the first message box can display any "random" integer (but 0 is quite likely, since your RAM has a lot of zero bytes most of the time).
But the second message will always display an empty string, even though your own constructor has never executed. Again, this is because the string is a managed type and so is initialised to '' (=nil pointer, zero bytes).
If you have a class, like
type
TMyClass = class
FRec: TRec;
end;
and create an instance of that class,
procedure Test2;
begin
var LMyClass := TMyClass.Create;
try
// use LMyClass.FRec
finally
LMyClass.Free;
end;
end;
then FRec will also contain the number 0 and the empty string. This is because fields of classes are always initialized to zero (nil).
Self := Default(TRec)is that it will also initialize any fields you add later on to the record type. If you doFName := ''; ...etc. in the constructor, it's easy to forget to initialize any newly added members of the record type.