Знакомлюсь сейчас с "потенциальными убийцами С++", в частности с Rust и Go. С удивлением обнаружил, что и там и там поддерживается структурная типизация, то есть (псевдокод):
type liters { value : float };
type meters { value : float };
С точки зрения компилятора одно и то же и ничто не мешает нам вместо литров присвоить метры. Допускаю, что я что-то не понимаю, поэтому буду признателен за объяснения плюсов структрурной типизации перед номинативной.
Здравствуйте, MTD, Вы писали:
MTD>С точки зрения компилятора одно и то же и ничто не мешает нам вместо литров присвоить метры. Допускаю, что я что-то не понимаю, поэтому буду признателен за объяснения плюсов структрурной типизации перед номинативной.
Мне понравилась передача интерфейсов в функции. При структурной типизации не требуется наследование классов от интерфейсов. То есть если методы с конкретными сигнатурами реализованы в каком-то классе, то объект этого класса можно передавать туда, где требуется интерфейс с этими методами.
P.S. Читая книжку "The Way to Go", пришло в голову что номинативная типизация не противоречит структурной, они могут быть реализованы в одном языке программирования одновременно, надо только ключевое слово придумать для обозначения "структурно-типизированных структур".
Для комфортных экспериментов надо будет разобраться с IDE для Go, и Идой посмотреть какой код там генерируется для структурных интерфейсов, хотя я вроде и так догадываюсь.
Здравствуйте, include2h, Вы писали:
I>Мне понравилась передача интерфейсов в функции. При структурной типизации не требуется наследование классов от интерфейсов. То есть если методы с конкретными сигнатурами реализованы в каком-то классе, то объект этого класса можно передавать туда, где требуется интерфейс с этими методами.
В С++ это достигается через шаблоны, на мой взгляд этого достаточно.
Здравствуйте, MTD, Вы писали:
MTD>Знакомлюсь сейчас с "потенциальными убийцами С++", в частности с Rust и Go. С удивлением обнаружил, что и там и там поддерживается структурная типизация, то есть (псевдокод): MTD>type liters { value : float }; MTD>type meters { value : float }; MTD>С точки зрения компилятора одно и то же и ничто не мешает нам вместо литров присвоить метры. Допускаю, что я что-то не понимаю, поэтому буду признателен за объяснения плюсов структрурной типизации перед номинативной.
В C++ такая же фигня:
typedef float liters_t;
typedef float meters_t;
Логично распространить этот подход и на структуры, вообще говоря.
Здравствуйте, MTD, Вы писали:
MTD>Знакомлюсь сейчас с "потенциальными убийцами С++", в частности с Rust и Go. С удивлением обнаружил, что и там и там поддерживается структурная типизация, то есть (псевдокод):
Go не убийца C++ — скорее замена для Явы в случаях, когда хочется слезть с C++. Если б GC-язык мог убить C++, Ява с дотнетом давно бы уже убили.
Вот у Rust наибольший потенциал: запрет неявных копий, арены — поддержка аллокации не дефолтным аллокатором, memory safety с указателями но без глобального GC.
MTD>С точки зрения компилятора одно и то же и ничто не мешает нам вместо литров присвоить метры. Допускаю, что я что-то не понимаю, поэтому буду признателен за объяснения плюсов структрурной типизации перед номинативной.
Не скажу за Go, но я из переписок разработчиков Rust понял что там исключительно компиляторо-строительные мотивы
— структурные типы облегчают сериализацию и ABI. Не надо сохранять никакие UUID-ы типов и версию бинарника который его записал; есть строго фиксированный нерасширяемый базовый набор типов, которые всяко-разно комбинируются.
— можно выдать из функции наружу любой локальный тип, не заботясь о его видимости
— что-то облегчают для компилятора
В Rust комбинация номинальных (интерфейсы, enum-ы) и структурных типов. Причем структурные не такие, когда любой тип с атрибутом value подходит, а более строгие (все имена, мутабельность и типы должны совпасть). Если имя поля не несет смысла, то можно оформить single-variant enum:
Да и вообще, страх того, что нечаянно не то присвоишь, это фигня. На динамических языках же пишут. В С++ шаблонный аргумент тоже может нечаянно не тот тип мимо проверки провести.
+1, структурная типизация, а так же вывод типов, могут быть опасны с точки зрения безопасности типов.
выше приводили пример, что типа в С++ тожесамое —
`typedef float meters;` и `typedef float liters;` тоже никак не различаются,
но именно по этому в С++ добавили пользовательские литералы, чтобы убрать эту проблему,
теперь можно спокойно использовать `struct meters { float value; };`,
и писать выражения типа `meters x = y + 1m;`, где литерал "1m" будут иметь тип `meters`.
(а также можно писать `meters_per_sec = 10m / 1sec;`, ибо перегрузка операторов и т.п.)