Size: a a a

2020 March 12

N

Nik in Delphi & Lazarus
Короче, слив по полной
источник

VA

Viktor Akselrod in Delphi & Lazarus
я почитал комментарии и таки надо признать, что я ошибался.
Стефан прав и код работает именно так, как должен.

ограничивая параметр классом TTest1 мы говорим о том, что параметры будут являться наследниками TTest1 и соо-но в коде можем использовать только методы и свойства TTest1. ожидать, что внутри обобщённого класса можно будет использовать другие методы из классов наследников абсолютно неправильно (а ведь по факту TTest2.Test - это абсолютно другой метод и не имеет ничего общего с одноименным методом из TTest1).

Простой пример: если мы добавим метод TTest2.OtherTest мы же не сможем его вызывать из обобщённого кода, тк такой метод отсутствует в базовом классе.
источник

GB

George Bakhtadze in Delphi & Lazarus
Viktor Akselrod
я почитал комментарии и таки надо признать, что я ошибался.
Стефан прав и код работает именно так, как должен.

ограничивая параметр классом TTest1 мы говорим о том, что параметры будут являться наследниками TTest1 и соо-но в коде можем использовать только методы и свойства TTest1. ожидать, что внутри обобщённого класса можно будет использовать другие методы из классов наследников абсолютно неправильно (а ведь по факту TTest2.Test - это абсолютно другой метод и не имеет ничего общего с одноименным методом из TTest1).

Простой пример: если мы добавим метод TTest2.OtherTest мы же не сможем его вызывать из обобщённого кода, тк такой метод отсутствует в базовом классе.
ты ошибался, я ошибался. :) а почему? потому что работает не очевидно. очевидно, что статический тип при специализации заменяется на аргумент. и он заменяется, но не совсем.
а правильно это считается потому что так работает в C#. эталон у них такой
источник

AS

Alexey Shumkin in Delphi & Lazarus
Nik
Давайте его к пэхапистам отправим? 😏
Ник, не бузи ))
источник

N

Nik in Delphi & Lazarus
Alexey Shumkin
Ник, не бузи ))
😝
источник

VA

Viktor Akselrod in Delphi & Lazarus
George Bakhtadze
ты ошибался, я ошибался. :) а почему? потому что работает не очевидно. очевидно, что статический тип при специализации заменяется на аргумент. и он заменяется, но не совсем.
а правильно это считается потому что так работает в C#. эталон у них такой
по мне дак все встало на свои места.
как бы ты поступил в таком случае на месте компилятора?

type
 TTest1 = class
   procedure Test();
 end;

 TTest2 = class(TTest1)
   procedure OtherTest();
 end;

 TTest<T: TTest1, constructor> = class(TObject)
   FTest: T;
   procedure TestIt();
 end;

procedure TTest1.Test();
begin
 WriteLn('1');
end;

procedure TTest2.OtherTest();
begin
 WriteLn('2');
end;

procedure TTest<T>.TestIt();
begin
 FTest := T.Create();
 FTest.OtherTest();
 readln;
end;

begin
 with TTest<TTest2>.Create do
   TestIt();
end.
источник

GB

George Bakhtadze in Delphi & Lazarus
Viktor Akselrod
я почитал комментарии и таки надо признать, что я ошибался.
Стефан прав и код работает именно так, как должен.

ограничивая параметр классом TTest1 мы говорим о том, что параметры будут являться наследниками TTest1 и соо-но в коде можем использовать только методы и свойства TTest1. ожидать, что внутри обобщённого класса можно будет использовать другие методы из классов наследников абсолютно неправильно (а ведь по факту TTest2.Test - это абсолютно другой метод и не имеет ничего общего с одноименным методом из TTest1).

Простой пример: если мы добавим метод TTest2.OtherTest мы же не сможем его вызывать из обобщённого кода, тк такой метод отсутствует в базовом классе.
я кстати подзабыл, что методы, реализующие интерфейс не обязаны буть виртуальными. а невиртуальный вызов меня устроит. но пока я вижу таки виртуальный :(
источник

GB

George Bakhtadze in Delphi & Lazarus
Viktor Akselrod
по мне дак все встало на свои места.
как бы ты поступил в таком случае на месте компилятора?

type
 TTest1 = class
   procedure Test();
 end;

 TTest2 = class(TTest1)
   procedure OtherTest();
 end;

 TTest<T: TTest1, constructor> = class(TObject)
   FTest: T;
   procedure TestIt();
 end;

procedure TTest1.Test();
begin
 WriteLn('1');
end;

procedure TTest2.OtherTest();
begin
 WriteLn('2');
end;

procedure TTest<T>.TestIt();
begin
 FTest := T.Create();
 FTest.OtherTest();
 readln;
end;

begin
 with TTest<TTest2>.Create do
   TestIt();
end.
тут очевидно не скомпилируется, за неимением метода
источник

VA

Viktor Akselrod in Delphi & Lazarus
George Bakhtadze
тут очевидно не скомпилируется, за неимением метода
твой случай - это тоже самое, за исключением совпадения имен методов.
так что всё честно, как ни крути.
ну и хорошая новость - в женериках под делфи снова нет багов 🙂
источник

GB

George Bakhtadze in Delphi & Lazarus
Viktor Akselrod
твой случай - это тоже самое, за исключением совпадения имен методов.
так что всё честно, как ни крути.
ну и хорошая новость - в женериках под делфи снова нет багов 🙂
нет, не тоже самое. тут как и с операторами <>. женерики - инструмент времени компиляции, поэтому во время компиляции все можно подставить и убедиться, что такой метод есть и именно его и вызвать.
источник

GB

George Bakhtadze in Delphi & Lazarus
ну и не ругаться по поводу отсутствующих операторов, если код специализирован типом, у которого они есть. хотя тут чуть сложнее, т.к. дерево до специализации не построишь так просто
источник

VA

Viktor Akselrod in Delphi & Lazarus
George Bakhtadze
нет, не тоже самое. тут как и с операторами <>. женерики - инструмент времени компиляции, поэтому во время компиляции все можно подставить и убедиться, что такой метод есть и именно его и вызвать.
это как минимум создает неоднозначность.
2 класса, 2 одноименных метода.
источник

GB

George Bakhtadze in Delphi & Lazarus
Viktor Akselrod
это как минимум создает неоднозначность.
2 класса, 2 одноименных метода.
во-первых, неоднозначность она все равно на месте. во-вторых она есть в рантайме, а во время компиляции ее нет
источник

VA

Viktor Akselrod in Delphi & Lazarus
George Bakhtadze
во-первых, неоднозначность она все равно на месте. во-вторых она есть в рантайме, а во время компиляции ее нет
в общем, я таки считаю, что все честно  и менять ничего не надо, что собственно  и будет в итоге с вероятностью 99%.
но все равно было интересно 🙂
источник

GB

George Bakhtadze in Delphi & Lazarus
с такой же вероятностью ничего не поменяли бы даже если там прям баг был :)
источник

GB

George Bakhtadze in Delphi & Lazarus
а по поводу интерфейсов и невиртуальных вызовов у тебя работало?
источник

VA

Viktor Akselrod in Delphi & Lazarus
ну не, баги правят, особенно если на них обратить должное внимание и обосновать.
@ziv_2006 не даст соврать
источник

VA

Viktor Akselrod in Delphi & Lazarus
George Bakhtadze
а по поводу интерфейсов и невиртуальных вызовов у тебя работало?
а в чем суть, я видимо пропустил.
в идеале с примером
источник

GB

George Bakhtadze in Delphi & Lazarus
Viktor Akselrod
а в чем суть, я видимо пропустил.
в идеале с примером
суть в том, чтобы TTest1 сделать интерфейсом. тогда вызывается нужный метод. и как говорил ты, да и тот же Стефан должно вызываться как невиртуальный метод. но пока что я вижу нечто похожее на виртуальный вызов. хотя сам метод без virtual
источник

VA

Viktor Akselrod in Delphi & Lazarus
George Bakhtadze
суть в том, чтобы TTest1 сделать интерфейсом. тогда вызывается нужный метод. и как говорил ты, да и тот же Стефан должно вызываться как невиртуальный метод. но пока что я вижу нечто похожее на виртуальный вызов. хотя сам метод без virtual
встречный вопрос - а почему ты так стараешься избежать виртуального метода?
источник