В Pascal существует два типа объявлений типов:
- псевдонимы типов: type NewName = OldType
- type creation: type NewType = type OldType
Первый просто создает удобную стенографию, например typedef в C. Эти псевдонимы совместимы друг с другом и с их оригинальным типом. Созданные типы преднамеренно несовместимы и не могут быть смешаны без явного и небезопасного по определению типа.
var
nn: NewName; nt: NewType; ot: OldType;
...
nn := ot; // should work
nt := ot; // should break with type safety violation error.
nt := NewType(ot); // Disabling type safety. Should work even if
// it has no sense semantically and types really ARE incompatible.
Это основы Pascal, как я их понимаю.
Теперь рассмотрим один определенный тип и два его псевдонима:
- массив System.Types.TStringDynArray = строки;
- System.TArray < Т >= массив T;
- в частности, что означает TArray <string>= массив строки; по определению.
Теперь давайте возьмем функцию, возвращающую прежний псевдоним типа, и передаем его результат функции, ожидающей последнего:
uses Classes, IOUtils;
TStringList.Create.AddStrings(
TDirectory.GetFiles('c:\', '*.dll') );
TStringList.Create.AddStrings(
TArray<string>( // this is required by compiler - but why ???
TDirectory.GetFiles('c:\', '*.dll') ) );
1-й фрагмент не будет компилироваться из-за нарушения типов. Второй счастливо компилируется и работает, но хрупка в отношении будущих изменений типа и является избыточным.
QC сообщает, что компилятор прав, а дизайн RTL ошибочен. http://qc.embarcadero.com/wc/qcmain.aspx?d=106246
Почему компилятор здесь? Почему эти псевдонимы несовместимы? Даже сама разработка RTL предполагает, что они считаются совместимыми!
PS. Дэвид предложил еще более простой пример, не используя TArray <T>
type T1 = array of string; T2 = array of string;
procedure TForm1.FormCreate(Sender: TObject);
function Generator: T1;
begin Result := T1.Create('xxx', 'yyy', 'zzz'); end;
procedure Consumer (const data: T2);
begin
with TStringList.Create do
try
AddStrings(data);
Self.Caption := CommaText;
finally
Free;
end;
end;
begin
Consumer(Generator);
end;
То же самое получить без объяснения...
ПФС. Сейчас есть несколько документов. Я хочу подчеркнуть одно: хотя это ограничение может быть косвенно унаследовано из отчета Паскаля 1949 года, сегодня 2012 год, а Delphi очень сильно отличался от школьных лабораторий полвека назад. Я назвал несколько БАД эффектов сохранения этих ограничений и все же не видел ничего хорошего.
Ироническая вещь, что это ограничение может быть отменено без нарушения правил Паскаля: в Паскале нет такого нестрого зверя, как открытые массивы и динамические массивы. Поэтому пусть эти исходные фиксированные массивы будут ограничены по своему усмотрению, но открытые массивы и динамические массивы не являются гражданами Паскаля и не обязаны ограничиваться его кодовой книгой!
Пожалуйста, сообщите Эмбе в QC или, возможно, даже здесь, но если вы просто проходите мимо, не выражая свое мнение - ничего не изменится!