, но меня интересует нечто другое.
Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?
Для примера — вариант в Scala:
В Go вроде бы тоже есть нечто подобное, но не нашел примера
А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?
, но меня интересует нечто другое. XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно? XC>Для примера — вариант в Scala: XC>
, но меня интересует нечто другое. XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно? XC>Для примера — вариант в Scala: XC>
XC>В Go вроде бы тоже есть нечто подобное, но не нашел примера XC>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?
Здравствуйте, x-code, Вы писали:
XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно? XC>
J>это если нужно просто отвалиться по assert в случае неправильного типа.
J>Если же хочется перегрузки по наличию/отсутствию функции, то нужно будет эту проверку упаковать в enable_if: J>
Кстати, интерсный пример для иллюстрации цели этой темы. Я программист С++, почти ничего не понял в этом коде при этом на Скале не писал ни строчки кода вообще, а пример вполне понятен.
, но меня интересует нечто другое. XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно? XC>Для примера — вариант в Scala: XC>
Здравствуйте, x-code, Вы писали:
XC>Кстати, интерсный пример для иллюстрации цели этой темы. Я программист С++, почти ничего не понял в этом коде
В "этом коде" — это во втором? Ну так для этого надо быть в теме enable_if (http://www.boost.org/libs/utility/enable_if.html), это да, тут ничего не поделаешь. Но это нужно только если нужна перегрузка — не самый частый случай, обычно просто сообщения об ошибке достаточно, и об этом первый пример.
Надеюсь, в первом-то примере всё понятно, или тоже нет?
XC>при этом на Скале не писал ни строчки кода вообще, а пример вполне понятен.
Ну извини, Скала — только-только появившийся язык (2004 год). Нафиг бы он был нужен, если б не умел что-то делать лучше, чем существующие языки
Здравствуйте, Temoto, Вы писали:
XC>>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?
T>def test(f: auto) { println(f.getName) }
Т.е. просто положиться на вывод типов?
И кстати, еще интересный вопрос: какой тип должен использоваться реально для структурной типизации? Специальный "структурный" интерфейс? Как он должен быть устроен на низком уровне?
И как сделать, чтобы в программе отличались "структурные" интерфейсы от "номинативных" (при условии, что в некоторых случаях "номинативные" тоже нужны)?
XC>>>А можно сделать еще лучше? При этом (важно!) не ломая классического синтаксиса обычной номинативной типизации ?
T>>def test(f: auto) { println(f.getName) } XC>Т.е. просто положиться на вывод типов?
Да. Строго говоря, это скорее будет вывод интерфейса.
XC>И кстати, еще интересный вопрос: какой тип должен использоваться реально для структурной типизации? Специальный "структурный" интерфейс? Как он должен быть устроен на низком уровне?
Да. Специальный анонимный интерфейс для каждого использования объекта.
Не вижу никаких причин, чтобы этот интерфейс был на низком уровне устроен иначе, чем другие интерфейсы. Фактически, код выше можно переписать на этапе проверки типов в
XC>И как сделать, чтобы в программе отличались "структурные" интерфейсы от "номинативных" (при условии, что в некоторых случаях "номинативные" тоже нужны)?
Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия?
Здравствуйте, Temoto, Вы писали:
T>Не вижу никаких причин, чтобы этот интерфейс был на низком уровне устроен иначе, чем другие интерфейсы. Фактически, код выше можно переписать на этапе проверки типов в
T>
И как заставить все используемые там классы наследоваться от этого интерфейса (на низком уровне)? Особенно если многие классы уже в библиотеках в каком-то двоичном виде?
T>Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия?
Если я например имею именованный интерфейс, но хочу чтобы он был структурным.
T>>Не вижу никаких причин, чтобы этот интерфейс был на низком уровне устроен иначе, чем другие интерфейсы. Фактически, код выше можно переписать на этапе проверки типов в
T>>
XC>И как заставить все используемые там классы наследоваться от этого интерфейса (на низком уровне)? Особенно если многие классы уже в библиотеках в каком-то двоичном виде?
Ну если для корректной работы нужно отнаследовать классы, тогда у нас не структурная типизация.
Наверное, сразу стоило сказать вслух. Я неявно подразумеваю вот что: номинативная типизация это структурная с дополнительными ограничениями (явное указание конкретного интерфейса). Логическим следствием было бы реализовывать в компиляторе только структурную типизацию. И сверху сахаром [никому не нужную] номинативную, которая только вводит дополнительное ограничение к тому что работает.
Вот пример как именно можно выразить номинативный интерфейс:
То есть у интерфейса появляется неизменяемое поле с его именем, которое для проверки типов должно совпадать при каждом использовании. Поскольку поле неизменяемое, эту проверку можно сделать на этапе компиляции.
T>>Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия? XC>Если я например имею именованный интерфейс, но хочу чтобы он был структурным.
Сделано. Любой именованый интерфейс является структурным. Аналогия: любая именованая функция является функцией (лямбдой).
Здравствуйте, x-code, Вы писали:
XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования? Как можно оформить это синтаксически — чтобы было красиво и понятно?
Здравствуйте, x-code, Вы писали:
XC>Возможно одновременное существование структурной и номинативной типизации в обычном си-подобном языке программирования?
Возможно. Например, в F# записи подчиняются законам структурной типизации принятой в ML, а все остальные типы подчиняются правилам номинативной системы типов.
У меня лично возникают два вопроса по этому поводу:
1. Зачем нужна номинативная типизация в языке где качественно поддерживается структурная?
2. Как эффективно реализовать структурную типизацию в рантаймах на это не рассчитанных (.Net/Mono/Java)? Дело в том, что в этих рантаймах нет нужных средств и в лучшем случае получится эмуляция. А это повлечет или сильные ограничения, или потерю производительности.
Что же касается того как совмещать структурную и номинативную типизации, то тут есть только одно решение, на мой взгляд — разделить типы в языке на те что подчиняются структурной типизации и остальные. Но тут есть нюансы:
1. Ограничить структурную типизацию только этими типами. Так сделано, например, с записями в F#.
2. Дать возможность любой тип приводить к структурному.
Для второго случая я бы ввел некий модификатор для интерфейсов (если оные есть в языке). Например:
structural interface ITest
{
...
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, x-code, Вы писали:
XC>И как заставить все используемые там классы наследоваться от этого интерфейса (на низком уровне)? Особенно если многие классы уже в библиотеках в каком-то двоичном виде?
Если язык поддерживает КОП (компонентно-ориентированное программирование), то никак или с серьезным рантайм-верехэдом.
Например, в языке где поддерживаются ссылки на методы объектов можно превратить такой интерфейс с структуру содержащую ссылки на методы. Таким образом код вида (базовый языком взят C#):
interface ITest
{
int Method1(string s);
string Prop1 { get; }
}
class A
{
public Test(structural ITest test)
{
var x = test.Method1(test.Prop1);
...
}
}
...
new A().Test(new B());
можно переписать в:
class ITest_Proxy
{
public Func<string, int> Method1;
public Func<string> Prop1;
}
class A
{
public Test(ITest test)
{
var x = test.Method1(test.Prop1);
...
}
}
...
var tempB = new B();
var proxy = new ITest_Proxy() { tempB.Method1; tempB.Prop1; `}
new A().Test(proxy);
Единственная проблема будет в том, что test нельзя будет динамически привести к другому типу, так как работа будет вестись не с родным объектом, а с прокси.
T>>Не вижу никаких причин, хотеть чтобы структурные интерфейсы отличались от номинативных. У них всё равно будут отличия: 1) номинативные интерфейсы нужно сначала объявить, 2) следовательно у них есть имя. Но зачем делать ещё какие-то отличия? XC>Если я например имею именованный интерфейс, но хочу чтобы он был структурным.
Это не проблема. Как в примере выше можно указывать требование структурной совместимости в параметре или переменной/поле. Ну, а для функций принимающих структурные интерфейсы можно можно просто генерировать два тела. Одно для структурного прокси, а другое для обычной реализации. Правда если таких параметров много, то может начаться комбинаторный взрыв и придется генерировать не столько тел, сколько имеется пересечений структурных интерфейсов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, x-code, Вы писали:
XC>Если я например имею именованный интерфейс, но хочу чтобы он был структурным.
Ну в моем примере на С++ это будет просто набор условий типа того, что уже там есть, объединенный в именованную структуру, которая будет использоваться в коде вместо is_same.
Т.е. будет нечто вроде:
template<class T>
auto MyInterface(T f)
-> and_<
is_same< decltype(f.getName()), string >,
is_same< decltype(f.setName(string)), void >,
// и т.д., остальные условия
>::type;
and_<...>::type вернет либо true_, либо false_ (это типы).
Теперь у тебя есть структурный интерфейс с именем MyInterface.
Дальше в пользовательском коде:
Здравствуйте, jazzer, Вы писали:
J>Надеюсь, с макросами тебя это уже не пугает?
Пугает то, то что С++ — прямой наследник Си — уходит все дальше и дальше в какие-то дебри, а языки для всяких безопасных тормозных фреймворков становятся все лучше и лучше И где в мире справедливость?
Хотя, надо признать, реализация структурной типизации на шаблонах самая быстрая их всех возможных — для каждого варианта использования будет сгенерирована своя версия функции.
Здравствуйте, VladD2, Вы писали:
VD>У меня лично возникают два вопроса по этому поводу: VD>1. Зачем нужна номинативная типизация в языке где качественно поддерживается структурная?
Не могу строго аргументировать, но кажется, что номинативная "привычнее", естественнее и проще в реализации, и в большинстве случаев ее достаточно.
VD>Что же касается того как совмещать структурную и номинативную типизации, то тут есть только одно решение, на мой взгляд — разделить типы в языке на те что подчиняются структурной типизации и остальные. Но тут есть нюансы: VD>1. Ограничить структурную типизацию только этими типами. Так сделано, например, с записями в F#. VD>2. Дать возможность любой тип приводить к структурному.
Да, похоже что так можно, хотя сразу понятно что там огромное количество неочевидных нюансов
Здравствуйте, x-code, Вы писали:
XC>Здравствуйте, jazzer, Вы писали:
J>>Надеюсь, с макросами тебя это уже не пугает? XC>Пугает то, то что С++ — прямой наследник Си — уходит все дальше и дальше в какие-то дебри, а языки для всяких безопасных тормозных фреймворков становятся все лучше и лучше И где в мире справедливость?
Да ладно тебе, какие же это дебри — автоматический вывод типов, переменное число аргументов у макросов и шаблонов, универсальная инициализация и прочие вкусности? Это все, имхо, делает язык лучше. Т.е. С++0х, имхо, однозначно лучше С++98.
А если не рассматривать С++0х, то в дебри уходят программисты, а не язык Буст, Александреску, шаблонное и препроцессорное метарограммирование — это все реализовано на базе старого доброго С++98
XC>Хотя, надо признать, реализация структурной типизации на шаблонах самая быстрая их всех возможных — для каждого варианта использования будет сгенерирована своя версия функции.
Да, все эти игры с типизацией в С++ остаются на стадии компиляции, а после того, как сгенерены и проверены все типы, идет обычная кодогенерация сишного уровня, со всеми подобающими оптимизациями, специфическими для результирующего типа. Т.е. сколько бы я проверок не навернул во время компиляции, если компилятор не кривой, они никакого влияния на скорость исполнения скомпилированного кода не окажут.