Здравствуйте, x-code, Вы писали:
XC>Не могу строго аргументировать, но кажется, что номинативная "привычнее", естественнее и проще в реализации, и в большинстве случаев ее достаточно.
Привычнее то что использовал. Ваш, КО.
А вот структурная система типов гибче. Нет многих проблем присущих номинативной системе.
В качестве примера могу привести дженерики дотнета и шаблоны С++. Первые имеют известную проблему. Ограничения для параметров типов в дженериках указываются в полном соответствии с канонами номинативной системы типов — через именованные интерфейсы. Реализация интерфейса должна быть явно описана при декларации типа. Таким образом, если кто-то наложил ограничения на параметр типа, то вместо него нельзя передать не реализующий интерфейс даже если этот тип полностью подходит по функциональности.
В структурной системе типов это не было бы проблемой.
VD>>Что же касается того как совмещать структурную и номинативную типизации, то тут есть только одно решение, на мой взгляд — разделить типы в языке на те что подчиняются структурной типизации и остальные. Но тут есть нюансы: VD>>1. Ограничить структурную типизацию только этими типами. Так сделано, например, с записями в F#. VD>>2. Дать возможность любой тип приводить к структурному.
XC>Да, похоже что так можно, хотя сразу понятно что там огромное количество неочевидных нюансов
Например?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, x-code, Вы писали:
VD>>1. Зачем нужна номинативная типизация в языке где качественно поддерживается структурная? XC>Не могу строго аргументировать, но кажется, что номинативная "привычнее", естественнее и проще в реализации, и в большинстве случаев ее достаточно.
Структурная для понимания как раз проще, да и для языков с выводом типов естественнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, x-code, Вы писали:
XC>>Не могу строго аргументировать, но кажется, что номинативная "привычнее", естественнее и проще в реализации, и в большинстве случаев ее достаточно.
VD>Привычнее то что использовал. Ваш, КО.
VD>А вот структурная система типов гибче. Нет многих проблем присущих номинативной системе.
VD>В качестве примера могу привести дженерики дотнета и шаблоны С++. Первые имеют известную проблему. Ограничения для параметров типов в дженериках указываются в полном соответствии с канонами номинативной системы типов — через именованные интерфейсы. Реализация интерфейса должна быть явно описана при декларации типа. Таким образом, если кто-то наложил ограничения на параметр типа, то вместо него нельзя передать не реализующий интерфейс даже если этот тип полностью подходит по функциональности.
VD>В структурной системе типов это не было бы проблемой.
Было бы. У функций в интерфейсе тоже есть имена. Как предлагается проверять структурное соответствие для них?
interface IShow
{
string toString();
}
и
class Some
{
string fileName() { return"1.txt"; }
}
Проблема тут не в имени, а в невозможности по месту "отнаследовать".
Здравствуйте, VoidEx, Вы писали:
VE>Было бы. У функций в интерфейсе тоже есть имена. Как предлагается проверять структурное соответствие для них?
В структурных системах типов обычно и производится проверка по именам членов.
VE>Проблема тут не в имени, а в невозможности по месту "отнаследовать".
В структурных системах типов наследование не обязательно. Там достаточно понятия подтипа. А наследование если и есть, то является средством повторного использования кода, а не средством полиморфизма.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, VoidEx, Вы писали:
VE>>Было бы. У функций в интерфейсе тоже есть имена. Как предлагается проверять структурное соответствие для них?
VD>В структурных системах типов обычно и производится проверка по именам членов.
Вот именно.
interface IToString { string toString(); }
class MyData { string asString(); }
class MyData2 { list<char> toString(); }
В OCaml сопоставление происходит по сигнатуре функции то есть по кортежу (<возвращаемое значение>, <имя функции>, <параметры>)
при этом возвращаемое значение и параметры максимально возможно обобщаются и условно для функции
int CountChars(o)
{
return fold(enum(o.toString()), (sum, c) => sum + 1)
}
Здравствуйте, FR, Вы писали:
FR>В OCaml сопоставление происходит по сигнатуре функции то есть по кортежу (<возвращаемое значение>, <имя функции>, <параметры>) FR>при этом возвращаемое значение и параметры максимально возможно обобщаются и условно для функции
FR>
FR>int CountChars(o)
FR>{
FR>return fold(enum(o.toString()), (sum, c) => sum + 1)
FR>}
FR>
FR>подойдут и IToString и MyData2
Можно ли вызвать так, чтобы MyData тоже подошло? Какой нужен дополнительный код?
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, VoidEx, Вы писали:
FR>>>подойдут и IToString и MyData2
VE>>Можно ли вызвать так, чтобы MyData тоже подошло? Какой нужен дополнительный код?
FR>Нет, совпадение имени необходимо.
Именно об этом я и говорил, что из-за завязки на имя в этом решении тоже придётся городить обходные пути.
Было бы куда лучше, например, так:
foo(myData { toString = asString })
Или вообще уровня scope:
let instance IsString MyData where
toString = asString
in
...
Здравствуйте, VoidEx, Вы писали:
FR>>Нет, совпадение имени необходимо.
VE>Именно об этом я и говорил, что из-за завязки на имя в этом решении тоже придётся городить обходные пути.
Здравствуйте, VladD2, Вы писали:
VD>Вообще, структурная типизация подразумевает, что имя метода члена в совокупности с его сигнатурой определяет его предназначение. И обычно так и есть.
сразу в голову приходят length/size/count, а в некоторых контекстах на их место может претендовать и vertices/numPoints/etc.
Неплохо было бы (очень неплохо) уметь указывать по месту, мол в данном случае за length можно считать vertices.
VD>>Вообще, структурная типизация подразумевает, что имя метода члена в совокупности с его сигнатурой определяет его предназначение. И обычно так и есть.
VE>сразу в голову приходят length/size/count, а в некоторых контекстах на их место может претендовать и vertices/numPoints/etc. VE>Неплохо было бы (очень неплохо) уметь указывать по месту, мол в данном случае за length можно считать vertices.
Для совместимости волей неволей большинство разработчиков придут к единому соглашению.
Здравствуйте, VladD2, Вы писали:
VD>Возможно. Например, в F# записи подчиняются законам структурной типизации принятой в ML, а все остальные типы подчиняются правилам номинативной системы типов.
Да ладно тебе. Покажи-ка пример структурной типизации для записей.
Здравствуйте, VladD2, Вы писали:
VD>В качестве примера могу привести дженерики дотнета и шаблоны С++. Первые имеют известную проблему. Ограничения для параметров типов в дженериках указываются в полном соответствии с канонами номинативной системы типов — через именованные интерфейсы. Реализация интерфейса должна быть явно описана при декларации типа. Таким образом, если кто-то наложил ограничения на параметр типа, то вместо него нельзя передать не реализующий интерфейс даже если этот тип полностью подходит по функциональности.
VD>В структурной системе типов это не было бы проблемой.
А как же бинарный контракт? Либо весь исходник с собой таскать надо, для целей кодогенерации под конкретный "клиентский" тип, либо разделить объявление типов и их реализацию, но зафиксировать в каком-либо виде бинарный контракт м/у объявлением и реализацией.
Здравствуйте, FR, Вы писали:
FR>Не полноценного а привычного.
Пока что считается, что в этом и состоит сильная статическая типизация, чтобы компилятор помогал ловить ошибки семантики, коль мы наделяем A и B разной семантикой. ИМХО, в С++ очень удачное название название у шаблонов, намекающее на то, что это не сам код. Т.е. мы вроде как не статическую типизацию в теле шаблона нарушаем, а скромно генерим другой код по образцу и подобию.
Здравствуйте, vdimas, Вы писали:
FR>>Не полноценного а привычного.
V>Пока что считается, что в этом и состоит сильная статическая типизация, чтобы компилятор помогал ловить ошибки семантики, коль мы наделяем A и B разной семантикой.
Это в тебе голос привычного ОО говорит, при структурной типизации никаких классов по сути нет, есть объекты и есть методы объектов и семантика должна быть завязана именно на это, а не на мифические классы
V>ИМХО, в С++ очень удачное название название у шаблонов, намекающее на то, что это не сам код. Т.е. мы вроде как не статическую типизацию в теле шаблона нарушаем, а скромно генерим другой код по образцу и подобию.
Шаблоны C++ (да и D) это все-таки не совсем структурная типизация, а нечто на нее очень похожее. В том же OCaml статическая типизация нигде ни нарушается, и структурно типизированные функции шаблонами не являются.
Здравствуйте, FR, Вы писали:
FR>>>Не полноценного а привычного.
V>>Пока что считается, что в этом и состоит сильная статическая типизация, чтобы компилятор помогал ловить ошибки семантики, коль мы наделяем A и B разной семантикой.
FR>Это в тебе голос привычного ОО говорит, при структурной типизации никаких классов по сути нет, есть объекты и есть методы объектов и семантика должна быть завязана именно на это, а не на мифические классы
И как структурная типизация позволит защититься от сравнения яблок с апельсинами?
Все хорошо к месту, и структурная типизация не отменяет номинативной, это ортогональные измерения, и они отлично вместе сосуществуют, не отменяя друг друга.
(Хотя в С++, в котором можно в "структурную" типизцию на шаблонах впихнуть типы и вообще все, что угодно (traits, например), можно эмулировать и нормальную типизацию через те же traits. Но в С++ шаблоны намного мощнее простой стуктурной типизации. Структурная типизация — это просто кастрированная версия предикатной типизации (когда можно задать любой вопрос относительно типа), в которой предикаты ограничены примитивными "есть член с таким именем и сигнатурой")
V>>ИМХО, в С++ очень удачное название название у шаблонов, намекающее на то, что это не сам код. Т.е. мы вроде как не статическую типизацию в теле шаблона нарушаем, а скромно генерим другой код по образцу и подобию.
FR>Шаблоны C++ (да и D) это все-таки не совсем структурная типизация, а нечто на нее очень похожее.
"нечто на нее очень похожее" — в терминах duck typing это высказывание эквивалентно "это оно и есть"
Если спор не чисто терминологический, конечно.
FR>В том же OCaml статическая типизация нигде ни нарушается, и структурно типизированные функции шаблонами не являются.
И как они работают на бинарном уровне тогда? Вот у тебя есть функция, и ты ее зовешь с тремя абсолютно по-разному устроенными, но структурно-совместимыми объектами. В С++ для каждого вызова сгенерится код, наиболее подходящий для каждого типа (т.е. если искомая функция в одном объекте виртуальная, а в другом — нет, то будут сгенерены виртуальный и невиртуальный вызовы соответственно). Что генерит компилятор окамла?